geoipresponse.cpp

Go to the documentation of this file.
00001 /*
00002 **  This file is part of Vidalia, and is subject to the license terms in the
00003 **  LICENSE file, found in the top level directory of this distribution. If you
00004 **  did not receive the LICENSE file with this file, you may obtain it from the
00005 **  Vidalia source package distributed by the Vidalia Project at
00006 **  http://www.vidalia-project.net/. No part of Vidalia, including this file,
00007 **  may be copied, modified, propagated, or distributed except according to the
00008 **  terms described in the LICENSE file.
00009 */
00010 
00011 /*
00012 ** \file geoipresponse.cpp
00013 ** \version $Id: geoipresponse.cpp 2533 2008-04-25 04:50:43Z edmanm $
00014 ** \brief Parses a response to a previous GeoIP request
00015 */
00016 
00017 #include <QStringList>
00018 #include <zlibbytearray.h>
00019 
00020 #include "geoipresponse.h"
00021 
00022 /** Status code for a successful HTTP request. */
00023 #define STATUS_HTTP_OK                 200
00024 /** Status code for content encoding errors. */
00025 #define STATUS_CONTENT_ENCODING_ERR    601
00026 /** Status code for transfer encoding errors. */
00027 #define STATUS_TRANSFER_ENCODING_ERR   602
00028 
00029 
00030 /** Constructor. Parses the response data for an HTTP header and Geo IP
00031  * information. */
00032 GeoIpResponse::GeoIpResponse(QByteArray response)
00033 {
00034   QString errmsg;
00035   
00036   /* Parse out the header */
00037   int headerPos = response.indexOf("\r\n\r\n");
00038   _header = QHttpResponseHeader(QString(response.mid(0, headerPos)));
00039 
00040   /* Parse out the Geo IP information, if any was included. */
00041   if (headerPos > 0 && _header.statusCode() == STATUS_HTTP_OK) {
00042     QByteArray content = response.mid(headerPos+4);
00043  
00044     if (_header.hasKey("Transfer-Encoding")) {
00045       QString encoding = _header.value("Transfer-Encoding");
00046       if (encoding == "chunked") {
00047         content = decodeChunked(content);
00048         if (content.isEmpty()) {
00049           _header.setStatusLine(STATUS_TRANSFER_ENCODING_ERR,
00050             QString("Failed to decode chunked response"));
00051           return;
00052         }
00053       } else {
00054         _header.setStatusLine(STATUS_TRANSFER_ENCODING_ERR,
00055           QString("Unknown transfer encoding '%1'").arg(encoding));
00056         return;
00057       }
00058     }
00059  
00060     if (_header.hasKey("Content-Encoding")) {
00061       ZlibByteArray::CompressionMethod method;
00062       QString encoding = _header.value("Content-Encoding");
00063       if (encoding == "gzip" || encoding == "x-gzip") {
00064         method = ZlibByteArray::Gzip;
00065       } else if (encoding == "deflate" || encoding == "x-deflate") {
00066         method = ZlibByteArray::Zlib;
00067       } else if (encoding == "text/plain") {
00068         method = ZlibByteArray::None;
00069       } else {
00070         _header.setStatusLine(STATUS_CONTENT_ENCODING_ERR,
00071           QString("Unknown content encoding '%1'").arg(encoding));
00072         return;
00073       }
00074  
00075       content = ZlibByteArray::uncompress(content, method, &errmsg);
00076       if (content.isEmpty()) {
00077         _header.setStatusLine(STATUS_CONTENT_ENCODING_ERR,
00078           QString("Content decoding using method '%1' failed: %2")
00079                                        .arg(encoding).arg(errmsg));
00080         return;
00081       }
00082     }
00083 
00084     /* Parse the Geo IP information in each line */
00085     QStringList lines = QString(content).split("\n");
00086     foreach (QString line, lines) {
00087       GeoIp geoip = GeoIp::fromString(line);
00088       if (!geoip.isEmpty())
00089         _geoips << geoip;
00090     }
00091   }
00092 }
00093 
00094 /** Decodes a <b>chunked</b> transfer encoding. Returns the unchunked 
00095  * result on success, or an empty QByteArray if decoding fails. */
00096 QByteArray
00097 GeoIpResponse::decodeChunked(QByteArray chunked)
00098 {
00099   QByteArray unchunked;
00100   QString sizeString;
00101   int eol, chunkedlen, chunksize, offset = 0;
00102   bool ok;
00103  
00104   chunkedlen = chunked.length();
00105   while (offset < chunkedlen) {
00106     eol = chunked.indexOf("\r\n", offset);
00107     if (eol < 0)
00108       return QByteArray();
00109     sizeString = QString::fromAscii(chunked.mid(offset, eol-offset));
00110     offset = eol + 2; /* Skip past the CRLF */
00111     
00112     if (sizeString.indexOf(";") >= 0)
00113       sizeString.truncate(sizeString.indexOf(";")); 
00114     chunksize = sizeString.toInt(&ok, 16);
00115     if (!ok || chunksize > chunkedlen - offset)
00116       return QByteArray();
00117     if (!chunksize)
00118       break; /* Last chunk. Ignore the trailer. */
00119     
00120     unchunked.append(chunked.mid(offset, chunksize));
00121     offset += chunksize;
00122     offset += 2; /* CRLF after each chunk */
00123   }
00124   return unchunked;
00125 }
00126 

Generated on Sat Aug 16 17:31:48 2008 for Vidalia by  doxygen 1.5.6