6#include "multipartformdataparser_p.h"
14 if (body->isSequential()) {
15 qCWarning(CUTELYST_MULTIPART) <<
"Parsing sequential body is not supported" << body;
19 int start = contentType.indexOf(
"boundary=");
21 qCWarning(CUTELYST_MULTIPART) <<
"No boundary match" << contentType;
27 const int len = contentType.length();
28 boundary.reserve(contentType.length() - start + 2);
30 for (
int i = start, quotes = 0; i < len; ++i) {
31 const char ch = contentType.at(i);
33 if (quotes == 0 && i > start) {
35 }
else if (++quotes == 2) {
38 }
else if (ch ==
';') {
45 if (boundary.isEmpty()) {
46 qCWarning(CUTELYST_MULTIPART) <<
"Boundary match was empty" << contentType;
49 boundary.prepend(
"--", 2);
51 if (bufferSize < 1024) {
54 char *buffer =
new char[bufferSize];
56 ret = MultiPartFormDataParserPrivate::execute(buffer, bufferSize, body, boundary);
63Uploads MultiPartFormDataParserPrivate::execute(
char *buffer,
66 const QByteArray &boundary)
69 QByteArray headerLine;
71 qint64 startOffset = 0;
73 qint64 contentLength = body->size();
75 int boundarySize = boundary.size();
76 ParserState state = FindBoundary;
77 QByteArrayMatcher matcher(boundary);
79 while (pos < contentLength) {
80 qint64 len = body->read(buffer + bufferSkip, bufferSize - bufferSkip);
82 qCWarning(CUTELYST_MULTIPART) <<
"Error while reading POST body" << body->errorString();
93 i += findBoundary(buffer + i, len - i, matcher, boundarySize, state);
97 if (buffer[i] !=
'\r') {
101 state = EndBoundaryLF;
104 if (buffer[i] !=
'\n') {
108 state = StartHeaders;
111 if (headerLine.isEmpty() && buffer[i] ==
'\r') {
115 const char *pch =
static_cast<char *
>(memchr(buffer + i,
'\r', len - i));
116 if (pch ==
nullptr) {
117 headerLine.append(buffer + i, len - i);
120 headerLine.append(buffer + i, pch - buffer - i);
122 state = FinishHeader;
127 if (buffer[i] ==
'\n') {
128 int dotdot = headerLine.indexOf(
':');
130 headerLine.left(dotdot),
131 QByteArrayView{headerLine}.sliced(dotdot + 1).trimmed().toByteArray());
133 state = StartHeaders;
140 if (buffer[i] ==
'\n') {
150 startOffset = pos - len + i;
154 i += findBoundary(buffer + i, len - i, matcher, boundarySize, state);
156 if (state == EndBoundaryCR) {
159 const qint64 endOffset = pos - len + i - boundarySize - 1;
161 new Upload(
new UploadPrivate(body, headers, startOffset, endOffset));
168 bufferSkip = boundarySize - 1;
169 memmove(buffer, buffer + len - bufferSkip, bufferSkip);
181int MultiPartFormDataParserPrivate::findBoundary(
char *buffer,
183 const QByteArrayMatcher &matcher,
185 MultiPartFormDataParserPrivate::ParserState &state)
187 int i = matcher.indexIn(buffer, len);
192 state = EndBoundaryCR;
193 return i + boundarySize - 1;
198#include "moc_multipartformdataparser_p.cpp"
Cutelyst Upload handles file upload requests.
The Cutelyst namespace holds all public Cutelyst API.