diff --git a/src/tracker/qtracker.cpp b/src/tracker/qtracker.cpp index 6ce509bde..9de1abf8f 100644 --- a/src/tracker/qtracker.cpp +++ b/src/tracker/qtracker.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -86,27 +87,36 @@ void QTracker::readRequest() QTcpSocket *socket = static_cast(sender()); QByteArray input = socket->readAll(); //qDebug("QTracker: Raw request:\n%s", input.data()); - HttpRequestParser parser; - parser.write(input); - if(!parser.isValid()) { - qDebug("QTracker: Invalid HTTP Request:\n %s", qPrintable(parser.toString())); + QHttpRequestHeader http_request(input); + if(!http_request.isValid()) { + qDebug("QTracker: Invalid HTTP Request:\n %s", qPrintable(http_request.toString())); respondInvalidRequest(socket, 100, "Invalid request type"); return; } //qDebug("QTracker received the following request:\n%s", qPrintable(parser.toString())); // Request is correct, is it a GET request? - if(parser.method() != "GET") { - qDebug("QTracker: Unsupported HTTP request: %s", qPrintable(parser.method())); + if(http_request.method() != "GET") { + qDebug("QTracker: Unsupported HTTP request: %s", qPrintable(http_request.method())); respondInvalidRequest(socket, 100, "Invalid request type"); return; } - if(!parser.url().startsWith("/announce", Qt::CaseInsensitive)) { - qDebug("QTracker: Unrecognized path: %s", qPrintable(parser.url())); + if(!http_request.path().startsWith("/announce", Qt::CaseInsensitive)) { + qDebug("QTracker: Unrecognized path: %s", qPrintable(http_request.path())); respondInvalidRequest(socket, 100, "Invalid request type"); return; } + // OK, this is a GET request - respondToAnnounceRequest(socket, parser); + // Parse GET parameters + QHash get_parameters; + QUrl url = QUrl::fromEncoded(http_request.path().toAscii()); + QListIterator > i(url.queryItems()); + while (i.hasNext()) { + QPair pair = i.next(); + get_parameters[pair.first] = pair.second; + } + + respondToAnnounceRequest(socket, get_parameters); } void QTracker::respondInvalidRequest(QTcpSocket *socket, int code, QString msg) @@ -117,18 +127,19 @@ void QTracker::respondInvalidRequest(QTcpSocket *socket, int code, QString msg) socket->disconnectFromHost(); } -void QTracker::respondToAnnounceRequest(QTcpSocket *socket, const HttpRequestParser& parser) +void QTracker::respondToAnnounceRequest(QTcpSocket *socket, + const QHash& get_parameters) { TrackerAnnounceRequest annonce_req; // IP annonce_req.peer.ip = socket->peerAddress().toString(); // 1. Get info_hash - if(parser.get("info_hash").isNull()) { + if(!get_parameters.contains("info_hash")) { qDebug("QTracker: Missing info_hash"); respondInvalidRequest(socket, 101, "Missing info_hash"); return; } - annonce_req.info_hash = parser.get("info_hash"); + annonce_req.info_hash = get_parameters.value("info_hash"); // info_hash cannot be longer than 20 bytes /*if(annonce_req.info_hash.toAscii().length() > 20) { qDebug("QTracker: Info_hash is not 20 byte long: %s (%d)", qPrintable(annonce_req.info_hash), annonce_req.info_hash.toAscii().length()); @@ -136,12 +147,12 @@ void QTracker::respondToAnnounceRequest(QTcpSocket *socket, const HttpRequestPar return; }*/ // 2. Get peer ID - if(parser.get("peer_id").isNull()) { + if(!get_parameters.contains("peer_id")) { qDebug("QTracker: Missing peer_id"); respondInvalidRequest(socket, 102, "Missing peer_id"); return; } - annonce_req.peer.peer_id = parser.get("peer_id"); + annonce_req.peer.peer_id = get_parameters.value("peer_id"); // peer_id cannot be longer than 20 bytes /*if(annonce_req.peer.peer_id.length() > 20) { qDebug("QTracker: peer_id is not 20 byte long: %s", qPrintable(annonce_req.peer.peer_id)); @@ -149,13 +160,13 @@ void QTracker::respondToAnnounceRequest(QTcpSocket *socket, const HttpRequestPar return; }*/ // 3. Get port - if(parser.get("port").isNull()) { + if(!get_parameters.contains("port")) { qDebug("QTracker: Missing port"); respondInvalidRequest(socket, 103, "Missing port"); return; } bool ok = false; - annonce_req.peer.port = parser.get("port").toInt(&ok); + annonce_req.peer.port = get_parameters.value("port").toInt(&ok); if(!ok || annonce_req.peer.port < 1 || annonce_req.peer.port > 65535) { qDebug("QTracker: Invalid port number (%d)", annonce_req.peer.port); respondInvalidRequest(socket, 103, "Missing port"); @@ -163,14 +174,14 @@ void QTracker::respondToAnnounceRequest(QTcpSocket *socket, const HttpRequestPar } // 4. Get event annonce_req.event = ""; - if(!parser.get("event").isNull()) { - annonce_req.event = parser.get("event"); + if(get_parameters.contains("event")) { + annonce_req.event = get_parameters.value("event"); qDebug("QTracker: event is %s", qPrintable(annonce_req.event)); } // 5. Get numwant annonce_req.numwant = 50; - if(!parser.get("numwant").isNull()) { - int tmp = parser.get("numwant").toInt(); + if(get_parameters.contains("numwant")) { + int tmp = get_parameters.value("numwant").toInt(); if(tmp > 0) { qDebug("QTracker: numwant=%d", tmp); annonce_req.numwant = tmp; @@ -178,7 +189,7 @@ void QTracker::respondToAnnounceRequest(QTcpSocket *socket, const HttpRequestPar } // 6. no_peer_id (extension) annonce_req.no_peer_id = false; - if(parser.hasKey("no_peer_id")) { + if(get_parameters.contains("no_peer_id")) { annonce_req.no_peer_id = true; } // 7. TODO: support "compact" extension diff --git a/src/tracker/qtracker.h b/src/tracker/qtracker.h index 7fa0d5bd6..731f89666 100644 --- a/src/tracker/qtracker.h +++ b/src/tracker/qtracker.h @@ -35,7 +35,6 @@ #include #include -#include "httprequestparser.h" #include "trackerannouncerequest.h" #include "qpeer.h" @@ -63,7 +62,7 @@ protected slots: void readRequest(); void handlePeerConnection(); void respondInvalidRequest(QTcpSocket *socket, int code, QString msg); - void respondToAnnounceRequest(QTcpSocket *socket, const HttpRequestParser& parser); + void respondToAnnounceRequest(QTcpSocket *socket, const QHash& get_parameters); void ReplyWithPeerList(QTcpSocket *socket, const TrackerAnnounceRequest &annonce_req); private: diff --git a/src/webui/httpconnection.cpp b/src/webui/httpconnection.cpp index 26f2f209b..e5ac1e056 100644 --- a/src/webui/httpconnection.cpp +++ b/src/webui/httpconnection.cpp @@ -91,7 +91,7 @@ void HttpConnection::read() { m_generator.setStatusLine(400, "Bad Request"); write(); } else { - if (m_parser.isParsable()) + if (!m_parser.isError()) respond(); } } @@ -129,7 +129,6 @@ void HttpConnection::translateDocument(QString& data) { ++context_index; } while(translation == word && context_index < 15); } - // Remove keyboard shortcuts translation.replace(mnemonic, ""); @@ -153,7 +152,7 @@ void HttpConnection::respond() { write(); return; } - QString auth = m_parser.value("Authorization"); + QString auth = m_parser.header().value("Authorization"); if(auth.isEmpty()) { // Return unauthorized header qDebug("Auth is Empty..."); @@ -164,7 +163,7 @@ void HttpConnection::respond() { } //qDebug("Auth: %s", qPrintable(auth.split(" ").first())); if (QString::compare(auth.split(" ").first(), "Digest", Qt::CaseInsensitive) != 0 - || !m_httpserver->isAuthorized(auth.toLocal8Bit(), m_parser.method())) { + || !m_httpserver->isAuthorized(auth.toLocal8Bit(), m_parser.header().method())) { // Update failed attempt counter m_httpserver->increaseNbFailedAttemptsForIp(peer_ip); qDebug("client IP: %s (%d failed attempts)", qPrintable(peer_ip), nb_fail); @@ -567,19 +566,16 @@ void HttpConnection::respondCommand(const QString& command) { return; } if(command == "recheck"){ - recheckTorrent(m_parser.post("hash")); + QBtSession::instance()->recheckTorrent(m_parser.post("hash")); return; } } -void HttpConnection::recheckTorrent(const QString& hash) { - QBtSession::instance()->recheckTorrent(hash); -} - -void HttpConnection::decreaseTorrentsPriority(const QStringList &hashes) -{ +void HttpConnection::decreaseTorrentsPriority(const QStringList &hashes) { qDebug() << Q_FUNC_INFO << hashes; - std::priority_queue, std::vector >, std::less > > torrent_queue; + std::priority_queue, + std::vector >, + std::less > > torrent_queue; // Sort torrents by priority foreach(const QString &hash, hashes) { try { @@ -602,7 +598,9 @@ void HttpConnection::decreaseTorrentsPriority(const QStringList &hashes) void HttpConnection::increaseTorrentsPriority(const QStringList &hashes) { qDebug() << Q_FUNC_INFO << hashes; - std::priority_queue, std::vector >, std::greater > > torrent_queue; + std::priority_queue, + std::vector >, + std::greater > > torrent_queue; // Sort torrents by priority foreach(const QString &hash, hashes) { try { diff --git a/src/webui/httpconnection.h b/src/webui/httpconnection.h index 2eedc9cc0..e7a09ab4d 100644 --- a/src/webui/httpconnection.h +++ b/src/webui/httpconnection.h @@ -65,7 +65,6 @@ protected slots: void respondNotFound(); void processDownloadedFile(const QString& url, const QString& file_path); void handleDownloadFailure(const QString& url, const QString& reason); - void recheckTorrent(const QString& hash); void decreaseTorrentsPriority(const QStringList& hashes); void increaseTorrentsPriority(const QStringList& hashes); diff --git a/src/webui/httprequestparser.cpp b/src/webui/httprequestparser.cpp index 90a2edece..055130abd 100644 --- a/src/webui/httprequestparser.cpp +++ b/src/webui/httprequestparser.cpp @@ -33,8 +33,7 @@ #include #include -HttpRequestParser::HttpRequestParser(): m_headerDone(false), - m_messageDone(false), m_error(false) +HttpRequestParser::HttpRequestParser(): m_error(false) { } @@ -42,11 +41,6 @@ HttpRequestParser::~HttpRequestParser() { } -bool HttpRequestParser::isParsable() const { - return !m_error && m_headerDone && isValid() - && (m_messageDone || !hasContentLength() || contentLength() == 0); -} - bool HttpRequestParser::isError() const { return m_error; } @@ -56,71 +50,59 @@ QString HttpRequestParser::url() const { } QByteArray HttpRequestParser::message() const { - if (isParsable()) - return m_data; - return QByteArray(); + return m_data; } QString HttpRequestParser::get(const QString& key) const { - return m_getMap.value(key); + return m_getMap.value(key); } QString HttpRequestParser::post(const QString& key) const { - return m_postMap.value(key); + return m_postMap.value(key); } QByteArray HttpRequestParser::torrent() const { return m_torrentContent; } -void HttpRequestParser::write(QByteArray ba) { +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; + } + // Parse header - while (!m_headerDone && !ba.isEmpty()) { - const int index = ba.indexOf('\n') + 1; - if(index == 0) { - m_data += ba; - ba.clear(); - } else { - m_data += ba.left(index); - ba.remove(0, index); - if(m_data.right(4) == "\r\n\r\n") { - QHttpRequestHeader::operator=(QHttpRequestHeader(m_data)); - m_headerDone = true; - m_data.clear(); - QUrl url = QUrl::fromEncoded(QHttpRequestHeader::path().toAscii()); - m_path = url.path(); + m_header = QHttpRequestHeader(ba.left(end_of_header)); + QUrl url = QUrl::fromEncoded(m_header.path().toAscii()); + m_path = url.path(); - QListIterator > i(url.queryItems()); - while (i.hasNext()) { - QPair pair = i.next(); - m_getMap[pair.first] = pair.second; - } - } - } - } - // Parse message - if(!m_messageDone && !ba.isEmpty()) { - if(hasContentLength()) { - m_data += ba; - if(m_data.size() >= (int) contentLength()) { - m_data.resize(contentLength()); - m_messageDone = true; - //parse POST data - if(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; - } - } - if(contentType() == "multipart/form-data") { - m_torrentContent = m_data.right(m_data.size()-m_data.indexOf("\r\n\r\n")-QByteArray("\r\n\r\n").size()); - } - } - } else { - m_error = true; + // Parse GET parameters + QListIterator > i(url.queryItems()); + while (i.hasNext()) { + QPair pair = i.next(); + m_getMap[pair.first] = pair.second; + } + + // Parse message content + if (m_header.hasContentLength()) { + m_data = ba.mid(end_of_header + 4, m_header.contentLength()); // +4 to skip "\r\n\r\n" + + // 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) + if(m_header.contentType() == "multipart/form-data") { + m_torrentContent = m_data.right(m_data.size()-m_data.indexOf("\r\n\r\n")-QByteArray("\r\n\r\n").size()); + } } } } diff --git a/src/webui/httprequestparser.h b/src/webui/httprequestparser.h index b26d4c4bd..5f8071794 100644 --- a/src/webui/httprequestparser.h +++ b/src/webui/httprequestparser.h @@ -34,23 +34,22 @@ #include -class HttpRequestParser : public QHttpRequestHeader { +class HttpRequestParser { public: HttpRequestParser(); ~HttpRequestParser(); - bool isParsable() const; bool isError() const; QString url() const; QByteArray message() const; QString get(const QString& key) const; QString post(const QString& key) const; QByteArray torrent() const; - void write(QByteArray ba); + void write(const QByteArray& ba); + inline QHttpRequestHeader& header() { return m_header; } private: - bool m_headerDone; - bool m_messageDone; + QHttpRequestHeader m_header; bool m_error; QByteArray m_data; QString m_path;