Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
multipart reply extracted from WCS provider QgsNetworkReplyParser
- Loading branch information
Showing
4 changed files
with
247 additions
and
84 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
/*************************************************************************** | ||
qgsnetworkreplyparser.cpp - Multipart QNetworkReply parser | ||
------------------- | ||
begin : 4 January, 2013 | ||
copyright : (C) 2013 by Radim Blazek | ||
email : radim dot blazek at gmail.com | ||
***************************************************************************/ | ||
|
||
/*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "qgslogger.h" | ||
#include "qgsnetworkreplyparser.h" | ||
|
||
#include <QNetworkReply> | ||
#include <QObject> | ||
#include <QRegExp> | ||
#include <QString> | ||
#include <QStringList> | ||
|
||
QgsNetworkReplyParser::QgsNetworkReplyParser( QNetworkReply *reply ) | ||
: mReply(reply) | ||
, mValid(false) | ||
{ | ||
if ( !mReply ) return; | ||
|
||
// Content type examples: | ||
// multipart/mixed; boundary=wcs | ||
// multipart/mixed; boundary="wcs"\n | ||
if ( !isMultipart( mReply ) ) | ||
{ | ||
// reply is not multipart, copy body and headers | ||
QMap<QByteArray,QByteArray> headers; | ||
foreach ( QByteArray h, mReply->rawHeaderList() ) | ||
{ | ||
headers.insert( h, mReply->rawHeader( h ) ); | ||
} | ||
mHeaders.append( headers ); | ||
mBodies.append( mReply->readAll() ); | ||
} | ||
else // multipart | ||
{ | ||
QString contentType = mReply->header( QNetworkRequest::ContentTypeHeader ).toString(); | ||
QgsDebugMsg( "contentType: " + contentType ); | ||
|
||
QRegExp re( ".*boundary=\"?([^\"]+)\"?\\s?", Qt::CaseInsensitive ); | ||
|
||
if ( !re.indexIn( contentType ) == 0 ) | ||
{ | ||
mError = tr( "Cannot find boundary in multipart content type" ); | ||
return; | ||
} | ||
|
||
QString boundary = re.cap( 1 ); | ||
QgsDebugMsg( "boundary = " + boundary ); | ||
boundary = "--" + boundary; | ||
|
||
// Lines should be terminated by CRLF ("\r\n") but any new line combination may appear | ||
QByteArray data = mReply->readAll(); | ||
int from, to; | ||
from = data.indexOf( boundary.toAscii(), 0 ) + boundary.length() + 1 ; | ||
//QVector<QByteArray> partHeaders; | ||
//QVector<QByteArray> partBodies; | ||
while ( true ) | ||
{ | ||
to = data.indexOf( boundary.toAscii(), from ); | ||
if ( to < 0 ) | ||
{ | ||
// It may happent that bondary is missing at the end (GeoServer) | ||
// in that case, take everything to th end | ||
if ( data.size() - from > 1 ) | ||
{ | ||
to = data.size(); // out of range OK | ||
} | ||
else | ||
{ | ||
break; | ||
} | ||
} | ||
QgsDebugMsg( QString( "part %1 - %2" ).arg( from ).arg( to ) ); | ||
QByteArray part = data.mid( from, to - from ); | ||
// Remove possible new line from beginning | ||
while ( part.size() > 0 && ( part.at( 0 ) == '\r' || part.at( 0 ) == '\n' ) ) | ||
{ | ||
part.remove( 0, 1 ); | ||
} | ||
// Split header and data (find empty new line) | ||
// New lines should be CRLF, but we support also CRLFCRLF, LFLF to find empty line | ||
int pos = 0; // body start | ||
while ( pos < part.size() - 1 ) | ||
{ | ||
if ( part.at( pos ) == '\n' && ( part.at( pos + 1 ) == '\n' || part.at( pos + 1 ) == '\r' ) ) | ||
{ | ||
if ( part.at( pos + 1 ) == '\r' ) pos++; | ||
pos += 2; | ||
break; | ||
} | ||
pos++; | ||
} | ||
// parse headers | ||
QMap<QByteArray,QByteArray> headersMap; | ||
QByteArray headers = part.left( pos ); | ||
QgsDebugMsg( "headers:\n" + headers ); | ||
|
||
QStringList headerRows = QString( headers ).split( QRegExp( "[\n\r]+" ) ); | ||
foreach ( QString row, headerRows ) | ||
{ | ||
QgsDebugMsg( "row = " + row ); | ||
QStringList kv = row.split( ": " ); | ||
headersMap.insert( kv.value( 0 ).toAscii(), kv.value( 1 ).toAscii() ); | ||
} | ||
mHeaders.append( headersMap ); | ||
|
||
mBodies.append( part.mid( pos ) ); | ||
|
||
from = to + boundary.length() + 1; | ||
} | ||
} | ||
mValid = true; | ||
} | ||
|
||
bool QgsNetworkReplyParser::isMultipart( QNetworkReply *reply ) | ||
{ | ||
if ( !reply ) return false; | ||
|
||
QString contentType = reply->header( QNetworkRequest::ContentTypeHeader ).toString(); | ||
QgsDebugMsg( "contentType: " + contentType ); | ||
|
||
// Multipart content type examples: | ||
// multipart/mixed; boundary=wcs | ||
// multipart/mixed; boundary="wcs"\n | ||
if ( contentType.startsWith( "multipart/", Qt::CaseInsensitive ) ) | ||
{ | ||
return true; | ||
} | ||
return false; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/*************************************************************************** | ||
qgsnetworkreplyparser.h - Multipart QNetworkReply parser | ||
------------------- | ||
begin : 4 January, 2013 | ||
copyright : (C) 2013 by Radim Blazek | ||
email : radim dot blazek at gmail.com | ||
***************************************************************************/ | ||
|
||
/*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#ifndef QGSNETWORKREPLYPARSER_H | ||
#define QGSNETWORKREPLYPARSER_H | ||
|
||
#include <QNetworkReply> | ||
|
||
/** | ||
\brief Multipart QNetworkReply parser. | ||
It seams that Qt does not have currently support for multipart reply | ||
and it is not even possible to create QNetworkReply from raw data | ||
so we need a class for multipart QNetworkReply parsing. | ||
*/ | ||
|
||
class CORE_EXPORT QgsNetworkReplyParser : public QObject | ||
{ | ||
Q_OBJECT | ||
|
||
public: | ||
/** Constructor | ||
* @param reply */ | ||
QgsNetworkReplyParser( QNetworkReply *reply ); | ||
|
||
/** Indicates if successfully parsed | ||
* @return true if successfully parsed */ | ||
bool isValid() const { return mValid; } | ||
|
||
/** Get number of parts | ||
* @return number of parts */ | ||
int parts() const { return mHeaders.size(); } | ||
|
||
/** Get part header | ||
* @param part part index | ||
* @return raw header */ | ||
QByteArray rawHeader ( int part, const QByteArray & headerName ) const { return mHeaders.value(part).value(headerName); } | ||
|
||
/** Get part part body | ||
* @param part part index | ||
* @return part body */ | ||
QByteArray body ( int part ) const { return mBodies.value(part); } | ||
|
||
/** Parsing error */ | ||
QString error() const { return mError; } | ||
|
||
/** Test if reply is multipart. | ||
* @return true if reply is multipart */ | ||
static bool isMultipart ( QNetworkReply *reply ); | ||
|
||
private: | ||
QNetworkReply *mReply; | ||
|
||
bool mValid; | ||
|
||
QString mError; | ||
|
||
/* List of header maps */ | ||
QList< QMap<QByteArray,QByteArray> > mHeaders; | ||
|
||
/* List of part bodies */ | ||
QList<QByteArray> mBodies; | ||
}; | ||
|
||
#endif |
Oops, something went wrong.