sdrangel/httpserver/httprequest.h

251 lines
6.8 KiB
C++

/**
@file
@author Stefan Frings
*/
#ifndef HTTPREQUEST_H
#define HTTPREQUEST_H
#include <QByteArray>
#include <QHostAddress>
#include <QTcpSocket>
#include <QMap>
#include <QMultiMap>
#include <QSettings>
#include <QTemporaryFile>
#include <QUuid>
#include "httpglobal.h"
#include "httplistenersettings.h"
#include "export.h"
namespace qtwebapp {
/**
This object represents a single HTTP request. It reads the request
from a TCP socket and provides getters for the individual parts
of the request.
<p>
The follwing config settings are required:
<code><pre>
maxRequestSize=16000
maxMultiPartSize=1000000
</pre></code>
<p>
MaxRequestSize is the maximum size of a HTTP request. In case of
multipart/form-data requests (also known as file-upload), the maximum
size of the body must not exceed maxMultiPartSize.
The body is always a little larger than the file itself.
*/
class HTTPSERVER_API HttpRequest {
Q_DISABLE_COPY(HttpRequest)
friend class HttpSessionStore;
public:
/** Values for getStatus() */
enum RequestStatus {waitForRequest, waitForHeader, waitForBody, complete, abort};
/**
Constructor.
@param settings Configuration settings
*/
HttpRequest(QSettings* settings);
/**
Constructor.
@param settings Configuration settings as a structure
*/
HttpRequest(const HttpListenerSettings* settings);
/**
Destructor.
*/
virtual ~HttpRequest();
/**
Read the HTTP request from a socket.
This method is called by the connection handler repeatedly
until the status is RequestStatus::complete or RequestStatus::abort.
@param socket Source of the data
*/
void readFromSocket(QTcpSocket* socket);
/**
Get the status of this reqeust.
@see RequestStatus
*/
RequestStatus getStatus() const;
/** Get the method of the HTTP request (e.g. "GET") */
QByteArray getMethod() const;
/** Get the decoded path of the HTPP request (e.g. "/index.html") */
QByteArray getPath() const;
/** Get the raw path of the HTTP request (e.g. "/file%20with%20spaces.html") */
const QByteArray& getRawPath() const;
/** Get the version of the HTPP request (e.g. "HTTP/1.1") */
QByteArray getVersion() const;
/**
Get the value of a HTTP request header.
@param name Name of the header, not case-senitive.
@return If the header occurs multiple times, only the last
one is returned.
*/
QByteArray getHeader(const QByteArray& name) const;
/**
Get the values of a HTTP request header.
@param name Name of the header, not case-senitive.
*/
QList<QByteArray> getHeaders(const QByteArray& name) const;
/**
* Get all HTTP request headers. Note that the header names
* are returned in lower-case.
*/
QMultiMap<QByteArray,QByteArray> getHeaderMap() const;
/**
Get the value of a HTTP request parameter.
@param name Name of the parameter, case-sensitive.
@return If the parameter occurs multiple times, only the last
one is returned.
*/
QByteArray getParameter(const QByteArray& name) const;
/**
Get the values of a HTTP request parameter.
@param name Name of the parameter, case-sensitive.
*/
QList<QByteArray> getParameters(const QByteArray& name) const;
/** Get all HTTP request parameters. */
QMultiMap<QByteArray,QByteArray> getParameterMap() const;
/** Get the HTTP request body. */
QByteArray getBody() const;
/**
Decode an URL parameter.
E.g. replace "%23" by '#' and replace '+' by ' '.
@param source The url encoded strings
@see QUrl::toPercentEncoding for the reverse direction
*/
static QByteArray urlDecode(const QByteArray source);
/**
Get an uploaded file. The file is already open. It will
be closed and deleted by the destructor of this HttpRequest
object (after processing the request).
<p>
For uploaded files, the method getParameters() returns
the original fileName as provided by the calling web browser.
*/
QTemporaryFile* getUploadedFile(const QByteArray fieldName) const;
/**
Get the value of a cookie.
@param name Name of the cookie
*/
QByteArray getCookie(const QByteArray& name) const;
/** Get all cookies. */
QMap<QByteArray,QByteArray>& getCookieMap();
/**
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 getPeerAddress() const;
private:
/** Request headers */
QMultiMap<QByteArray,QByteArray> headers;
/** Parameters of the request */
QMultiMap<QByteArray,QByteArray> parameters;
/** Uploaded files of the request, key is the field name. */
QMap<QByteArray,QTemporaryFile*> uploadedFiles;
/** Received cookies */
QMap<QByteArray,QByteArray> cookies;
/** Storage for raw body data */
QByteArray bodyData;
/** Request method */
QByteArray method;
/** Request path (in raw encoded format) */
QByteArray path;
/** Request protocol version */
QByteArray version;
/**
Status of this request. For the state engine.
@see RequestStatus
*/
RequestStatus status;
/** Address of the connected peer. */
QHostAddress peerAddress;
/** Maximum size of requests in bytes. */
int maxSize;
/** Maximum allowed size of multipart forms in bytes. */
int maxMultiPartSize;
/** Current size */
int currentSize;
/** Expected size of body */
int expectedBodySize;
/** Name of the current header, or empty if no header is being processed */
QByteArray currentHeader;
/** Boundary of multipart/form-data body. Empty if there is no such header */
QByteArray boundary;
/** Temp file, that is used to store the multipart/form-data body */
QTemporaryFile* tempFile;
/** Parse the multipart body, that has been stored in the temp file. */
void parseMultiPartFile();
/** Sub-procedure of readFromSocket(), read the first line of a request. */
void readRequest(QTcpSocket* socket);
/** Sub-procedure of readFromSocket(), read header lines. */
void readHeader(QTcpSocket* socket);
/** Sub-procedure of readFromSocket(), read the request body. */
void readBody(QTcpSocket* socket);
/** Sub-procedure of readFromSocket(), extract and decode request parameters. */
void decodeRequestParams();
/** Sub-procedure of readFromSocket(), extract cookies from headers */
void extractCookies();
/** Buffer for collecting characters of request and header lines */
QByteArray lineBuffer;
/** Settings flag */
bool useQtSettings;
};
} // end of namespace
#endif // HTTPREQUEST_H