static ClientSocketContext *
parseHttpRequest(ConnStateData *csd, Http1::RequestParser &hp)
{
- /* NP: don't be tempted to move this down or remove again.
- * It's the only DDoS protection old-String has against long URL */
- if ( hp.bufsiz <= 0) {
- debugs(33, 5, "Incomplete request, waiting for end of request line");
- return NULL;
- } else if ( (size_t)hp.bufsiz >= Config.maxRequestHeaderSize && headersEnd(hp.buf, Config.maxRequestHeaderSize) == 0) {
- debugs(33, 5, "parseHttpRequest: Too large request");
- hp.request_parse_status = Http::scHeaderTooLarge;
- return parseHttpRequestAbort(csd, "error:request-too-large");
- }
-
/* Attempt to parse the first line; this will define where the method, url, version and header begin */
{
const bool parsedOk = hp.parse();
return NULL;
}
- if (!parsedOk)
+ if (!parsedOk) {
+ if (hp.request_parse_status == Http::scHeaderTooLarge)
+ return parseHttpRequestAbort(csd, "error:request-too-large");
+
return parseHttpRequestAbort(csd, "error:invalid-request");
+ }
}
/* We know the whole request is in hp.buf now */
/* So the rest of the code will need to deal with '0'-byte headers (ie, none, so don't try parsing em) */
assert(req_sz > 0);
- /* Enforce max_request_size */
- if (req_sz >= Config.maxRequestHeaderSize) {
- debugs(33, 5, "parseHttpRequest: Too large request");
- hp.request_parse_status = Http::scHeaderTooLarge;
- return parseHttpRequestAbort(csd, "error:request-too-large");
- }
-
/* deny CONNECT via accelerated ports */
if (hp.method() == Http::METHOD_CONNECT && csd->port && csd->port->flags.accelSurrogate) {
debugs(33, DBG_IMPORTANT, "WARNING: CONNECT method received on " << csd->port->transport.protocol << " Accelerator port " << csd->port->s.port());
memmove(conn->in.buf, conn->in.buf + byteCount, conn->in.notYetUsed);
}
-/// respond with ERR_TOO_BIG if request header exceeds request_header_max_size
-void
-ConnStateData::checkHeaderLimits()
-{
- if (in.notYetUsed < Config.maxRequestHeaderSize)
- return; // can accumulte more header data
-
- debugs(33, 3, "Request header is too large (" << in.notYetUsed << " > " <<
- 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()
{
ClientSocketContext *context = parseHttpRequest(this, *parser_);
PROF_stop(parseHttpRequest);
- /* partial or incomplete request */
- if (!context) {
- // TODO: why parseHttpRequest can just return parseHttpRequestAbort
- // (which becomes context) but checkHeaderLimits cannot?
- checkHeaderLimits();
- break;
- }
-
/* status -1 or 1 */
if (context) {
debugs(33, 5, HERE << clientConnection << ": parsed a request");
return -1;
}
}
+
if (req.end == -1) {
+ // DoS protection against long first-line
+ if ( (size_t)bufsiz >= Config.maxRequestHeaderSize) {
+ debugs(33, 5, "Too large request-line");
+ // XXX: return URL-too-log status code if second_whitespace is not yet found.
+ request_parse_status = Http::scHeaderTooLarge;
+ return -1;
+ }
+
debugs(74, 5, "Parser: retval 0: from " << req.start <<
"->" << req.end << ": needs more data to complete first line.");
return 0;
// Input Validation:
+ // DoS protection against long first-line
+ if ((size_t)(req.end-req.start) >= Config.maxRequestHeaderSize) {
+ debugs(33, 5, "Too large request-line");
+ request_parse_status = Http::scHeaderTooLarge;
+ return -1;
+ }
+
// Process what we now know about the line structure into field offsets
// generating HTTP status for any aborts as we go.
*/
int64_t mimeHeaderBytes = 0;
if ((mimeHeaderBytes = headersEnd(buf+parseOffset_, bufsiz-parseOffset_)) == 0) {
- debugs(33, 5, "Incomplete request, waiting for end of headers");
+ if (bufsiz-parseOffset_ >= Config.maxRequestHeaderSize) {
+ debugs(33, 5, "Too large request");
+ request_parse_status = Http::scHeaderTooLarge;
+ completedState_ = HTTP_PARSE_DONE;
+ } else
+ debugs(33, 5, "Incomplete request, waiting for end of headers");
return false;
}
mimeHeaderBlock_.assign(&buf[req.end+1], mimeHeaderBytes);
// NP: planned name for this stage is HTTP_PARSE_MIME
// but we do not do any further stages here yet so go straight to DONE
completedState_ = HTTP_PARSE_DONE;
+
+ // Squid could handle these headers, but admin does not want to
+ if (messageHeaderSize() >= Config.maxRequestHeaderSize) {
+ debugs(33, 5, "Too large request");
+ request_parse_status = Http::scHeaderTooLarge;
+ return false;
+ }
}
return isDone();