geoipresponse.cpp

Go to the documentation of this file.
00001 /****************************************************************
00002  *  Vidalia is distributed under the following license:
00003  *
00004  *  Copyright (C) 2006-2007,  Matt Edman, Justin Hipple
00005  *
00006  *  This program is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU General Public License
00008  *  as published by the Free Software Foundation; either version 2
00009  *  of the License, or (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  *  Boston, MA  02110-1301, USA.
00020  ****************************************************************/
00021 
00022 /**
00023  * \file geoipresponse.cpp
00024  * \version $Id: geoipresponse.cpp 1593 2007-01-16 03:52:47Z edmanm $
00025  * \brief Parses a response to a previous GeoIP request
00026  */
00027 
00028 #include <QStringList>
00029 #include <util/zlibbytearray.h>
00030 
00031 #include "geoipresponse.h"
00032 
00033 /** Status code for a successful HTTP request. */
00034 #define STATUS_HTTP_OK                 200
00035 /** Status code for content encoding errors. */
00036 #define STATUS_CONTENT_ENCODING_ERR    601
00037 /** Status code for transfer encoding errors. */
00038 #define STATUS_TRANSFER_ENCODING_ERR   602
00039 
00040 
00041 /** Constructor. Parses the response data for an HTTP header and Geo IP
00042  * information. */
00043 GeoIpResponse::GeoIpResponse(QByteArray response)
00044 {
00045   QString errmsg;
00046   
00047   /* Parse out the header */
00048   int headerPos = response.indexOf("\r\n\r\n");
00049   _header = QHttpResponseHeader(QString(response.mid(0, headerPos)));
00050 
00051   /* Parse out the Geo IP information, if any was included. */
00052   if (headerPos > 0 && _header.statusCode() == STATUS_HTTP_OK) {
00053     QByteArray content = response.mid(headerPos+4);
00054  
00055     if (_header.hasKey("Transfer-Encoding")) {
00056       QString encoding = _header.value("Transfer-Encoding");
00057       if (encoding == "chunked") {
00058         content = decodeChunked(content);
00059         if (content.isEmpty()) {
00060           _header.setStatusLine(STATUS_TRANSFER_ENCODING_ERR,
00061             QString("Failed to decode chunked response"));
00062           return;
00063         }
00064       } else {
00065         _header.setStatusLine(STATUS_TRANSFER_ENCODING_ERR,
00066           QString("Unknown transfer encoding '%1'").arg(encoding));
00067         return;
00068       }
00069     }
00070  
00071     if (_header.hasKey("Content-Encoding")) {
00072       ZlibByteArray::CompressionMethod method;
00073       QString encoding = _header.value("Content-Encoding");
00074       if (encoding == "gzip" || encoding == "x-gzip") {
00075         method = ZlibByteArray::Gzip;
00076       } else if (encoding == "deflate" || encoding == "x-deflate") {
00077         method = ZlibByteArray::Zlib;
00078       } else if (encoding == "text/plain") {
00079         method = ZlibByteArray::None;
00080       } else {
00081         _header.setStatusLine(STATUS_CONTENT_ENCODING_ERR,
00082           QString("Unknown content encoding '%1'").arg(encoding));
00083         return;
00084       }
00085  
00086       content = ZlibByteArray::uncompress(content, method, &errmsg);
00087       if (content.isEmpty()) {
00088         _header.setStatusLine(STATUS_CONTENT_ENCODING_ERR,
00089           QString("Content decoding using method '%1' failed: %2")
00090                                        .arg(encoding).arg(errmsg));
00091         return;
00092       }
00093     }
00094 
00095     /* Parse the Geo IP information in each line */
00096     QStringList lines = QString(content).split("\n");
00097     foreach (QString line, lines) {
00098       GeoIp geoip = GeoIp::fromString(line);
00099       if (!geoip.isEmpty())
00100         _geoips << geoip;
00101     }
00102   }
00103 }
00104 
00105 /** Decodes a <b>chunked</b> transfer encoding. Returns the unchunked 
00106  * result on success, or an empty QByteArray if decoding fails. */
00107 QByteArray
00108 GeoIpResponse::decodeChunked(QByteArray chunked)
00109 {
00110   QByteArray unchunked;
00111   QString sizeString;
00112   int eol, chunkedlen, chunksize, offset = 0;
00113   bool ok;
00114  
00115   chunkedlen = chunked.length();
00116   while (offset < chunkedlen) {
00117     eol = chunked.indexOf("\r\n", offset);
00118     if (eol < 0)
00119       return QByteArray();
00120     sizeString = QString::fromAscii(chunked.mid(offset, eol-offset));
00121     offset = eol + 2; /* Skip past the CRLF */
00122     
00123     if (sizeString.indexOf(";") >= 0)
00124       sizeString.truncate(sizeString.indexOf(";")); 
00125     chunksize = sizeString.toInt(&ok, 16);
00126     if (!ok || chunksize > chunkedlen - offset)
00127       return QByteArray();
00128     if (!chunksize)
00129       break; /* Last chunk. Ignore the trailer. */
00130     
00131     unchunked.append(chunked.mid(offset, chunksize));
00132     offset += chunksize;
00133     offset += 2; /* CRLF after each chunk */
00134   }
00135   return unchunked;
00136 }
00137 

Generated on Wed Sep 5 15:49:27 2007 for Vidalia by  doxygen 1.5.3