void
connNoteUseOfBuffer(ConnStateData* conn, size_t byteCount)
{
- assert(byteCount > 0 && byteCount <= conn->in.notYetUsed);
- conn->in.notYetUsed -= byteCount;
- debugs(33, 5, HERE << "conn->in.notYetUsed = " << conn->in.notYetUsed);
- /*
- * If there is still data that will be used,
- * move it to the beginning.
- */
-
- if (conn->in.notYetUsed > 0)
- memmove(conn->in.buf, conn->in.buf + byteCount, conn->in.notYetUsed);
+ assert(byteCount > 0 && byteCount <= conn->in.buf.length());
+ conn->in.buf.consume(byteCount);
+ debugs(33, 5, "conn->in.buf has " << conn->in.buf.length() << " bytes unused.");
}
-/// respond with ERR_TOO_BIG if request header exceeds request_header_max_size
-void
-ConnStateData::checkHeaderLimits()
-{
- if (in.buf.length() < Config.maxRequestHeaderSize)
- return; // can accumulte more header data
-
- debugs(33, 3, "Request header is too large (" << in.buf.length() << " > " <<
- Config.maxRequestHeaderSize << " bytes)");
-
- ClientSocketContext *context = parseHttpRequestAbort(this, "error:request-too-large");
- clientStreamNode *node = context->getClientReplyContext();
- clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
- assert (repContext);
- repContext->setReplyToError(ERR_TOO_BIG,
- Http::scBadRequest, Http::METHOD_NONE, NULL,
- clientConnection->remote, NULL, NULL, NULL);
- context->registerWithConn();
- context->pullData();
-}
-
void
ConnStateData::clientAfterReadingRequests()
{
return false;
}
- #endif // USE_SSL
+ #endif // USE_OPENSSL
static void
-clientProcessRequest(ConnStateData *conn, HttpParser *hp, ClientSocketContext *context, const HttpRequestMethod& method, Http::ProtocolVersion http_ver)
+clientProcessRequest(ConnStateData *conn, Http1::RequestParser &hp, ClientSocketContext *context)
{
ClientHttpRequest *http = context->http;
HttpRequest::Pointer request;
setLogUri(http, http->uri, true);
clientReplyContext *repContext = dynamic_cast<clientReplyContext *>(node->data.getRaw());
assert (repContext);
- switch (hp->request_parse_status) {
+ switch (hp.request_parse_status) {
case Http::scHeaderTooLarge:
- repContext->setReplyToError(ERR_TOO_BIG, Http::scBadRequest, method, http->uri,
- conn->clientConnection->remote, NULL, conn->in.buf, NULL);
+ repContext->setReplyToError(ERR_TOO_BIG, Http::scBadRequest, method, http->uri, conn->clientConnection->remote, NULL, conn->in.buf.c_str(), NULL);
break;
case Http::scMethodNotAllowed:
repContext->setReplyToError(ERR_UNSUP_REQ, Http::scMethodNotAllowed, method, http->uri,
- conn->clientConnection->remote, NULL, conn->in.buf, NULL);
+ conn->clientConnection->remote, NULL, conn->in.buf.c_str(), NULL);
break;
+ case Http::scHttpVersionNotSupported:
+ repContext->setReplyToError(ERR_UNSUP_HTTPVERSION, Http::scHttpVersionNotSupported, method, http->uri,
+ conn->clientConnection->remote, NULL, conn->in.buf, NULL);
+ break;
default:
- repContext->setReplyToError(ERR_INVALID_REQ, hp.request_parse_status, method, http->uri,
- conn->clientConnection->remote, NULL, conn->in.buf, NULL);
+ repContext->setReplyToError(ERR_INVALID_REQ, hp->request_parse_status, method, http->uri,
+ conn->clientConnection->remote, NULL, conn->in.buf.c_str(), NULL);
}
assert(context->http->out.offset == 0);
context->pullData();
// Loop while we have read bytes that are not needed for producing the body
// On errors, bodyPipe may become nil, but readMore will be cleared
- while (in.notYetUsed > 0 && !bodyPipe && flags.readMore) {
+ while (!in.buf.isEmpty() && !bodyPipe && flags.readMore) {
- connStripBufferWhitespace(this);
/* Don't try to parse if the buffer is empty */
- if (in.notYetUsed == 0)
+ if (in.buf.isEmpty())
break;
/* Limit the number of concurrent requests */
/* Begin the parsing */
PROF_start(parseHttpRequest);
- HttpParserInit(&parser_, in.buf.c_str(), in.buf.length());
- /* Process request */
- Http::ProtocolVersion http_ver;
- ClientSocketContext *context = parseHttpRequest(this, &parser_, &method, &http_ver);
- PROF_stop(parseHttpRequest);
+ // parser is incremental. Generate new parser state if we,
+ // a) dont have one already
+ // b) have completed the previous request parsing already
+ if (!parser_ || parser_->isDone())
- parser_ = new Http1::RequestParser(in.buf, in.notYetUsed);
++ parser_ = new Http1::RequestParser(in.buf.c_str(), in.buf.length());
+ else // update the buffer space being parsed
- parser_->bufsiz = in.notYetUsed;
++ parser_->bufsiz = in.buf.length();
- /* partial or incomplete request */
- if (!context) {
- // TODO: why parseHttpRequest can just return parseHttpRequestAbort
- // (which becomes context) but checkHeaderLimits cannot?
- checkHeaderLimits();
- break;
+ /* Process request */
+ ClientSocketContext *context = parseHttpRequest(this, *parser_);
+ if (parser_->doneBytes()) {
+ // we are done with some of the buffer. consume it now.
+ connNoteUseOfBuffer(this, parser_->doneBytes());
+ parser_->noteBufferShift(parser_->doneBytes());
}
+ PROF_stop(parseHttpRequest);
/* status -1 or 1 */
if (context) {