13 #include <QMapIterator> 20 m_datetime = QDateTime::currentDateTime();
23 m_expectedBodySize = 0;
24 m_connection = parent;
46 if (m_currentSize > m_connection->settings()->maxRequestSize()) {
63 int toRead = m_connection->settings()->maxRequestSize() - m_currentSize + 1;
64 QByteArray newdata = socket->readLine(toRead).trimmed();
65 m_currentSize += newdata.size();
67 if (newdata.isEmpty()) {
71 QStringList list = QString::fromUtf8(newdata).split(
' ');
72 if (list.size() != 3 || !list[2].contains(
"HTTP")) {
73 qWarning(
"HttpRequest: received broken HTTP request, invalid first line");
83 m_connection->setObjectName(m_path);
91 int toRead = m_connection->settings()->maxRequestSize() - m_currentSize + 1;
92 QByteArray newdata = socket->readLine(toRead).trimmed();
93 m_currentSize += newdata.size();
95 int colonpos = newdata.indexOf(
':');
97 m_currentHeader = QString::fromUtf8(newdata.left(colonpos));
98 QString value = QString::fromUtf8(newdata.mid(colonpos+1).trimmed());
99 m_headers.insert(m_currentHeader,value);
103 if (colonpos <= 0 && !newdata.isEmpty()) {
106 m_headers.value(m_currentHeader) + QString(
" ") + QString::fromUtf8(newdata)
111 if (newdata.isEmpty()) {
114 if (
contentType.startsWith(
"multipart/form-data", Qt::CaseInsensitive)) {
115 int pos =
contentType.indexOf(
"boundary=", 0, Qt::CaseInsensitive);
121 m_expectedBodySize =
header(
"Content-Length").toInt();
122 if (m_expectedBodySize <= 0) {
127 if (m_boundary.isEmpty() && m_expectedBodySize + m_currentSize > m_connection->settings()->maxRequestSize()) {
128 qWarning(
"HttpRequest: expected body is too large");
133 if (!m_boundary.isEmpty() && m_expectedBodySize > m_connection->settings()->maxMultiPartSize()) {
134 qWarning(
"HttpRequest: expected multipart body is too large");
151 if (m_boundary.isEmpty()) {
152 int toRead = m_expectedBodySize - m_bodyData.size();
153 QByteArray newdata = socket->read(toRead);
154 m_currentSize += newdata.size();
156 m_bodyData.append(newdata);
157 if (m_bodyData.size() >= m_expectedBodySize) {
164 if (!m_boundary.isEmpty()) {
165 if (!m_tempFile.isOpen()) {
168 int filesize = m_tempFile.size();
169 int toRead = m_expectedBodySize - filesize;
170 if (toRead > 65536) {
174 filesize += m_tempFile.write(socket->read(toRead));
175 if (filesize >= m_connection->settings()->maxMultiPartSize()) {
176 qWarning(
"HttpRequest: received too many multipart bytes");
181 if (filesize >= m_expectedBodySize) {
196 QString rawParameters;
197 if (
header(
"Content-Type").toLower() ==
"application/x-www-form-urlencoded") {
198 rawParameters = m_bodyData;
200 int questionmarkpos = m_path.indexOf(
'?');
201 if (questionmarkpos >= 0) {
202 rawParameters = m_path.mid(questionmarkpos+1);
203 m_path = m_path.left(questionmarkpos);
207 QStringList list = rawParameters.split(
'&');
208 for (
int i=0; i<list.size(); i++) {
209 QString& part = list[i];
210 int eqpos = part.indexOf(
'=');
212 QString name =
urlDecode( part.left(eqpos).trimmed() );
213 QString value =
urlDecode( part.mid(eqpos+1).trimmed() );
214 m_parameters.insert(name, value);
218 if (!part.isEmpty()) {
220 m_parameters.insert(name,
"");
230 QStringList cookies =
headers(
"Cookie");
231 for (
int i=0; i<cookies.size(); i++) {
233 QStringList parts = cookies[i].split(
";");
234 for (
int i=0; i<parts.size(); i++) {
235 QString& part = parts[i];
236 int eqpos = part.indexOf(
'=');
238 QString name = part.left(eqpos).trimmed();
239 QString value = part.mid(eqpos+1).trimmed();
240 if (name.startsWith(
"$")) {
243 m_cookies.insert(name, value);
247 m_cookies.insert(part,
"");
260 QByteArray buffer(text.toUtf8());
261 buffer.replace(
'+',
' ');
262 int percentpos = buffer.indexOf(
'%');
263 while (percentpos >= 0) {
266 int byte = buffer.mid(percentpos+1, 2).toInt(&ok, 16);
268 buffer.remove(percentpos,3);
269 buffer.insert(percentpos, byte);
271 percentpos = buffer.indexOf(
'%', percentpos+1);
273 return QString::fromUtf8(buffer);
283 while (!m_tempFile.atEnd() && !finished && !m_tempFile.error()) {
288 while (!m_tempFile.atEnd() && !finished && !m_tempFile.error()) {
289 QString line = QString::fromUtf8(m_tempFile.readLine(65536).trimmed());
290 if (line.startsWith(
"--"+m_boundary)) {
continue; }
291 if (line.isEmpty()) {
break; }
292 if (line.startsWith(
"Content-Disposition:", Qt::CaseInsensitive)) {
293 if (line.contains(
"form-data", Qt::CaseInsensitive)) {
294 int start=line.indexOf(
" name=\"", 0, Qt::CaseInsensitive);
295 int end=line.indexOf(
"\"",start+7);
296 if (start>=0 && end>=start) {
297 fieldName=line.mid(start+7,end-start-7);
299 start=line.indexOf(
" filename=\"", 0, Qt::CaseInsensitive);
300 end=line.indexOf(
"\"",start+11);
301 if (start>=0 && end>=start) {
302 fileName=line.mid(start+11,end-start-11);
307 if (line.startsWith(
"Content-Type:", Qt::CaseInsensitive)) {
308 contentType = line.remove(QRegExp(
"^Content-Type:\\s*", Qt::CaseInsensitive));
312 qDebug() <<
"HttpRequest: ignoring unsupported content part" << line;
316 QByteArray fieldValue;
317 while (!m_tempFile.atEnd() && !finished && !m_tempFile.error()) {
318 QByteArray line = m_tempFile.readLine(65536);
319 if (line.startsWith(
"--"+m_boundary)) {
322 if (fileName.isEmpty() && !fieldName.isEmpty()) {
324 fieldValue.remove(fieldValue.size()-2,2);
325 m_parameters.insert(fieldName,fieldValue);
327 else if (!fileName.isEmpty() && !fieldName.isEmpty()) {
332 m_parameters.insert(fieldName,fileName);
336 if (line.contains(m_boundary+
"--")) {
341 if (fileName.isEmpty() && !fieldName.isEmpty()) {
343 m_currentSize+=line.size();
344 fieldValue.append(line);
346 else if (!fileName.isEmpty() && !fieldName.isEmpty()) {
354 qCritical(
"HttpRequest: error writing temp file, %s",qPrintable(
uploadedFile->errorString()));
360 if (m_tempFile.error()) {
361 qCritical(
"HttpRequest: cannot read temp file, %s",qPrintable(m_tempFile.errorString()));
367 QMapIterator<QString, QString> iterator(m_headers);
368 while (iterator.hasNext()) {
370 if (iterator.key().toLower() == name.toLower()) {
371 return iterator.value();
379 QMapIterator<QString, QString> iterator(m_headers);
380 while (iterator.hasNext()) {
382 if (iterator.key().toLower() == name.toLower()) {
383 return m_headers.values(iterator.key());
386 return QList<QString>();
QString statusString() const
Returns current status of the request as a string.
QList< QString > headers(const QString &name) const
Returns all headers of HTTP request in QList, case insensitive.
void readHeader(QTcpSocket *socket)
Reads HTTP headers of the request.
void parseMultiPartFile()
Parses the mime multipart request.
QString contentType(const QString &fieldName) const
Returns content type of uploaded file.
QTemporaryFile * uploadedFile(const QString &fieldName)
Returns temporary file with uploaded file from html form.
QString header(const QString &name) const
Returns requested header value, case insensitive.
static QString urlDecode(const QString &source)
Converts URL encoded string to UTF8 string.
void readBody(QTcpSocket *socket)
Reads body of the request.
void readFromSocket(QTcpSocket *socket)
Reads data from socket.
void readRequest(QTcpSocket *socket)
Reads request from socket.
void extractCookies()
Parses cookies.
Namespace of HTTP server.
HttpRequest(HttpConnection *connection)
Constructor sets default falues from configuration.
One single connection to http server.
void decodeRequestParams()
Parses parameters of the URL.