From eeda9379d55b646ee513b9f9eaedc8f4ff4110ea Mon Sep 17 00:00:00 2001 From: Christophe Dumez Date: Sat, 1 Oct 2011 23:30:33 +0300 Subject: [PATCH] HTTP server: Greatly improved HTTP request parsing --- src/webui/httpconnection.cpp | 41 ++++++++++++------ src/webui/httprequestparser.cpp | 75 +++++++++++++++------------------ src/webui/httprequestparser.h | 3 +- 3 files changed, 64 insertions(+), 55 deletions(-) diff --git a/src/webui/httpconnection.cpp b/src/webui/httpconnection.cpp index d7744e666..34757b409 100644 --- a/src/webui/httpconnection.cpp +++ b/src/webui/httpconnection.cpp @@ -78,26 +78,41 @@ void HttpConnection::handleDownloadFailure(const QString& url, } void HttpConnection::read() { - static QByteArray input; + QByteArray input = m_socket->readAll(); - input.append(m_socket->readAll()); - if(input.size() > 100000) { - qDebug("Request too big"); - input.clear(); + // Parse HTTP request header + int header_end = input.indexOf("\r\n\r\n"); + QByteArray header = input.left(header_end); + m_parser.writeHeader(header); + if (m_parser.isError()) { + qDebug() << Q_FUNC_INFO << "parsing error"; m_generator.setStatusLine(400, "Bad Request"); write(); return; } - if (!input.endsWith("\r\n")) { - // incomplete, let wait for more data - qDebug() << Q_FUNC_INFO << "Incomplete HTTP request, let's wait for more data..."; - return; - } + // Parse HTTP request message + if (m_parser.header().hasContentLength()) { + QByteArray message = input.mid(header_end + 4); + int expected_length = m_parser.header().contentLength(); - // HTTP Request is complete, let's parse it - m_parser.write(input); - input.clear(); + if (expected_length > 100000) { + m_generator.setStatusLine(400, "Bad Request"); + write(); + return; + } + + bool is_reading = true; + while (message.length() < expected_length && is_reading) { + disconnect(m_socket, SIGNAL(readyRead()), this, SLOT(read())); + is_reading = m_socket->waitForReadyRead(2000); + if (is_reading) { + message.append(m_socket->readAll()); + } + connect(m_socket, SIGNAL(readyRead()), this, SLOT(read())); + } + m_parser.writeMessage(message); + } if(m_parser.isError()) { qDebug() << Q_FUNC_INFO << "parsing error"; diff --git a/src/webui/httprequestparser.cpp b/src/webui/httprequestparser.cpp index 829d40680..5177a5c01 100644 --- a/src/webui/httprequestparser.cpp +++ b/src/webui/httprequestparser.cpp @@ -65,16 +65,9 @@ const QByteArray& HttpRequestParser::torrent() const { return m_torrentContent; } -void HttpRequestParser::write(const QByteArray& ba) { - int end_of_header = ba.indexOf("\r\n\r\n"); - if (end_of_header < 0) { - qWarning() << "Could not find HTTP header: " << ba.constData(); - m_error = true; - return; - } - +void HttpRequestParser::writeHeader(const QByteArray& ba) { // Parse header - m_header = QHttpRequestHeader(ba.left(end_of_header)); + m_header = QHttpRequestHeader(ba); QUrl url = QUrl::fromEncoded(m_header.path().toAscii()); m_path = url.path(); @@ -84,26 +77,27 @@ void HttpRequestParser::write(const QByteArray& ba) { QPair pair = i.next(); m_getMap[pair.first] = pair.second; } +} +void HttpRequestParser::writeMessage(const QByteArray& ba) { // Parse message content - if (m_header.hasContentLength()) { - qDebug() << Q_FUNC_INFO << "ba.size(): " << ba.size(); - qDebug() << Q_FUNC_INFO << "\n\n" << "header: " << ba.left(end_of_header) << "\n\n"; - m_data = ba.mid(end_of_header + 4, m_header.contentLength()); // +4 to skip "\r\n\r\n" - qDebug() << "m_data.size(): " << m_data.size(); + Q_ASSERT (m_header.hasContentLength()); - // Parse POST data - if(m_header.contentType() == "application/x-www-form-urlencoded") { - QUrl url; - url.setEncodedQuery(m_data); - QListIterator > i(url.queryItems()); - while (i.hasNext()) { - QPair pair = i.next(); - m_postMap[pair.first] = pair.second; - } - } else { - // Parse form data (torrent file) - /** + m_data = ba; + qDebug() << "m_data.size(): " << m_data.size(); + + // Parse POST data + if(m_header.contentType() == "application/x-www-form-urlencoded") { + QUrl url; + url.setEncodedQuery(m_data); + QListIterator > i(url.queryItems()); + while (i.hasNext()) { + QPair pair = i.next(); + m_postMap[pair.first] = pair.second; + } + } else { + // Parse form data (torrent file) + /** m_data has the following format (if boundary is "cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5") --cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5 @@ -121,22 +115,21 @@ Content-Disposition: form-data; name=\"Upload\" Submit Query --cH2ae0GI3KM7GI3Ij5ae0ei4Ij5Ij5-- **/ - if (m_header.contentType().startsWith("multipart/form-data")) { - int filename_index = m_data.indexOf("filename="); - if (filename_index >= 0) { - QByteArray boundary = m_data.left(m_data.indexOf("\r\n")); - qDebug() << "Boundary is " << boundary << "\n\n"; - qDebug() << "Before binary data: " << m_data.left(m_data.indexOf("\r\n\r\n", filename_index+9)) << "\n\n"; - m_torrentContent = m_data.mid(m_data.indexOf("\r\n\r\n", filename_index+9) + 4); - int binaryend_index = m_torrentContent.indexOf("\r\n"+boundary); - if (binaryend_index >= 0) { - qDebug() << "found end boundary :)"; - m_torrentContent = m_torrentContent.left(binaryend_index); - } - qDebug() << Q_FUNC_INFO << "m_torrentContent.size(): " << m_torrentContent.size()<< "\n\n"; - } else { - m_error = true; + if (m_header.contentType().startsWith("multipart/form-data")) { + int filename_index = m_data.indexOf("filename="); + if (filename_index >= 0) { + QByteArray boundary = m_data.left(m_data.indexOf("\r\n")); + qDebug() << "Boundary is " << boundary << "\n\n"; + qDebug() << "Before binary data: " << m_data.left(m_data.indexOf("\r\n\r\n", filename_index+9)) << "\n\n"; + m_torrentContent = m_data.mid(m_data.indexOf("\r\n\r\n", filename_index+9) + 4); + int binaryend_index = m_torrentContent.indexOf("\r\n"+boundary); + if (binaryend_index >= 0) { + qDebug() << "found end boundary :)"; + m_torrentContent = m_torrentContent.left(binaryend_index); } + qDebug() << Q_FUNC_INFO << "m_torrentContent.size(): " << m_torrentContent.size()<< "\n\n"; + } else { + m_error = true; } } } diff --git a/src/webui/httprequestparser.h b/src/webui/httprequestparser.h index e5fc03891..39f9be1e9 100644 --- a/src/webui/httprequestparser.h +++ b/src/webui/httprequestparser.h @@ -45,7 +45,8 @@ public: QString get(const QString& key) const; QString post(const QString& key) const; const QByteArray& torrent() const; - void write(const QByteArray& ba); + void writeHeader(const QByteArray& ba); + void writeMessage(const QByteArray& ba); inline QHttpRequestHeader& header() { return m_header; } private: