| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  | /**
 | 
					
						
							|  |  |  |   @file | 
					
						
							|  |  |  |   @author Stefan Frings | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "httprequest.h"
 | 
					
						
							| 
									
										
										
										
											2017-11-13 01:26:48 +01:00
										 |  |  | #include "httplistenersettings.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  | #include <QList>
 | 
					
						
							|  |  |  | #include <QDir>
 | 
					
						
							|  |  |  | #include "httpcookie.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-11 09:32:15 +01:00
										 |  |  | using namespace qtwebapp; | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-17 08:52:15 +01:00
										 |  |  | HttpRequest::HttpRequest(QSettings* settings) : | 
					
						
							|  |  |  |         useQtSettings(true) | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-11-18 10:15:29 +01:00
										 |  |  |     Q_ASSERT(settings != 0); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |     status=waitForRequest; | 
					
						
							|  |  |  |     currentSize=0; | 
					
						
							|  |  |  |     expectedBodySize=0; | 
					
						
							|  |  |  |     maxSize=settings->value("maxRequestSize","16000").toInt(); | 
					
						
							|  |  |  |     maxMultiPartSize=settings->value("maxMultiPartSize","1000000").toInt(); | 
					
						
							| 
									
										
										
										
											2017-11-13 13:46:02 +01:00
										 |  |  |     tempFile=0; | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-18 10:15:29 +01:00
										 |  |  | HttpRequest::HttpRequest(const HttpListenerSettings* settings) : | 
					
						
							| 
									
										
										
										
											2017-11-17 08:52:15 +01:00
										 |  |  |         useQtSettings(false) | 
					
						
							| 
									
										
										
										
											2017-11-13 01:26:48 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2017-11-18 10:15:29 +01:00
										 |  |  |     Q_ASSERT(settings != 0); | 
					
						
							| 
									
										
										
										
											2017-11-13 01:26:48 +01:00
										 |  |  |     status=waitForRequest; | 
					
						
							|  |  |  |     currentSize=0; | 
					
						
							|  |  |  |     expectedBodySize=0; | 
					
						
							| 
									
										
										
										
											2017-11-18 10:15:29 +01:00
										 |  |  |     maxSize=settings->maxRequestSize; | 
					
						
							|  |  |  |     maxMultiPartSize=settings->maxMultiPartSize; | 
					
						
							| 
									
										
										
										
											2017-11-13 13:46:02 +01:00
										 |  |  |     tempFile=0; | 
					
						
							| 
									
										
										
										
											2017-11-13 01:26:48 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | void HttpRequest::readRequest(QTcpSocket* socket) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |         qDebug("HttpRequest::readRequest: read request"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |     #endif
 | 
					
						
							|  |  |  |     int toRead=maxSize-currentSize+1; // allow one byte more to be able to detect overflow
 | 
					
						
							|  |  |  |     lineBuffer.append(socket->readLine(toRead)); | 
					
						
							|  |  |  |     currentSize+=lineBuffer.size(); | 
					
						
							|  |  |  |     if (!lineBuffer.contains('\r') && !lineBuffer.contains('\n')) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |             qDebug("HttpRequest::readRequest: collecting more parts until line break"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |         #endif
 | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     QByteArray newData=lineBuffer.trimmed(); | 
					
						
							|  |  |  |     lineBuffer.clear(); | 
					
						
							|  |  |  |     if (!newData.isEmpty()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QList<QByteArray> list=newData.split(' '); | 
					
						
							|  |  |  |         if (list.count()!=3 || !list.at(2).contains("HTTP")) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |             qWarning("HttpRequest::readRequest: received broken HTTP request, invalid first line"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |             status=abort; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             method=list.at(0).trimmed(); | 
					
						
							|  |  |  |             path=list.at(1); | 
					
						
							|  |  |  |             version=list.at(2); | 
					
						
							|  |  |  |             peerAddress = socket->peerAddress(); | 
					
						
							|  |  |  |             status=waitForHeader; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void HttpRequest::readHeader(QTcpSocket* socket) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |         qDebug("HttpRequest::readHeader"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |     #endif
 | 
					
						
							|  |  |  |     int toRead=maxSize-currentSize+1; // allow one byte more to be able to detect overflow
 | 
					
						
							|  |  |  |     lineBuffer.append(socket->readLine(toRead)); | 
					
						
							|  |  |  |     currentSize+=lineBuffer.size(); | 
					
						
							|  |  |  |     if (!lineBuffer.contains('\r') && !lineBuffer.contains('\n')) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |             qDebug("HttpRequest::readHeader: collecting more parts until line break"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |         #endif
 | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     QByteArray newData=lineBuffer.trimmed(); | 
					
						
							|  |  |  |     lineBuffer.clear(); | 
					
						
							|  |  |  |     int colon=newData.indexOf(':'); | 
					
						
							|  |  |  |     if (colon>0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Received a line with a colon - a header
 | 
					
						
							|  |  |  |         currentHeader=newData.left(colon).toLower(); | 
					
						
							|  |  |  |         QByteArray value=newData.mid(colon+1).trimmed(); | 
					
						
							|  |  |  |         headers.insert(currentHeader,value); | 
					
						
							|  |  |  |         #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |             qDebug("HttpRequest::readHeader: received header %s: %s",currentHeader.data(),value.data()); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |         #endif
 | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (!newData.isEmpty()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // received another line - belongs to the previous header
 | 
					
						
							|  |  |  |         #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |             qDebug("HttpRequest::readHeader: read additional line of header"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |         #endif
 | 
					
						
							|  |  |  |         // Received additional line of previous header
 | 
					
						
							|  |  |  |         if (headers.contains(currentHeader)) { | 
					
						
							|  |  |  |             headers.insert(currentHeader,headers.value(currentHeader)+" "+newData); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // received an empty line - end of headers reached
 | 
					
						
							|  |  |  |         #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |             qDebug("HttpRequest::readHeader: headers completed"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |         #endif
 | 
					
						
							|  |  |  |         // Empty line received, that means all headers have been received
 | 
					
						
							|  |  |  |         // Check for multipart/form-data
 | 
					
						
							|  |  |  |         QByteArray contentType=headers.value("content-type"); | 
					
						
							|  |  |  |         if (contentType.startsWith("multipart/form-data")) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             int posi=contentType.indexOf("boundary="); | 
					
						
							|  |  |  |             if (posi>=0) { | 
					
						
							|  |  |  |                 boundary=contentType.mid(posi+9); | 
					
						
							|  |  |  |                 if  (boundary.startsWith('"') && boundary.endsWith('"')) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                    boundary = boundary.mid(1,boundary.length()-2); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         QByteArray contentLength=headers.value("content-length"); | 
					
						
							|  |  |  |         if (!contentLength.isEmpty()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             expectedBodySize=contentLength.toInt(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (expectedBodySize==0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |                 qDebug("HttpRequest::readHeader: expect no body"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |             #endif
 | 
					
						
							|  |  |  |             status=complete; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (boundary.isEmpty() && expectedBodySize+currentSize>maxSize) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |             qWarning("HttpRequest::readHeader: expected body is too large"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |             status=abort; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (!boundary.isEmpty() && expectedBodySize>maxMultiPartSize) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |             qWarning("HttpRequest::readHeader: expected multipart body is too large"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |             status=abort; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |                 qDebug("HttpRequest::readHeader: expect %i bytes body",expectedBodySize); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |             #endif
 | 
					
						
							|  |  |  |             status=waitForBody; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void HttpRequest::readBody(QTcpSocket* socket) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Q_ASSERT(expectedBodySize!=0); | 
					
						
							|  |  |  |     if (boundary.isEmpty()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // normal body, no multipart
 | 
					
						
							|  |  |  |         #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |             qDebug("HttpRequest::readBody: receive body"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |         #endif
 | 
					
						
							|  |  |  |         int toRead=expectedBodySize-bodyData.size(); | 
					
						
							|  |  |  |         QByteArray newData=socket->read(toRead); | 
					
						
							|  |  |  |         currentSize+=newData.size(); | 
					
						
							|  |  |  |         bodyData.append(newData); | 
					
						
							|  |  |  |         if (bodyData.size()>=expectedBodySize) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             status=complete; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // multipart body, store into temp file
 | 
					
						
							|  |  |  |         #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |             qDebug("HttpRequest::readBody: receiving multipart body"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |         #endif
 | 
					
						
							|  |  |  |         // Create an object for the temporary file, if not already present
 | 
					
						
							|  |  |  |         if (tempFile == NULL) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             tempFile = new QTemporaryFile; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (!tempFile->isOpen()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             tempFile->open(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         // Transfer data in 64kb blocks
 | 
					
						
							|  |  |  |         int fileSize=tempFile->size(); | 
					
						
							|  |  |  |         int toRead=expectedBodySize-fileSize; | 
					
						
							|  |  |  |         if (toRead>65536) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             toRead=65536; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         fileSize+=tempFile->write(socket->read(toRead)); | 
					
						
							|  |  |  |         if (fileSize>=maxMultiPartSize) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |             qWarning("HttpRequest::readBody: received too many multipart bytes"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |             status=abort; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (fileSize>=expectedBodySize) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |         #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |             qDebug("HttpRequest::readBody: received whole multipart body"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |         #endif
 | 
					
						
							|  |  |  |             tempFile->flush(); | 
					
						
							|  |  |  |             if (tempFile->error()) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |                 qCritical("HttpRequest::readBody: Error writing temp file for multipart body"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |             parseMultiPartFile(); | 
					
						
							|  |  |  |             tempFile->close(); | 
					
						
							|  |  |  |             status=complete; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void HttpRequest::decodeRequestParams() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |         qDebug("HttpRequest::decodeRequestParams: extract and decode request parameters"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |     #endif
 | 
					
						
							|  |  |  |     // Get URL parameters
 | 
					
						
							|  |  |  |     QByteArray rawParameters; | 
					
						
							|  |  |  |     int questionMark=path.indexOf('?'); | 
					
						
							|  |  |  |     if (questionMark>=0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         rawParameters=path.mid(questionMark+1); | 
					
						
							|  |  |  |         path=path.left(questionMark); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Get request body parameters
 | 
					
						
							|  |  |  |     QByteArray contentType=headers.value("content-type"); | 
					
						
							|  |  |  |     if (!bodyData.isEmpty() && (contentType.isEmpty() || contentType.startsWith("application/x-www-form-urlencoded"))) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (!rawParameters.isEmpty()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             rawParameters.append('&'); | 
					
						
							|  |  |  |             rawParameters.append(bodyData); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             rawParameters=bodyData; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // Split the parameters into pairs of value and name
 | 
					
						
							|  |  |  |     QList<QByteArray> list=rawParameters.split('&'); | 
					
						
							|  |  |  |     foreach (QByteArray part, list) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int equalsChar=part.indexOf('='); | 
					
						
							|  |  |  |         if (equalsChar>=0) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             QByteArray name=part.left(equalsChar).trimmed(); | 
					
						
							|  |  |  |             QByteArray value=part.mid(equalsChar+1).trimmed(); | 
					
						
							|  |  |  |             parameters.insert(urlDecode(name),urlDecode(value)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else if (!part.isEmpty()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             // Name without value
 | 
					
						
							|  |  |  |             parameters.insert(urlDecode(part),""); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void HttpRequest::extractCookies() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |         qDebug("HttpRequest::extractCookies"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |     #endif
 | 
					
						
							|  |  |  |     foreach(QByteArray cookieStr, headers.values("cookie")) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QList<QByteArray> list=HttpCookie::splitCSV(cookieStr); | 
					
						
							|  |  |  |         foreach(QByteArray part, list) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |                 qDebug("HttpRequest::extractCookies: found cookie %s",part.data()); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |             #endif                // Split the part into name and value
 | 
					
						
							|  |  |  |             QByteArray name; | 
					
						
							|  |  |  |             QByteArray value; | 
					
						
							|  |  |  |             int posi=part.indexOf('='); | 
					
						
							|  |  |  |             if (posi) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 name=part.left(posi).trimmed(); | 
					
						
							|  |  |  |                 value=part.mid(posi+1).trimmed(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 name=part.trimmed(); | 
					
						
							|  |  |  |                 value=""; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             cookies.insert(name,value); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     headers.remove("cookie"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void HttpRequest::readFromSocket(QTcpSocket* socket) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     Q_ASSERT(status!=complete); | 
					
						
							|  |  |  |     if (status==waitForRequest) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         readRequest(socket); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (status==waitForHeader) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         readHeader(socket); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (status==waitForBody) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         readBody(socket); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if ((boundary.isEmpty() && currentSize>maxSize) || (!boundary.isEmpty() && currentSize>maxMultiPartSize)) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |         qWarning("HttpRequest::readFromSocket: received too many bytes"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |         status=abort; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (status==complete) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         // Extract and decode request parameters from url and body
 | 
					
						
							|  |  |  |         decodeRequestParams(); | 
					
						
							|  |  |  |         // Extract cookies from headers
 | 
					
						
							|  |  |  |         extractCookies(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | HttpRequest::RequestStatus HttpRequest::getStatus() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return status; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QByteArray HttpRequest::getMethod() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return method; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QByteArray HttpRequest::getPath() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return urlDecode(path); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const QByteArray& HttpRequest::getRawPath() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return path; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QByteArray HttpRequest::getVersion() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return version; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QByteArray HttpRequest::getHeader(const QByteArray& name) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return headers.value(name.toLower()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QList<QByteArray> HttpRequest::getHeaders(const QByteArray& name) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return headers.values(name.toLower()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QMultiMap<QByteArray,QByteArray> HttpRequest::getHeaderMap() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return headers; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QByteArray HttpRequest::getParameter(const QByteArray& name) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return parameters.value(name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QList<QByteArray> HttpRequest::getParameters(const QByteArray& name) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return parameters.values(name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QMultiMap<QByteArray,QByteArray> HttpRequest::getParameterMap() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return parameters; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QByteArray HttpRequest::getBody() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return bodyData; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QByteArray HttpRequest::urlDecode(const QByteArray source) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     QByteArray buffer(source); | 
					
						
							|  |  |  |     buffer.replace('+',' '); | 
					
						
							|  |  |  |     int percentChar=buffer.indexOf('%'); | 
					
						
							|  |  |  |     while (percentChar>=0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         bool ok; | 
					
						
							|  |  |  |         char byte=buffer.mid(percentChar+1,2).toInt(&ok,16); | 
					
						
							|  |  |  |         if (ok) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             buffer.replace(percentChar,3,(char*)&byte,1); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         percentChar=buffer.indexOf('%',percentChar+1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return buffer; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void HttpRequest::parseMultiPartFile() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |     qDebug("HttpRequest::parseMultiPartFile: parsing multipart temp file"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |     tempFile->seek(0); | 
					
						
							|  |  |  |     bool finished=false; | 
					
						
							|  |  |  |     while (!tempFile->atEnd() && !finished && !tempFile->error()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2024-07-10 22:59:13 +02:00
										 |  |  |             qDebug("HttpRequest::parseMultiPartFile: reading multipart headers"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |         #endif
 | 
					
						
							|  |  |  |         QByteArray fieldName; | 
					
						
							|  |  |  |         QByteArray fileName; | 
					
						
							|  |  |  |         while (!tempFile->atEnd() && !finished && !tempFile->error()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             QByteArray line=tempFile->readLine(65536).trimmed(); | 
					
						
							|  |  |  |             if (line.startsWith("Content-Disposition:")) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if (line.contains("form-data")) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     int start=line.indexOf(" name=\""); | 
					
						
							|  |  |  |                     int end=line.indexOf("\"",start+7); | 
					
						
							|  |  |  |                     if (start>=0 && end>=start) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         fieldName=line.mid(start+7,end-start-7); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     start=line.indexOf(" filename=\""); | 
					
						
							|  |  |  |                     end=line.indexOf("\"",start+11); | 
					
						
							|  |  |  |                     if (start>=0 && end>=start) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         fileName=line.mid(start+11,end-start-11); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |                         qDebug("HttpRequest::parseMultiPartFile: multipart field=%s, filename=%s",fieldName.data(),fileName.data()); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |                     #endif
 | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else | 
					
						
							|  |  |  |                 { | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |                     qDebug("HttpRequest::parseMultiPartFile: ignoring unsupported content part %s",line.data()); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else if (line.isEmpty()) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2024-07-10 22:59:13 +02:00
										 |  |  |             qDebug("HttpRequest::parseMultiPartFile: reading multipart data"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |         #endif
 | 
					
						
							|  |  |  |         QTemporaryFile* uploadedFile=0; | 
					
						
							|  |  |  |         QByteArray fieldValue; | 
					
						
							|  |  |  |         while (!tempFile->atEnd() && !finished && !tempFile->error()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             QByteArray line=tempFile->readLine(65536); | 
					
						
							|  |  |  |             if (line.startsWith("--"+boundary)) | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 // Boundary found. Until now we have collected 2 bytes too much,
 | 
					
						
							|  |  |  |                 // so remove them from the last result
 | 
					
						
							|  |  |  |                 if (fileName.isEmpty() && !fieldName.isEmpty()) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     // last field was a form field
 | 
					
						
							|  |  |  |                     fieldValue.remove(fieldValue.size()-2,2); | 
					
						
							|  |  |  |                     parameters.insert(fieldName,fieldValue); | 
					
						
							|  |  |  |                     qDebug("HttpRequest: set parameter %s=%s",fieldName.data(),fieldValue.data()); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else if (!fileName.isEmpty() && !fieldName.isEmpty()) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     // last field was a file
 | 
					
						
							|  |  |  |                     #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |                         qDebug("HttpRequest::parseMultiPartFile: finishing writing to uploaded file"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |                     #endif
 | 
					
						
							|  |  |  |                     parameters.insert(fieldName,fileName); | 
					
						
							| 
									
										
										
										
											2018-02-21 18:54:59 +01:00
										 |  |  |                     if (uploadedFile) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         uploadedFile->resize(uploadedFile->size()-2); | 
					
						
							|  |  |  |                         uploadedFile->flush(); | 
					
						
							|  |  |  |                         uploadedFile->seek(0); | 
					
						
							|  |  |  |                         qDebug("HttpRequest::parseMultiPartFile: set parameter %s=%s",fieldName.data(),fileName.data()); | 
					
						
							|  |  |  |                         uploadedFiles.insert(fieldName,uploadedFile); | 
					
						
							|  |  |  |                         qDebug("HttpRequest::parseMultiPartFile: uploaded file size is %i",(int) uploadedFile->size()); | 
					
						
							|  |  |  |                     } | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 if (line.contains(boundary+"--")) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     finished=true; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |             { | 
					
						
							|  |  |  |                 if (fileName.isEmpty() && !fieldName.isEmpty()) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     // this is a form field.
 | 
					
						
							|  |  |  |                     currentSize+=line.size(); | 
					
						
							|  |  |  |                     fieldValue.append(line); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 else if (!fileName.isEmpty() && !fieldName.isEmpty()) | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     // this is a file
 | 
					
						
							|  |  |  |                     if (!uploadedFile) | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         uploadedFile=new QTemporaryFile(); | 
					
						
							|  |  |  |                         uploadedFile->open(); | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     uploadedFile->write(line); | 
					
						
							|  |  |  |                     if (uploadedFile->error()) | 
					
						
							|  |  |  |                     { | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |                         qCritical("HttpRequest::parseMultiPartFile: error writing temp file, %s",qPrintable(uploadedFile->errorString())); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |                     } | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (tempFile->error()) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |         qCritical("HttpRequest::parseMultiPartFile: cannot read temp file, %s",qPrintable(tempFile->errorString())); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     #ifdef SUPERVERBOSE
 | 
					
						
							| 
									
										
										
										
											2018-02-11 21:45:44 +01:00
										 |  |  |         qDebug("HttpRequest::parseMultiPartFile: finished parsing multipart temp file"); | 
					
						
							| 
									
										
										
										
											2017-08-23 18:47:07 +02:00
										 |  |  |     #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | HttpRequest::~HttpRequest() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     foreach(QByteArray key, uploadedFiles.keys()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         QTemporaryFile* file=uploadedFiles.value(key); | 
					
						
							|  |  |  |         if (file->isOpen()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             file->close(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         delete file; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (tempFile != NULL) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (tempFile->isOpen()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             tempFile->close(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         delete tempFile; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QTemporaryFile* HttpRequest::getUploadedFile(const QByteArray fieldName) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return uploadedFiles.value(fieldName); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | QByteArray HttpRequest::getCookie(const QByteArray& name) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return cookies.value(name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** Get the map of cookies */ | 
					
						
							|  |  |  | QMap<QByteArray,QByteArray>& HttpRequest::getCookieMap() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return cookies; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |   Get the address of the connected client. | 
					
						
							|  |  |  |   Note that multiple clients may have the same IP address, if they | 
					
						
							|  |  |  |   share an internet connection (which is very common). | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | QHostAddress HttpRequest::getPeerAddress() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return peerAddress; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |