|
QGIS API Documentation
master-59fd5e0
|
00001 /*************************************************************************** 00002 qgsnetworkreplyparser.cpp - Multipart QNetworkReply parser 00003 ------------------- 00004 begin : 4 January, 2013 00005 copyright : (C) 2013 by Radim Blazek 00006 email : radim dot blazek at gmail.com 00007 00008 ***************************************************************************/ 00009 00010 /*************************************************************************** 00011 * * 00012 * This program is free software; you can redistribute it and/or modify * 00013 * it under the terms of the GNU General Public License as published by * 00014 * the Free Software Foundation; either version 2 of the License, or * 00015 * (at your option) any later version. * 00016 * * 00017 ***************************************************************************/ 00018 00019 #include "qgslogger.h" 00020 #include "qgsnetworkreplyparser.h" 00021 00022 #include <QNetworkReply> 00023 #include <QObject> 00024 #include <QRegExp> 00025 #include <QString> 00026 #include <QStringList> 00027 00028 QgsNetworkReplyParser::QgsNetworkReplyParser( QNetworkReply *reply ) 00029 : mReply( reply ) 00030 , mValid( false ) 00031 { 00032 QgsDebugMsg( "Entered." ); 00033 if ( !mReply ) return; 00034 00035 // Content type examples: 00036 // multipart/mixed; boundary=wcs 00037 // multipart/mixed; boundary="wcs"\n 00038 if ( !isMultipart( mReply ) ) 00039 { 00040 // reply is not multipart, copy body and headers 00041 QMap<QByteArray, QByteArray> headers; 00042 foreach ( QByteArray h, mReply->rawHeaderList() ) 00043 { 00044 headers.insert( h, mReply->rawHeader( h ) ); 00045 } 00046 mHeaders.append( headers ); 00047 mBodies.append( mReply->readAll() ); 00048 } 00049 else // multipart 00050 { 00051 QString contentType = mReply->header( QNetworkRequest::ContentTypeHeader ).toString(); 00052 QgsDebugMsg( "contentType: " + contentType ); 00053 00054 QRegExp re( ".*boundary=\"?([^\"]+)\"?\\s?", Qt::CaseInsensitive ); 00055 00056 if ( !re.indexIn( contentType ) == 0 ) 00057 { 00058 mError = tr( "Cannot find boundary in multipart content type" ); 00059 return; 00060 } 00061 00062 QString boundary = re.cap( 1 ); 00063 QgsDebugMsg( QString( "boundary = %1 size = %2" ).arg( boundary ).arg( boundary.size() ) ); 00064 boundary = "--" + boundary; 00065 00066 // Lines should be terminated by CRLF ("\r\n") but any new line combination may appear 00067 QByteArray data = mReply->readAll(); 00068 int from, to; 00069 from = data.indexOf( boundary.toAscii(), 0 ) + boundary.length() + 1 ; 00070 //QVector<QByteArray> partHeaders; 00071 //QVector<QByteArray> partBodies; 00072 while ( true ) 00073 { 00074 // 'to' is not really 'to', but index of the next byte after the end of part 00075 to = data.indexOf( boundary.toAscii(), from ); 00076 if ( to < 0 ) 00077 { 00078 QgsDebugMsg( QString( "No more boundaries, rest size = %1" ).arg( data.size() - from - 1 ) ); 00079 // It may be end, last boundary is followed by '--' 00080 if ( data.size() - from - 1 == 2 && QString( data.mid( from, 2 ) ) == "--" ) // end 00081 { 00082 break; 00083 } 00084 00085 // It may happen that boundary is missing at the end (GeoServer) 00086 // in that case, take everything to the end 00087 if ( data.size() - from > 1 ) 00088 { 00089 to = data.size(); // out of range OK 00090 } 00091 else 00092 { 00093 break; 00094 } 00095 } 00096 QgsDebugMsg( QString( "part %1 - %2" ).arg( from ).arg( to ) ); 00097 QByteArray part = data.mid( from, to - from ); 00098 // Remove possible new line from beginning 00099 while ( part.size() > 0 && ( part.at( 0 ) == '\r' || part.at( 0 ) == '\n' ) ) 00100 { 00101 part.remove( 0, 1 ); 00102 } 00103 // Split header and data (find empty new line) 00104 // New lines should be CRLF, but we support also CRLFCRLF, LFLF to find empty line 00105 int pos = 0; // body start 00106 while ( pos < part.size() - 1 ) 00107 { 00108 if ( part.at( pos ) == '\n' && ( part.at( pos + 1 ) == '\n' || part.at( pos + 1 ) == '\r' ) ) 00109 { 00110 if ( part.at( pos + 1 ) == '\r' ) pos++; 00111 pos += 2; 00112 break; 00113 } 00114 pos++; 00115 } 00116 // parse headers 00117 RawHeaderMap headersMap; 00118 QByteArray headers = part.left( pos ); 00119 QgsDebugMsg( "headers:\n" + headers ); 00120 00121 QStringList headerRows = QString( headers ).split( QRegExp( "[\n\r]+" ) ); 00122 foreach ( QString row, headerRows ) 00123 { 00124 QgsDebugMsg( "row = " + row ); 00125 QStringList kv = row.split( ": " ); 00126 headersMap.insert( kv.value( 0 ).toAscii(), kv.value( 1 ).toAscii() ); 00127 } 00128 mHeaders.append( headersMap ); 00129 00130 mBodies.append( part.mid( pos ) ); 00131 00132 from = to + boundary.length(); 00133 } 00134 } 00135 mValid = true; 00136 } 00137 00138 bool QgsNetworkReplyParser::isMultipart( QNetworkReply *reply ) 00139 { 00140 if ( !reply ) return false; 00141 00142 QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString(); 00143 QgsDebugMsg( "contentType: " + contentType ); 00144 00145 // Multipart content type examples: 00146 // multipart/mixed; boundary=wcs 00147 // multipart/mixed; boundary="wcs"\n 00148 return contentType.startsWith( "multipart/", Qt::CaseInsensitive ); 00149 }