[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[vidalia-svn] r3768: Switch to fetching and parsing the more extensible key=val G (in vidalia/trunk/src/vidalia: . network)
Author: edmanm
Date: 2009-05-13 15:07:26 -0400 (Wed, 13 May 2009)
New Revision: 3768
Modified:
vidalia/trunk/src/vidalia/CMakeLists.txt
vidalia/trunk/src/vidalia/network/GeoIp.cpp
vidalia/trunk/src/vidalia/network/GeoIp.h
vidalia/trunk/src/vidalia/network/GeoIpCache.cpp
vidalia/trunk/src/vidalia/network/GeoIpCache.h
vidalia/trunk/src/vidalia/network/GeoIpCacheItem.cpp
vidalia/trunk/src/vidalia/network/GeoIpCacheItem.h
vidalia/trunk/src/vidalia/network/GeoIpRequest.cpp
vidalia/trunk/src/vidalia/network/GeoIpRequest.h
vidalia/trunk/src/vidalia/network/GeoIpResolver.cpp
vidalia/trunk/src/vidalia/network/GeoIpResolver.h
vidalia/trunk/src/vidalia/network/GeoIpResponse.cpp
vidalia/trunk/src/vidalia/network/GeoIpResponse.h
vidalia/trunk/src/vidalia/network/NetViewer.cpp
vidalia/trunk/src/vidalia/network/RouterListItem.cpp
Log:
Switch to fetching and parsing the more extensible key=val GeoIP response
format, add support for associating an geographic location with a block of
IP addresses rather than a single address, add support for long region and
country names rather than just two-letter codes, and const-ify some method
arguments.
Modified: vidalia/trunk/src/vidalia/CMakeLists.txt
===================================================================
--- vidalia/trunk/src/vidalia/CMakeLists.txt 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/CMakeLists.txt 2009-05-13 19:07:26 UTC (rev 3768)
@@ -183,6 +183,7 @@
)
qt4_wrap_cpp(vidalia_SRCS
network/CircuitListWidget.h
+ network/GeoIpCache.h
network/GeoIpResolver.h
network/NetViewer.h
network/RouterDescriptorView.h
Modified: vidalia/trunk/src/vidalia/network/GeoIp.cpp
===================================================================
--- vidalia/trunk/src/vidalia/network/GeoIp.cpp 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/network/GeoIp.cpp 2009-05-13 19:07:26 UTC (rev 3768)
@@ -24,116 +24,52 @@
#define IS_VALID_LONGITUDE(x) (((x) >= -180.0) && ((x) <= 180.0))
-/** Constructor */
-GeoIp::GeoIp(QHostAddress ip)
+GeoIp::GeoIp()
{
- _ip = ip;
- _latitude = _longitude = 0xFFFF;
+ _latitude = 0.0;
+ _longitude = 0.0;
}
-/** Constructor. */
-GeoIp::GeoIp(QHostAddress ip, float latitude, float longitude,
- QString city, QString state, QString country)
+GeoIp::GeoIp(const QHostAddress &ip, float latitude, float longitude,
+ const QString &city, const QString ®ion,
+ const QString &country, const QString &countryCode)
{
- _ip = ip;
- _latitude = latitude;
+ _ip = ip;
+ _latitude = latitude;
_longitude = longitude;
- _city = city;
- _state = state;
- _country = country;
+ _city = city;
+ _region = region;
+ _country = country;
+ _countryCode = countryCode;
}
-/** Parses the GeoIp information from a comma-delimited string. The format of
- * the string is as in the following example:
- *
- * 128.213.48.13,Troy,NY,US,42.7495,-73.5951,1138402852
- */
-GeoIp
-GeoIp::fromString(QString geoip)
+bool
+GeoIp::isValid() const
{
- /* Split comma-delimited data fields */
- QStringList data = geoip.split(",");
-
- if (data.size() == 2 && data.at(1).toLower() == "unknown") {
- return GeoIp(QHostAddress(data.at(0)));
- } else if (data.size() < 6) {
- return GeoIp();
- }
-
- /* Parse the data from the string */
- QHostAddress ip(data.at(0));
- QString city = data.at(1);
- QString state = data.at(2);
- QString country = data.at(3);
- float latitude = data.at(4).toFloat();
- float longitude = data.at(5).toFloat();
-
- /* Create a new GeoIp object with the parsed data. */
- return GeoIp(ip, latitude, longitude, city, state, country);
+ return (! _ip.isNull()
+ && IS_VALID_LATITUDE(_latitude)
+ && IS_VALID_LONGITUDE(_longitude));
}
-/** Formats the GeoIp information as a comma-delimited string. */
QString
GeoIp::toString() const
{
- QString s;
- /* Assemble and comma-delimit the data fields */
- s.append(_ip.toString());
- s.append("," + _city);
- s.append("," + _state);
- s.append("," + _country);
- s.append("," + QString::number(_latitude, 'f', 4));
- s.append("," + QString::number(_longitude, 'f', 4));
- return s;
-}
-
-/** Returns true if the GeoIp object is invalid. */
-bool
-GeoIp::isEmpty() const
-{
- return (_ip.isNull() &&
- !IS_VALID_LATITUDE(_latitude) &&
- !IS_VALID_LONGITUDE(_longitude));
-}
-
-/** Returns true if the GeoIp object is valid, but no location information
- * is known for the associated IP address. */
-bool
-GeoIp::isUnknown() const
-{
- return (!_ip.isNull() &&
- !IS_VALID_LATITUDE(_latitude) &&
- !IS_VALID_LONGITUDE(_longitude));
-}
-
-/** Returns a human-readable string of GeoIp location information. */
-QString
-GeoIp::toLocation() const
-{
QStringList location;
-
+
/* Add the city name (if present) */
- if (!_city.isEmpty()) {
+ if (!_city.isEmpty())
location << _city;
- }
- /* Add the state or region name (if present) */
- if (!_state.isEmpty()) {
- /* Only display non-numeric region codes. */
- bool valid = true;
- for (int i = 0; i < _state.length(); i++) {
- if (_state[i].isDigit()) {
- valid = false;
- break;
- }
- }
- if (valid) {
- location << _state;
- }
- }
- /* Add the country code (if present) */
- if (!_country.isEmpty()) {
+
+ /* Add the full state or region name (if present) */
+ if (!_region.isEmpty() && _region != _city)
+ location << _region;
+
+ /* Add the country name or the country code (if present) */
+ if (!_country.isEmpty())
location << _country;
- }
+ else if (!_countryCode.isEmpty())
+ location << _countryCode;
+
return location.join(", ");
}
Modified: vidalia/trunk/src/vidalia/network/GeoIp.h
===================================================================
--- vidalia/trunk/src/vidalia/network/GeoIp.h 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/network/GeoIp.h 2009-05-13 19:07:26 UTC (rev 3768)
@@ -17,6 +17,7 @@
#ifndef _GEOIP_H
#define _GEOIP_H
+#include <QHash>
#include <QString>
#include <QHostAddress>
@@ -24,48 +25,71 @@
class GeoIp
{
public:
- /** Default constructor */
- GeoIp() : _latitude(0xFFFF), _longitude(0xFFFF) {}
- /** Constructor. */
- GeoIp(QHostAddress ip);
+ /** Default constructor. Creates an empty GeoIp object.
+ */
+ GeoIp();
- /** Constructor */
- GeoIp(QHostAddress ip, float latitude, float longitude,
- QString city, QString state, QString country);
-
- /** Creates a GeoIp object from a string. */
- static GeoIp fromString(QString geoip);
- /** Builds a comma-delimited string of GeoIp fields. */
- QString toString() const;
+ GeoIp(const QHostAddress &ip, float latitude, float longitude,
+ const QString &city = QString(),
+ const QString ®ion = QString(),
+ const QString &country = QString(),
+ const QString &countryCode = QString());
- /** Returns the IP address for this object. */
+ /** Returns the IP address associated with this GeoIP object.
+ */
QHostAddress ip() const { return _ip; }
- /** Returns the latitude coordinate for this IP. */
+
+ /** Returns the latitude portion of the geographic coordinates associated
+ * with this IP address or range of IP addresses.
+ */
float latitude() const { return _latitude; }
- /** Returns the longitude coordinate for this IP. */
+
+ /** Returns the longitude portion of the geographic coordinates associated
+ * with this IP address or range of IP addresses.
+ */
float longitude() const { return _longitude; }
- /** Returns the city in which this IP lives. */
+
+ /** Returns the name of the city associated with this IP address, if known.
+ * Otherwise, returns an empty QString.
+ */
QString city() const { return _city; }
- /** Returns the state or district in which this IP lives. */
- QString state() const { return _state; }
- /** Returns the country in which this IP lives. */
+
+ /** Returns the full region name (e.g., state) in which this IP address
+ * resides, if known. Otherwise, returns an empty QString.
+ */
+ QString region() const { return _region; }
+
+ /** Returns the full name of the country associated with this IP address
+ * or range of IP addresses, if known. Otherwise, returns an empty QString.
+ */
QString country() const { return _country; }
- /** Returns a human-readable string of city, region(state), and country. */
- QString toLocation() const;
- /** Returns true if the GeoIp object is invalid. */
- bool isEmpty() const;
- /** Returns true if the GeoIp object is valid, but no location information
- * is known for the associated IP address. */
- bool isUnknown() const;
+ /** Returns the ISO 3166-1 alpha-2 two-letter country code of the country
+ * associated with this IP address or range of IP addresses, if known.
+ * Otherwise, returns an empty QString.
+ */
+ QString countryCode() const { return _countryCode; }
+ /** Returns a human-readable string of city, region(state), and country.
+ * Some fields may be absent if they are not known. If no fields are known,
+ * this will return an empty QString.
+ */
+ QString toString() const;
+
+ /** Returns true if the GeoIp object is valid. A valid GeoIp object must
+ * have valid IP address, valid latitude and longitude coordinates and a
+ * two-letter country code.
+ */
+ bool isValid() const;
+
private:
QHostAddress _ip; /**< IP address for this location. */
float _latitude; /**< Latitudinal coordinate for this IP's location. */
float _longitude; /**< Longitudinal coordinate for this IP's location. */
QString _city; /**< City in which this IP lives. */
- QString _state; /**< State or district in which this IP lives. */
+ QString _region; /**< State or district in which this IP lives. */
QString _country; /**< Country in which this IP lives. */
+ QString _countryCode; /**< ISO-3166-1 alpha-2 country code. */
};
#endif
Modified: vidalia/trunk/src/vidalia/network/GeoIpCache.cpp
===================================================================
--- vidalia/trunk/src/vidalia/network/GeoIpCache.cpp 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/network/GeoIpCache.cpp 2009-05-13 19:07:26 UTC (rev 3768)
@@ -15,6 +15,8 @@
*/
#include "GeoIpCache.h"
+#include "GeoIpCacheItem.h"
+#include "GeoIp.h"
#include "Vidalia.h"
#include "file.h"
@@ -22,27 +24,24 @@
#include <QFile>
#include <QDir>
+#include <QString>
+#include <QDateTime>
#include <QTextStream>
+#include <QHostAddress>
-/* Location of Vidalia's geoip cache file. Qt docs claims that QFile will
- * translate the "/" correctly on Windows. Hopefully they didn't lie. */
-#define CACHE_FILENAME (Vidalia::dataDirectory() + "/geoip-cache")
-
-/** Constructor. */
-GeoIpCache::GeoIpCache()
+GeoIpCache::GeoIpCache(QObject *parent)
+ : QObject(parent)
{
loadFromDisk();
}
-/** Returns the location currently used for the cache file. */
QString
-GeoIpCache::cacheFilename()
+GeoIpCache::cacheFileName() const
{
- return CACHE_FILENAME;
+ return (Vidalia::dataDirectory() + "/geoip-cache");
}
-/** Writes the current cache to disk. */
bool
GeoIpCache::saveToDisk(QString *errmsg)
{
@@ -52,21 +51,21 @@
}
/* Try to open a temporary cache file for writing */
- QFile tmpCacheFile(CACHE_FILENAME + ".tmp");
+ QFile tmpCacheFile(cacheFileName() + ".tmp");
if (!tmpCacheFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
return err(errmsg, tmpCacheFile.errorString());
}
-
+
/* Write the cache entries to the file. */
QTextStream cache(&tmpCacheFile);
- foreach (GeoIpCacheItem cacheItem, _cache.values()) {
+ foreach (GeoIpCacheItem cacheItem, _cache) {
/* Save the cache item if it's not too old. */
if (!cacheItem.isExpired()) {
- cache << cacheItem.toString() << endl;
+ cache << cacheItem.toCacheString() << endl;
}
}
-
- QFile cacheFile(CACHE_FILENAME);
+
+ QFile cacheFile(cacheFileName());
/* Check if an previous cache file exists. */
if (cacheFile.exists()) {
/* A previous cache file exists, so try to remove it */
@@ -81,13 +80,11 @@
return true;
}
-/** Reads the cache contents in from disk. This function returns true if no
- * cache file exists, since it's possible nothing has been cached yet. */
bool
GeoIpCache::loadFromDisk(QString *errmsg)
{
- QFile cacheFile(CACHE_FILENAME);
-
+ QFile cacheFile(cacheFileName());
+
if (cacheFile.exists()) {
/* Try to open the cache file */
if (!cacheFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
@@ -97,49 +94,67 @@
/* Read the cached items from the cache file */
QTextStream cache(&cacheFile);
QString line = cache.readLine();
- while (!line.isNull()) {
+ while (! line.isNull()) {
/* Create a GeoIpCacheItem from the line and save it */
- GeoIpCacheItem item = GeoIpCacheItem::fromString(line);
- if (!item.isEmpty() && !item.isExpired()) {
- /* Only load non-stale cache items. */
- _cache.insert(item.ip().toIPv4Address(), item);
- }
+ GeoIpCacheItem item = GeoIpCacheItem::fromCacheString(line);
+ if (item.isValid() && ! item.isExpired())
+ addToCache(item);
+
line = cache.readLine();
}
+ vInfo("Parsed %1 GeoIP entries from '%2'").arg(_cache.size())
+ .arg(cacheFileName());
}
return true;
}
-/** Caches the given IP and geographic information to disk. Call saveToDisk()
- * when you want to write the cache to disk. */
void
-GeoIpCache::cache(GeoIp geoip)
+GeoIpCache::addToCache(const GeoIp &geoip)
{
- /* Store the entry in our in-memory cache */
- _cache.insert(geoip.ip().toIPv4Address(),
- GeoIpCacheItem(geoip,QDateTime::currentDateTime()));
+ /* Create a "range" consisting of only a single IP address. */
+ if (! contains(geoip.ip()))
+ addToCache(geoip.ip(), geoip.ip(), geoip);
}
-/** Returns a GeoIp object for the given IP from cache. */
+void
+GeoIpCache::addToCache(const QHostAddress &from, const QHostAddress &to,
+ const GeoIp &geoip)
+{
+ /* New cache entries expire 30 days from the time they are first cached. */
+ QDateTime expires = QDateTime::currentDateTime().toUTC().addDays(30);
+
+ /* Create a new GeoIpCacheItem and add it to the cache */
+ addToCache(GeoIpCacheItem(from, to, geoip, expires));
+}
+
+void
+GeoIpCache::addToCache(const GeoIpCacheItem &ci)
+{
+ if (! ci.isValid() || ci.isExpired())
+ return;
+
+ /* The key for the cache is the last IP address in the range of IP addresses
+ * covered by the GeoIpCacheItem. We do this because QMap::upperBound() and
+ * QMap::lowerBound() return an iterator to the next item higher than the
+ * search value (an IP address) if an exact match is not found.
+ */
+ _cache.insert(ci.ipRangeEnd().toIPv4Address(), ci);
+}
+
GeoIp
-GeoIpCache::geoip(QHostAddress ip)
+GeoIpCache::geoIpForAddress(const QHostAddress &ip)
{
- if (this->contains(ip)) {
- return _cache.value(ip.toIPv4Address()).geoip();
- }
+ GeoIpCacheMap::iterator i = _cache.upperBound(ip.toIPv4Address());
+ if (i != _cache.end() && (*i).contains(ip))
+ return (*i).toGeoIp(ip);
return GeoIp();
}
-/** Returns true if the given IP address is cached and the cached information
- * is not stale. */
bool
-GeoIpCache::contains(QHostAddress ip)
+GeoIpCache::contains(const QHostAddress &ip)
{
- quint32 ipv4 = ip.toIPv4Address();
- if (_cache.contains(ipv4)) {
- GeoIpCacheItem cacheItem = _cache.value(ipv4);
- return !cacheItem.isExpired();
- }
- return false;
+ GeoIpCacheMap::iterator i = _cache.upperBound(ip.toIPv4Address());
+ return (i != _cache.end() && (*i).contains(ip));
}
+
Modified: vidalia/trunk/src/vidalia/network/GeoIpCache.h
===================================================================
--- vidalia/trunk/src/vidalia/network/GeoIpCache.h 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/network/GeoIpCache.h 2009-05-13 19:07:26 UTC (rev 3768)
@@ -19,33 +19,68 @@
#include "GeoIpCacheItem.h"
-#include <QString>
-#include <QHash>
-#include <QHostAddress>
+#include <QObject>
+#include <QMap>
+class GeoIp;
+class QString;
+class QHostAddress;
-class GeoIpCache
+typedef QMap<quint32, GeoIpCacheItem> GeoIpCacheMap;
+
+
+class GeoIpCache : public QObject
{
+ Q_OBJECT
+
public:
/** Default constructor. */
- GeoIpCache();
+ GeoIpCache(QObject *parent = 0);
- /** Writes the current cache to disk. */
+ /** Writes the current cache to disk. Returns true if the cache file was
+ * successfully saved to disk. Otherwise, returns false and sets
+ * <b>errmsg</b> to a string describing the error encountered, if
+ * <b>errmsg</b> is not null.
+ */
bool saveToDisk(QString *errmsg = 0);
- /** Reads the cache in from disk. */
+
+ /** Reads the cache in from disk. Returns true if the cache file was
+ * successfully read. Otherwise, returns false and sets <b>errmsg</b> to
+ * a string describing the error encountered, if <b>errmsg</b> is not null.
+ */
bool loadFromDisk(QString *errmsg = 0);
- /** Returns the location currently used for the cache file. */
- QString cacheFilename();
- /** Caches the given IP and geographic information to disk. */
- void cache(GeoIp geoip);
- /** Returns a GeoIp object for the given IP from cache. */
- GeoIp geoip(QHostAddress ip);
- /** Returns true if the given IP address is cached. */
- bool contains(QHostAddress ip);
-
+ /** Returns the location currently used for the cache file.
+ */
+ QString cacheFileName() const;
+
+ /** Caches the geographic information in <b>geoip</b> associated with a
+ * single IP address.
+ */
+ void addToCache(const GeoIp &geoip);
+
+ /** Caches the geographic information in <b>geoip</b> associated with a
+ * range of IP addresses, from <b>from</b> to <b>to</b> (inclusive).
+ */
+ void addToCache(const QHostAddress &from, const QHostAddress &to,
+ const GeoIp &geoip);
+
+ /** Returns a GeoIp object for the given <b>ip</b> from cache. If no cached
+ * information is known for <b>ip</b>, an empty GeoIp object is returned.
+ */
+ GeoIp geoIpForAddress(const QHostAddress &ip);
+
+ /** Returns true if the cache contains geographic location information for
+ * <b>ip</b>. Otherwise, returns false.
+ */
+ bool contains(const QHostAddress &ip);
+
private:
- QHash<quint32, GeoIpCacheItem> _cache; /**< List of cached GeoIp objects. */
+ /** Adds the GeoIpCacheItem <b>ci</b> to the cache. */
+ void addToCache(const GeoIpCacheItem &ci);
+
+ /**< List of cached GeoIp objects. */
+ GeoIpCacheMap _cache;
};
#endif
Modified: vidalia/trunk/src/vidalia/network/GeoIpCacheItem.cpp
===================================================================
--- vidalia/trunk/src/vidalia/network/GeoIpCacheItem.cpp 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/network/GeoIpCacheItem.cpp 2009-05-13 19:07:26 UTC (rev 3768)
@@ -15,70 +15,169 @@
*/
#include "GeoIpCacheItem.h"
+#include "GeoIp.h"
+#include "stringutil.h"
+
+#include <QString>
+#include <QDateTime>
#include <QStringList>
+#define CACHE_KEY_FROM_IP "FROM"
+#define CACHE_KEY_TO_IP "TO"
+#define CACHE_KEY_EXPIRES "EXPIRES"
+#define CACHE_KEY_LATITUDE "LAT"
+#define CACHE_KEY_LONGITUDE "LON"
+#define CACHE_KEY_CITY "CITY"
+#define CACHE_KEY_REGION "REGION"
+#define CACHE_KEY_COUNTRY "COUNTRY"
+#define CACHE_KEY_COUNTRY_CODE "CC"
-/** Constructor */
-GeoIpCacheItem::GeoIpCacheItem(GeoIp geoip, QDateTime timestamp)
+
+GeoIpCacheItem::GeoIpCacheItem()
{
- _geoip = geoip;
- _timestamp = timestamp;
+ _fromIp = 0;
+ _toIp = 0;
}
-/** Returns true if this cache item is empty and invalid. A valid cache item
- * must have a valid GeoIp object and timestamp. */
-bool
-GeoIpCacheItem::isEmpty() const
+GeoIpCacheItem::GeoIpCacheItem(const QHostAddress &from, const QHostAddress &to,
+ const GeoIp &geoip, const QDateTime &expires)
{
- return (_geoip.isEmpty() || _timestamp.isNull());
+ _fromIp = from.toIPv4Address();
+ _toIp = to.toIPv4Address();
+ _expires = expires;
+
+ _fields.insert(CACHE_KEY_LATITUDE, geoip.latitude());
+ _fields.insert(CACHE_KEY_LONGITUDE, geoip.longitude());
+ if (! geoip.city().isEmpty())
+ _fields.insert(CACHE_KEY_CITY, geoip.city());
+ if (! geoip.region().isEmpty())
+ _fields.insert(CACHE_KEY_REGION, geoip.region());
+ if (! geoip.country().isEmpty())
+ _fields.insert(CACHE_KEY_COUNTRY, geoip.country());
+ if (! geoip.countryCode().isEmpty())
+ _fields.insert(CACHE_KEY_COUNTRY_CODE, geoip.countryCode());
}
-/** Returns a string representing the contents of this cache item, suitable
- * for writing to disk. The format is as in the following example:
- * <Geo IP Data>:<Timestamp>
- */
-QString
-GeoIpCacheItem::toString() const
+QHostAddress
+GeoIpCacheItem::ipRangeStart() const
{
- return _geoip.toString() + ":" + QString::number(_timestamp.toTime_t());
+ return QHostAddress(_fromIp);
}
-/** Returns a GeoIpCacheItem from a string as read from the cache that was
- * written to disk. The format is:
- * <Geo IP Data>[:<Timestamp>]
- *
- * If no value for Timestamp is given, the current date and time will be used.
- * If the string cannot be parsed for valid cached GeoIP data, then an empty
- * GeoIpCacheItem object is returned. The calling method should call isEmpty()
- * on the returned GeoIpCacheItem object to ensure it got a valid object.
- */
-GeoIpCacheItem
-GeoIpCacheItem::fromString(QString cacheString)
+QHostAddress
+GeoIpCacheItem::ipRangeEnd() const
{
- QDateTime timestamp;
- QStringList cacheData = cacheString.split(":");
+ return QHostAddress(_toIp);
+}
- if (cacheData.size() >= 1) {
- GeoIp geoip = GeoIp::fromString(cacheData.at(0));
- if (cacheData.size() >= 2)
- timestamp.setTime_t(cacheData.at(1).toUInt());
- else
- timestamp = QDateTime::currentDateTime();
- return GeoIpCacheItem(geoip, timestamp);
- }
- return GeoIpCacheItem();
+bool
+GeoIpCacheItem::contains(const QHostAddress &ip) const
+{
+ quint32 ipv4 = ip.toIPv4Address();
+
+ return (ipv4 >= _fromIp && ipv4 <= _toIp);
}
-/** Returns true if the cache item is too old to be considered valid. Normal
- * cached responses are valid for one month. Cached UNKNOWN responses are
- * considered valid for one week. */
bool
+GeoIpCacheItem::isValid() const
+{
+ return (_expires.isValid()
+ && ! QHostAddress(_fromIp).isNull()
+ && ! QHostAddress(_toIp).isNull()
+ && _fromIp <= _toIp
+ && _fields.contains(CACHE_KEY_LATITUDE)
+ && _fields.contains(CACHE_KEY_LONGITUDE));
+}
+
+bool
GeoIpCacheItem::isExpired() const
{
- if (_geoip.isUnknown()) {
- return (_timestamp.addDays(7) < QDateTime::currentDateTime());
+ return (_expires < QDateTime::currentDateTime().toUTC());
+}
+
+GeoIp
+GeoIpCacheItem::toGeoIp(const QHostAddress &ip) const
+{
+ if (this->contains(ip))
+ return GeoIp(ip,
+ _fields.value(CACHE_KEY_LATITUDE).toDouble(),
+ _fields.value(CACHE_KEY_LONGITUDE).toDouble(),
+ _fields.value(CACHE_KEY_CITY).toString(),
+ _fields.value(CACHE_KEY_REGION).toString(),
+ _fields.value(CACHE_KEY_COUNTRY).toString(),
+ _fields.value(CACHE_KEY_COUNTRY_CODE).toString());
+ return GeoIp();
+}
+
+QString
+GeoIpCacheItem::toCacheString() const
+{
+ QStringList keyvals;
+
+ keyvals << QString(CACHE_KEY_FROM_IP"=%1").arg(QHostAddress(_fromIp).toString());
+ keyvals << QString(CACHE_KEY_TO_IP"=%1").arg(QHostAddress(_toIp).toString());
+ keyvals << QString(CACHE_KEY_EXPIRES"=\"%1\"").arg(_expires.toString(Qt::ISODate));
+
+ foreach (QString key, _fields.keys()) {
+ QString value = _fields.value(key).toString();
+ if (value.contains(" ")) {
+ value.replace("\\", "\\\\");
+ value.replace("\"", "\\\"");
+ value = "\"" + value + "\"";
+ }
+ keyvals << key + "=" + value;
}
- return (_timestamp.addMonths(1) < QDateTime::currentDateTime());
+ return keyvals.join(" ");
}
+GeoIpCacheItem
+GeoIpCacheItem::fromCacheString(const QString &line)
+{
+ GeoIpCacheItem ci;
+ bool ok;
+
+ QHash<QString,QString> keyvals = string_parse_keyvals(line, &ok);
+ if (! ok)
+ return GeoIpCacheItem();
+
+ /* Get the range of IP addresses associated with this cache entry */
+ QHostAddress fromIp(keyvals.value(CACHE_KEY_FROM_IP));
+ QHostAddress toIp(keyvals.value(CACHE_KEY_TO_IP));
+ if (fromIp.isNull() || toIp.isNull())
+ return GeoIpCacheItem();
+ ci._fromIp = fromIp.toIPv4Address();
+ ci._toIp = toIp.toIPv4Address();
+
+ /* Extract the expiration timestamp of this entry */
+ ci._expires = QDateTime::fromString(keyvals.value(CACHE_KEY_EXPIRES),
+ Qt::ISODate);
+ if (! ci._expires.isValid())
+ ci._expires = QDateTime::currentDateTime().toUTC().addDays(30);
+
+
+ /* Make sure we have valid geographic coordinates */
+ float latitude = keyvals.value(CACHE_KEY_LATITUDE).toFloat(&ok);
+ if (! ok)
+ return GeoIpCacheItem();
+ ci._fields.insert(CACHE_KEY_LATITUDE, latitude);
+
+ float longitude = keyvals.value(CACHE_KEY_LONGITUDE).toFloat(&ok);
+ if (! ok)
+ return GeoIpCacheItem();
+ ci._fields.insert(CACHE_KEY_LONGITUDE, longitude);
+
+ /* Each of these fields is optional */
+ if (keyvals.contains(CACHE_KEY_CITY))
+ ci._fields.insert(CACHE_KEY_CITY, keyvals.value(CACHE_KEY_CITY));
+ if (keyvals.contains(CACHE_KEY_REGION))
+ ci._fields.insert(CACHE_KEY_REGION, keyvals.value(CACHE_KEY_REGION));
+ if (keyvals.contains(CACHE_KEY_COUNTRY))
+ ci._fields.insert(CACHE_KEY_COUNTRY, keyvals.value(CACHE_KEY_COUNTRY));
+ if (keyvals.contains(CACHE_KEY_COUNTRY_CODE))
+ ci._fields.insert(CACHE_KEY_COUNTRY_CODE,
+ keyvals.value(CACHE_KEY_COUNTRY_CODE));
+
+ return ci;
+}
+
Modified: vidalia/trunk/src/vidalia/network/GeoIpCacheItem.h
===================================================================
--- vidalia/trunk/src/vidalia/network/GeoIpCacheItem.h 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/network/GeoIpCacheItem.h 2009-05-13 19:07:26 UTC (rev 3768)
@@ -17,38 +17,80 @@
#ifndef _GEOIPCACHEITEM_H
#define _GEOIPCACHEITEM_H
-#include "GeoIp.h"
-
+#include <QHash>
+#include <QString>
+#include <QVariant>
#include <QDateTime>
+class GeoIp;
+class QHostAddress;
+
class GeoIpCacheItem
{
public:
- /** Default constructor */
- GeoIpCacheItem() {};
- /** Constructor. */
- GeoIpCacheItem(GeoIp geoip, QDateTime timestamp);
+ /** Default constructor
+ */
+ GeoIpCacheItem();
- /** Returns the IP of this cache item. */
- QHostAddress ip() const { return _geoip.ip(); }
- /** Returns the cached GeoIp object. */
- GeoIp geoip() const { return _geoip; }
- /** Returns true if this cache item is expired. */
+ /** Constructor.
+ */
+ GeoIpCacheItem(const QHostAddress &from, const QHostAddress &to,
+ const GeoIp &geoIp, const QDateTime &expires);
+
+ /** Returns the first IP address in the range of IP addresses associated
+ * with this GeoIpCacheItem.
+ */
+ QHostAddress ipRangeStart() const;
+
+ /** Returns the last IP address in the range of IP addresses associated
+ * with this GeoIpCacheItem.
+ */
+ QHostAddress ipRangeEnd() const;
+
+ /** Returns true if <b>ip</b> is within the range of IP addresses associated
+ * with this GeoIpCacheItem.
+ * \sa ipRangeStart()
+ * \sa ipRangeEnd()
+ */
+ bool contains(const QHostAddress &ip) const;
+
+ /** Returns true if this GeoIpCacheItem object contains valid values for
+ * all required fields.
+ */
+ bool isValid() const;
+
+ /** Returns true if the cache item is too old to be considered accurate.
+ * Cached GeoIp responses are considered valid for thirty days after they
+ * are first added to the cache.
+ */
bool isExpired() const;
- /** Returns true if this cache item is empty and invalid. */
- bool isEmpty() const;
- /** Returns a string representing the contents of this cache item, suitable
- * for writing to disk. */
- QString toString() const;
- /** Returns a GeoIpCacheItem from a string as read from the cache that was
- * written to disk. */
- static GeoIpCacheItem fromString(QString cacheString);
+ /** Returns a GeoIp object for <b>ip</b>, populated with the cached
+ * geographic information stored by this GeoIpCacheObject. If <b>ip</b>
+ * is not within the range of IP addresses associated with this object,
+ * an empty GeoIp object is returned.
+ * \sa contains
+ */
+ GeoIp toGeoIp(const QHostAddress &ip) const;
+ /** Formats the fields contained in this GeoIpCacheItem as a string
+ * suitable for writing to a cache file.
+ */
+ QString toCacheString() const;
+
+ /** Parses <b>cacheLine</b> and constructs a new GeoIpCacheItem object
+ * with the parsed values. The format of <b>cacheLine</b> must follow the
+ * format as produced by toCacheString().
+ * \sa toCacheString()
+ */
+ static GeoIpCacheItem fromCacheString(const QString &cacheLine);
+
private:
- GeoIp _geoip; /**< Cached GeoIp item. */
- QDateTime _timestamp; /**< Time this item was cached. */
+ quint32 _fromIp;
+ quint32 _toIp;
+ QDateTime _expires; /**< Time this item was cached. */
+ QHash<QString,QVariant> _fields;
};
#endif
Modified: vidalia/trunk/src/vidalia/network/GeoIpRequest.cpp
===================================================================
--- vidalia/trunk/src/vidalia/network/GeoIpRequest.cpp 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/network/GeoIpRequest.cpp 2009-05-13 19:07:26 UTC (rev 3768)
@@ -17,7 +17,11 @@
#include "GeoIpRequest.h"
#include "ZlibByteArray.h"
+#include <QString>
+#include <QHostAddress>
+#include <QHttpRequestHeader>
+
/** Creates an HTTP POST header for this request, based on the
* Host, Page, and content-length values. */
QHttpRequestHeader
@@ -45,7 +49,7 @@
void
GeoIpRequest::setRequest(const QList<QHostAddress> &ips)
{
- _request = "ip=";
+ _request = "format=long&ip=";
int ipcount = ips.size();
/* Add each IP to a comma-delimited list. */
Modified: vidalia/trunk/src/vidalia/network/GeoIpRequest.h
===================================================================
--- vidalia/trunk/src/vidalia/network/GeoIpRequest.h 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/network/GeoIpRequest.h 2009-05-13 19:07:26 UTC (rev 3768)
@@ -19,11 +19,12 @@
#include <QList>
#include <QString>
-#include <QByteArray>
-#include <QHostAddress>
#include <QHttpRequestHeader>
+class QHostAddress;
+class QByteArray;
+
class GeoIpRequest
{
public:
Modified: vidalia/trunk/src/vidalia/network/GeoIpResolver.cpp
===================================================================
--- vidalia/trunk/src/vidalia/network/GeoIpResolver.cpp 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/network/GeoIpResolver.cpp 2009-05-13 19:07:26 UTC (rev 3768)
@@ -15,29 +15,35 @@
*/
#include "GeoIpResolver.h"
+#include "GeoIpRequest.h"
+#include "GeoIpResponse.h"
+#include "GeoIp.h"
#include "Vidalia.h"
+#include "stringutil.h"
#include "TorSslSocket.h"
-/** Host for the geo ip information. */
-#define GEOIP_HOST "geoip.vidalia-project.net"
-/** The SSL GeoIP service runs on port 1443 (443 was taken). */
-#define GEOIP_SSL_PORT 1443
-/** Page that we request the geo ip information from. */
-#define GEOIP_PAGE "/cgi-bin/geoip"
+/** Host for the GeoIP information. */
+#define GEOIP_HOST "geoips.vidalia-project.net"
+/** The SSL GeoIP service runs on port 443. */
+#define GEOIP_SSL_PORT 443
+/** Page that we request the GeoIP information from. */
+#define GEOIP_PAGE "/cgi-bin/geoip.py"
/** Default constructor. */
-GeoIpResolver::GeoIpResolver()
+GeoIpResolver::GeoIpResolver(QObject *parent)
+ : QObject(parent)
{
_socksAddr = QHostAddress::LocalHost;
_socksPort = 9050;
+ _cache = new GeoIpCache(this);
}
/** Sets the address and port of Tor, through which GeoIP requests will be
* made. */
void
-GeoIpResolver::setSocksHost(QHostAddress addr, quint16 port)
+GeoIpResolver::setSocksHost(const QHostAddress &addr, quint16 port)
{
_socksAddr = addr;
_socksPort = port;
@@ -47,10 +53,10 @@
* signal will be emitted and true returned if we have cached geographic
* information for <b>ip</b>. Otherwise, this returns false. */
bool
-GeoIpResolver::resolveFromCache(QHostAddress ip)
+GeoIpResolver::resolveFromCache(const QHostAddress &ip)
{
- if (_cache.contains(ip)) {
- emit resolved(-1, QList<GeoIp>() << _cache.geoip(ip));
+ if (_cache->contains(ip)) {
+ emit resolved(-1, QList<GeoIp>() << _cache->geoIpForAddress(ip));
return true;
}
return false;
@@ -59,21 +65,19 @@
/** Resolves a list of IPs to a geographic location, but only those which are
* cached. Returns a list of IPs that were not in the cache. */
QList<QHostAddress>
-GeoIpResolver::resolveFromCache(QList<QHostAddress> ips)
+GeoIpResolver::resolveFromCache(const QList<QHostAddress> &ips)
{
QList<GeoIp> cached;
/* Build a list of which IPs have cached GeoIp information */
foreach (QHostAddress ip, ips) {
- if (_cache.contains(ip)) {
- ips.removeAt(ips.indexOf(ip));
- cached << _cache.geoip(ip);
- }
+ if (_cache->contains(ip))
+ cached << _cache->geoIpForAddress(ip);
}
/* If any were cached, emit their results now */
if (cached.size() > 0) {
- vInfo("Resolved %1 GeoIP entries from cache.").arg(ips.size());
+ vInfo("Resolved %1 GeoIP entries from cache.").arg(cached.size());
emit resolved(-1, cached);
}
return ips;
@@ -81,7 +85,7 @@
/** Resolves a single IP to a geographic location. */
int
-GeoIpResolver::resolve(QHostAddress ip)
+GeoIpResolver::resolve(const QHostAddress &ip)
{
return resolve(QList<QHostAddress>() << ip);
}
@@ -95,7 +99,8 @@
if (!_requestList.contains(socket)) {
return;
}
- GeoIpRequest *req = (GeoIpRequest *)_requestList.value(socket);
+ GeoIpRequest *req = static_cast<GeoIpRequest *>(_requestList.value(socket));
+
vInfo("Connected to the GeoIP host. Sending request for %1 uncached "
"GeoIP entries. (request id %2)").arg(req->size()).arg(req->id());
@@ -112,63 +117,107 @@
if (!_requestList.contains(socket)) {
return;
}
- GeoIpRequest *request = (GeoIpRequest *)_requestList.take(socket);
+ GeoIpRequest *req = static_cast<GeoIpRequest *>(_requestList.take(socket));
- /* Read and parse the response */
+ /* Read and parse the response header */
GeoIpResponse response = GeoIpResponse(socket->readAll());
/* Check the response code and see what we got */
if (response.statusCode() == 200) {
- /* We got a 200 OK, so get the Geo IP information and cache the results */
- int numCached = 0, i = 0;
- QList<GeoIp> geoips = response.geoIps();
- foreach (GeoIp geoip, geoips) {
- QHostAddress ip = geoip.ip();
-
- if (request->contains(ip)) {
- /* This is a requested geoip item, so if it wasn't cached, then
- * cache it now. */
- if (!_cache.contains(ip)) {
- _cache.cache(geoip);
- numCached++;
- }
- i++;
- } else {
- /* This item wasn't requested, so remove it. According to the Qt docs,
- * this is safe to do inside the foreach() loop because, "Qt
- * automatically takes a copy of the container when it enters a
- * foreach loop. If you modify the container as you are iterating,
- * that won't affect the loop." */
- vWarn("Received a GeoIP entry for IP address %1 that was not included "
- "in the initial request. (request id %2)").arg(ip)
- .arg(request->id());
- geoips.removeAt(i);
- }
- }
- /* If new results were cached, save them to disk */
- if (numCached > 0) {
- _cache.saveToDisk();
- }
- /* Emit the results */
- vInfo("Parsed %1 entries from the GeoIP response. (request id %2)")
- .arg(geoips.size()).arg(request->id());
- emit resolved(request->id(), geoips);
+ /* We got a 200 OK, so get the Geo IP information from the response body
+ * and cache the results. */
+ parseGeoIpResponse(response.content(), req);
} else {
/* We failed to get the Geo IP information, so emit resolveFailed and
* include the HTTP status message. */
- vWarn("GeoIP resolution failed (request id %1): %2").arg(request->id())
+ vWarn("GeoIP resolution failed (request id %1): %2").arg(req->id())
.arg(response.statusMessage());
- emit resolveFailed(request->id(), response.statusMessage());
+ emit resolveFailed(req->id(), response.statusMessage());
}
/* Close the socket and clean up */
socket->close();
delete socket;
- delete request;
+ delete req;
}
+void
+GeoIpResolver::parseGeoIpResponse(const QByteArray &response,
+ GeoIpRequest *request)
+{
+ QList<GeoIp> geoIpList;
+ QHash<QString,QString> keyvals;
+ QHostAddress ip, from, to;
+ QString city, region, country, cc;
+ float latitude, longitude;
+ GeoIp geoIp;
+ int numCached = 0;
+ bool ok;
+
+ QStringList lines = QString(response).split("\n", QString::SkipEmptyParts);
+ foreach (QString line, lines) {
+ /* Split the key=value formatted GeoIP record into keys and values */
+ QHash<QString,QString> keyvals = string_parse_keyvals(line.trimmed(), &ok);
+ if (! ok)
+ goto err;
+
+ /* Extract each of the required fields from the GeoIP record */
+ ip = QHostAddress(keyvals.value("IP"));
+ if (ip.isNull())
+ goto err;
+ latitude = keyvals.value("LAT").toFloat(&ok);
+ if (! ok)
+ goto err;
+ longitude = keyvals.value("LON").toFloat(&ok);
+ if (! ok)
+ goto err;
+
+ /* Each of these fields is optional */
+ city = keyvals.value("CITY");
+ region = keyvals.value("REGION");
+ country = keyvals.value("COUNTRY");
+ cc = keyvals.value("CC");
+
+ geoIp = GeoIp(ip, latitude, longitude, city, region, country, cc);
+ if (! geoIp.isValid())
+ goto err;
+
+ if (request->contains(ip)) {
+ if (! _cache->contains(ip)) {
+ from = QHostAddress(keyvals.value("FROM"));
+ to = QHostAddress(keyvals.value("TO"));
+ if (! from.isNull() && ! to.isNull())
+ _cache->addToCache(from, to, geoIp);
+ else
+ _cache->addToCache(geoIp);
+ numCached++;
+ }
+
+ geoIpList << geoIp;
+ continue;
+
+err:
+ vInfo("Ignored improperly formatted GeoIP record (request id %1): %2")
+ .arg(line).arg(request->id());
+ } else {
+ /* This item wasn't requested, so just log it and ignore. */
+ vWarn("Received a GeoIP entry for IP address %1 that was not included "
+ "in the initial request. (request id %2)").arg(ip)
+ .arg(request->id());
+ }
+ }
+ /* If new results were cached, save them to disk */
+ if (numCached > 0)
+ _cache->saveToDisk();
+
+ /* Emit the results */
+ vInfo("Parsed %1 entries from the GeoIP response. (request id %2)")
+ .arg(geoIpList.size()).arg(request->id());
+ emit resolved(request->id(), geoIpList);
+}
+
/** Called when an error has occurred requesting Geo IP information. */
void
-GeoIpResolver::socketError(QString errorString)
+GeoIpResolver::socketError(const QString &errorString)
{
/* Find the socket and request for whoever called this slot */
QAbstractSocket *socket = dynamic_cast<QAbstractSocket *>(sender());
@@ -177,22 +226,22 @@
}
/* We expect a remote host to close the socket, because that's how the HTTP
- * server tells us he's done talkig to us. */
+ * server tells us he's done talking to us. */
if (socket->error() != QAbstractSocket::RemoteHostClosedError) {
/* Emit the failure and clean up */
- GeoIpRequest *request = (GeoIpRequest *)_requestList.take(socket);
- emit resolveFailed(request->id(), errorString);
+ GeoIpRequest *req = static_cast<GeoIpRequest *>(_requestList.take(socket));
+ emit resolveFailed(req->id(), errorString);
socket->abort();
- vWarn("GeoIP request socket error (request id %1): %2").arg(request->id())
+ vWarn("GeoIP request socket error (request id %1): %2").arg(req->id())
.arg(errorString);
delete socket;
- delete request;
+ delete req;
}
}
/** Creates an HTTP request for Geo IP information. */
GeoIpRequest*
-GeoIpResolver::createRequest(QList<QHostAddress> ips)
+GeoIpResolver::createRequest(const QList<QHostAddress> &ips)
{
static int id = -1;
GeoIpRequest *request = new GeoIpRequest(++id);
@@ -204,18 +253,16 @@
/** Resolves a list of IPs to a geographic location. */
int
-GeoIpResolver::resolve(QList<QHostAddress> ips)
+GeoIpResolver::resolve(const QList<QHostAddress> &ips)
{
/* Resolve the cached IPs and get a list of IPs that still need to be
* resolved to a lat and long. */
QList<QHostAddress> uncached = resolveFromCache(ips);
- if (!uncached.size()) {
+ if (! uncached.size())
return -1;
- }
/* Create a socket used to request the geo ip information. */
TorSslSocket *socket = new TorSslSocket(_socksAddr, _socksPort);
-
connect(socket, SIGNAL(connectedToRemoteHost()), this, SLOT(connected()),
Qt::QueuedConnection);
connect(socket, SIGNAL(socketError(QString)),
@@ -223,7 +270,7 @@
Qt::QueuedConnection);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()),
Qt::QueuedConnection);
- GeoIpRequest *request = createRequest(ips);
+ GeoIpRequest *request = createRequest(uncached);
_requestList.insert(socket, request);
/* Connect so we can send our request and return the request ID. */
Modified: vidalia/trunk/src/vidalia/network/GeoIpResolver.h
===================================================================
--- vidalia/trunk/src/vidalia/network/GeoIpResolver.h 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/network/GeoIpResolver.h 2009-05-13 19:07:26 UTC (rev 3768)
@@ -17,44 +17,46 @@
#ifndef _GEOIPRESOLVER_H
#define _GEOIPRESOLVER_H
-#include "GeoIp.h"
#include "GeoIpCache.h"
-#include "GeoIpRequest.h"
-#include "GeoIpResponse.h"
#include <QObject>
#include <QList>
#include <QHash>
-#include <QString>
#include <QHostAddress>
+class GeoIp;
+class GeoIpRequest;
+class GeoIpResponse;
+class QString;
+class QAbstractSocket;
+
class GeoIpResolver : public QObject
{
Q_OBJECT
public:
/** Default constructor. */
- GeoIpResolver();
+ GeoIpResolver(QObject *parent = 0);
/** Sets the address and port of Tor, through which GeoIP requests will be
* made. */
- void setSocksHost(QHostAddress addr, quint16 port);
+ void setSocksHost(const QHostAddress &addr, quint16 port);
/** Resolves a single IP to a geographic location. */
- int resolve(QHostAddress ip);
+ int resolve(const QHostAddress &ip);
/** Resolves a list of IPs to a geographic location. */
- int resolve(QList<QHostAddress> ips);
+ int resolve(const QList<QHostAddress> &ips);
/** Resolves <b>ip</b> to geographic information only if it is cached. */
- bool resolveFromCache(QHostAddress ip);
+ bool resolveFromCache(const QHostAddress &ip);
/** Resolves a list of IPs to a geographic location, but only those which
* are cached. Returns a list of which IPs were not cached. */
- QList<QHostAddress> resolveFromCache(QList<QHostAddress> ips);
+ QList<QHostAddress> resolveFromCache(const QList<QHostAddress> &ips);
signals:
/** Emitted when a list of IPs have been resolved to lat/long. */
- void resolved(int id, QList<GeoIp> geoips);
+ void resolved(int id, const QList<GeoIp> &geoips);
/** Emitted when a resolve has failed. */
- void resolveFailed(int id, QString errorString);
+ void resolveFailed(int id, const QString &errorString);
private slots:
/** Called when the socket has connected to the Geo IP host. */
@@ -62,14 +64,16 @@
/** Called when the socket has disconnected from the Geo IP host. */
void disconnected();
/** Called when an error has occurred getting the Geo IP information. */
- void socketError(QString errorString);
+ void socketError(const QString &errorString);
private:
/** Creates an HTTP request for Geo IP information. */
- GeoIpRequest* createRequest(QList<QHostAddress> ips);
+ GeoIpRequest* createRequest(const QList<QHostAddress> &ips);
+ void parseGeoIpResponse(const QByteArray &response, GeoIpRequest *request);
+
/**< Cached GeoIp objects. */
- GeoIpCache _cache;
+ GeoIpCache* _cache;
/**< List of sockets used for requests. */
QHash<QAbstractSocket *,GeoIpRequest*> _requestList;
/** Tor's SocksListenAddress. */
Modified: vidalia/trunk/src/vidalia/network/GeoIpResponse.cpp
===================================================================
--- vidalia/trunk/src/vidalia/network/GeoIpResponse.cpp 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/network/GeoIpResponse.cpp 2009-05-13 19:07:26 UTC (rev 3768)
@@ -14,10 +14,15 @@
** \brief Parses a response to a previous GeoIP request
*/
-#include <GeoIpResponse.h>
-#include <ZlibByteArray.h>
+#include "GeoIpResponse.h"
+#include "GeoIp.h"
+#include "Vidalia.h"
+#include "ZlibByteArray.h"
+
+#include <QByteArray>
#include <QStringList>
+#include <QHttpResponseHeader>
/** Status code for a successful HTTP request. */
#define STATUS_HTTP_OK 200
@@ -27,9 +32,7 @@
#define STATUS_TRANSFER_ENCODING_ERR 602
-/** Constructor. Parses the response data for an HTTP header and Geo IP
- * information. */
-GeoIpResponse::GeoIpResponse(QByteArray response)
+GeoIpResponse::GeoIpResponse(const QByteArray &response)
{
QString errmsg;
@@ -39,13 +42,13 @@
/* Parse out the Geo IP information, if any was included. */
if (headerPos > 0 && _header.statusCode() == STATUS_HTTP_OK) {
- QByteArray content = response.mid(headerPos+4);
+ _content = response.mid(headerPos+4);
if (_header.hasKey("Transfer-Encoding")) {
QString encoding = _header.value("Transfer-Encoding");
if (encoding == "chunked") {
- content = decodeChunked(content);
- if (content.isEmpty()) {
+ _content = decodeChunked(_content);
+ if (_content.isEmpty()) {
_header.setStatusLine(STATUS_TRANSFER_ENCODING_ERR,
QString("Failed to decode chunked response"));
return;
@@ -72,29 +75,19 @@
return;
}
- content = ZlibByteArray::uncompress(content, method, &errmsg);
- if (content.isEmpty()) {
+ _content = ZlibByteArray::uncompress(_content, method, &errmsg);
+ if (_content.isEmpty()) {
_header.setStatusLine(STATUS_CONTENT_ENCODING_ERR,
QString("Content decoding using method '%1' failed: %2")
.arg(encoding).arg(errmsg));
return;
}
}
-
- /* Parse the Geo IP information in each line */
- QStringList lines = QString(content).split("\n");
- foreach (QString line, lines) {
- GeoIp geoip = GeoIp::fromString(line);
- if (!geoip.isEmpty())
- _geoips << geoip;
- }
}
}
-/** Decodes a <b>chunked</b> transfer encoding. Returns the unchunked
- * result on success, or an empty QByteArray if decoding fails. */
QByteArray
-GeoIpResponse::decodeChunked(QByteArray chunked)
+GeoIpResponse::decodeChunked(const QByteArray &chunked)
{
QByteArray unchunked;
QString sizeString;
@@ -124,3 +117,21 @@
return unchunked;
}
+int
+GeoIpResponse::statusCode() const
+{
+ return _header.statusCode();
+}
+
+QString
+GeoIpResponse::statusMessage() const
+{
+ return _header.reasonPhrase();
+}
+
+QByteArray
+GeoIpResponse::content() const
+{
+ return _content;
+}
+
Modified: vidalia/trunk/src/vidalia/network/GeoIpResponse.h
===================================================================
--- vidalia/trunk/src/vidalia/network/GeoIpResponse.h 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/network/GeoIpResponse.h 2009-05-13 19:07:26 UTC (rev 3768)
@@ -17,34 +17,41 @@
#ifndef _GEOIPRESPONSE_H
#define _GEOIPRESPONSE_H
-#include <GeoIp.h>
-
#include <QList>
#include <QByteArray>
#include <QHttpResponseHeader>
+class GeoIp;
+class QString;
+class QStringList;
+
class GeoIpResponse
{
public:
/** Constructor. Parses the response data for an HTTP header and Geo IP
* information. */
- GeoIpResponse(QByteArray response);
+ GeoIpResponse(const QByteArray &response);
- /** Returns the HTTP status code for this response. */
- int statusCode() { return _header.statusCode(); }
- /** Returns the HTTP status message for this response. */
- QString statusMessage() { return _header.reasonPhrase(); }
- /** Returns the Geo IP information contained in this response. */
- QList<GeoIp> geoIps() { return _geoips; }
+ /** Returns the HTTP status code for this response.
+ */
+ int statusCode() const;
+
+ /** Returns the HTTP status message for this response.
+ */
+ QString statusMessage() const;
+
+ /** Returns the Geo IP information contained in this response.
+ */
+ QByteArray content() const;
private:
/** Decodes a <b>chunked</b> transfer encoding. Returns the unchunked
* result on success, or an empty QByteArray if decoding fails. */
- QByteArray decodeChunked(QByteArray chunked);
+ QByteArray decodeChunked(const QByteArray &chunked);
QHttpResponseHeader _header; /**< HTTP response header. */
- QList<GeoIp> _geoips; /**< Geo IP information in this response. */
+ QByteArray _content; /**< Geo IP information in this response. */
};
#endif
Modified: vidalia/trunk/src/vidalia/network/NetViewer.cpp
===================================================================
--- vidalia/trunk/src/vidalia/network/NetViewer.cpp 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/network/NetViewer.cpp 2009-05-13 19:07:26 UTC (rev 3768)
@@ -461,6 +461,7 @@
NetViewer::resolved(int id, const QList<GeoIp> &geoips)
{
Q_UNUSED(id);
+
QString ip;
RouterListItem *router;
@@ -469,8 +470,6 @@
ip = geoip.ip().toString();
QList<QString> ids = _resolveMap.values(ip);
_resolveMap.remove(ip);
- if (geoip.isUnknown())
- continue; /* We don't know where this router is */
/* Update their geographic location information with the results of this
* GeoIP query. */
Modified: vidalia/trunk/src/vidalia/network/RouterListItem.cpp
===================================================================
--- vidalia/trunk/src/vidalia/network/RouterListItem.cpp 2009-05-13 18:54:28 UTC (rev 3767)
+++ vidalia/trunk/src/vidalia/network/RouterListItem.cpp 2009-05-13 19:07:26 UTC (rev 3768)
@@ -93,15 +93,15 @@
void
RouterListItem::setLocation(const GeoIp &geoip)
{
- QPixmap flag(":/images/flags/" + geoip.country().toLower() + ".png");
+ QPixmap flag(":/images/flags/" + geoip.countryCode().toLower() + ".png");
if (!flag.isNull()) {
setIcon(COUNTRY_COLUMN, QIcon(flag));
}
- setToolTip(COUNTRY_COLUMN, geoip.toLocation());
+ setToolTip(COUNTRY_COLUMN, geoip.toString());
if (_rd)
- _rd->setLocation(geoip.toLocation());
- _country = geoip.country();
+ _rd->setLocation(geoip.toString());
+ _country = geoip.countryCode();
}
/** Overload the comparison operator. */