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 3768 2009-05-13 19:07:26Z edmanm $
00014 ** \brief Parses a response to a previous GeoIP request
00015 */
00016 
00017 #include "GeoIpResponse.h"
00018 #include "GeoIp.h"
00019 #include "Vidalia.h"
00020 
00021 #include "ZlibByteArray.h"
00022 
00023 #include <QByteArray>
00024 #include <QStringList>
00025 #include <QHttpResponseHeader>
00026 
00027 /** Status code for a successful HTTP request. */
00028 #define STATUS_HTTP_OK                 200
00029 /** Status code for content encoding errors. */
00030 #define STATUS_CONTENT_ENCODING_ERR    601
00031 /** Status code for transfer encoding errors. */
00032 #define STATUS_TRANSFER_ENCODING_ERR   602
00033 
00034 
00035 GeoIpResponse::GeoIpResponse(const QByteArray &response)
00036 {
00037   QString errmsg;
00038   
00039   /* Parse out the header */
00040   int headerPos = response.indexOf("\r\n\r\n");
00041   _header = QHttpResponseHeader(QString(response.mid(0, headerPos)));
00042 
00043   /* Parse out the Geo IP information, if any was included. */
00044   if (headerPos > 0 && _header.statusCode() == STATUS_HTTP_OK) {
00045     _content = response.mid(headerPos+4);
00046  
00047     if (_header.hasKey("Transfer-Encoding")) {
00048       QString encoding = _header.value("Transfer-Encoding");
00049       if (encoding == "chunked") {
00050         _content = decodeChunked(_content);
00051         if (_content.isEmpty()) {
00052           _header.setStatusLine(STATUS_TRANSFER_ENCODING_ERR,
00053             QString("Failed to decode chunked response"));
00054           return;
00055         }
00056       } else {
00057         _header.setStatusLine(STATUS_TRANSFER_ENCODING_ERR,
00058           QString("Unknown transfer encoding '%1'").arg(encoding));
00059         return;
00060       }
00061     }
00062  
00063     if (_header.hasKey("Content-Encoding")) {
00064       ZlibByteArray::CompressionMethod method;
00065       QString encoding = _header.value("Content-Encoding");
00066       if (encoding == "gzip" || encoding == "x-gzip") {
00067         method = ZlibByteArray::Gzip;
00068       } else if (encoding == "deflate" || encoding == "x-deflate") {
00069         method = ZlibByteArray::Zlib;
00070       } else if (encoding == "text/plain") {
00071         method = ZlibByteArray::None;
00072       } else {
00073         _header.setStatusLine(STATUS_CONTENT_ENCODING_ERR,
00074           QString("Unknown content encoding '%1'").arg(encoding));
00075         return;
00076       }
00077  
00078       _content = ZlibByteArray::uncompress(_content, method, &errmsg);
00079       if (_content.isEmpty()) {
00080         _header.setStatusLine(STATUS_CONTENT_ENCODING_ERR,
00081           QString("Content decoding using method '%1' failed: %2")
00082                                        .arg(encoding).arg(errmsg));
00083         return;
00084       }
00085     }
00086   }
00087 }
00088 
00089 QByteArray
00090 GeoIpResponse::decodeChunked(const QByteArray &chunked)
00091 {
00092   QByteArray unchunked;
00093   QString sizeString;
00094   int eol, chunkedlen, chunksize, offset = 0;
00095   bool ok;
00096  
00097   chunkedlen = chunked.length();
00098   while (offset < chunkedlen) {
00099     eol = chunked.indexOf("\r\n", offset);
00100     if (eol < 0)
00101       return QByteArray();
00102     sizeString = QString::fromAscii(chunked.mid(offset, eol-offset));
00103     offset = eol + 2; /* Skip past the CRLF */
00104     
00105     if (sizeString.indexOf(";") >= 0)
00106       sizeString.truncate(sizeString.indexOf(";")); 
00107     chunksize = sizeString.toInt(&ok, 16);
00108     if (!ok || chunksize > chunkedlen - offset)
00109       return QByteArray();
00110     if (!chunksize)
00111       break; /* Last chunk. Ignore the trailer. */
00112     
00113     unchunked.append(chunked.mid(offset, chunksize));
00114     offset += chunksize;
00115     offset += 2; /* CRLF after each chunk */
00116   }
00117   return unchunked;
00118 }
00119 
00120 int
00121 GeoIpResponse::statusCode() const
00122 {
00123   return _header.statusCode();
00124 }
00125 
00126 QString
00127 GeoIpResponse::statusMessage() const
00128 {
00129   return _header.reasonPhrase();
00130 }
00131 
00132 QByteArray
00133 GeoIpResponse::content() const
00134 {
00135   return _content;
00136 }
00137 
Generated on Mon Aug 30 23:09:49 2010 for Vidalia by  doxygen 1.6.3