/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "istream.h"
#include "iostream.h"
#include "istream-sized.h"
#include "http-parser.h"
#include "http-header.h"
#include "http-header-parser.h"
#include "http-date.h"
#include "http-transfer.h"
#include "http-message-parser.h"
#include <ctype.h>
{
if (hdr_limits != NULL)
}
{
}
{
} else {
}
}
}
{
}
{
/* RFC 7230, Section 2.6: Protocol Versioning
HTTP-version = HTTP-name "/" DIGIT "." DIGIT
HTTP-name = %x48.54.54.50 ; "HTTP", case-sensitive
*/
if (size < 8)
return 0;
return -1;
}
return 1;
}
{
const unsigned char *data;
int ret;
return 1;
if (ret < 0) {
} else {
}
}
return ret;
}
return 1;
}
static int
{
/* RFC 7230, Section 3.2.2: Field Order
A sender MUST NOT generate multiple header fields with the same field
name in a message unless either the entire field value for that
header field is defined as a comma-separated list [i.e., #(values)]
or the header field is a well-known exception.
*/
switch (name[0]) {
case 'C': case 'c':
/* Connection: */
const char **opt_idx;
const char *option;
unsigned int num_tokens = 0;
/* RFC 7230, Section 6.1: Connection
Connection = 1#connection-option
connection-option = token
*/
/* Multiple Connection headers are allowed and combined into one */
for (;;) {
break;
num_tokens++;
}
return -1;
}
return 0;
}
/* Content-Length: */
/* There is no acceptable way to allow duplicates for this
header. */
return -1;
}
/* RFC 7230, Section 3.3.2: Content-Length
Content-Length = 1*DIGIT
*/
return -1;
}
return 0;
}
break;
case 'D': case 'd':
/* Date: */
return -1;
}
/* Allow the duplicate; last instance is used */
}
/* RFC 7231, Section 7.1.1.2: Date
Date = HTTP-date
*/
return -1;
}
return 0;
}
break;
case 'L': case 'l':
/* Location: */
/* RFC 7231, Section 7.1.2: Location
Location = URI-reference
-> not parsed here
*/
/* FIXME: move this to response parser */
return 0;
}
break;
case 'T': case 't':
/* Transfer-Encoding: */
/* Multiple Transfer-Encoding headers are allowed and combined into one */
/* RFC 7230, Section 3.3.1: Transfer-Encoding
Transfer-Encoding = 1#transfer-coding
RFC 7230, Section 4: Transfer Codings
transfer-coding = "chunked" ; RFC 7230, Section 4.1
/ "compress" ; RFC 7230, Section 4.2.1
/ "deflate" ; RFC 7230, Section 4.2.2
/ "gzip" ; RFC 7230, Section 4.2.3
/ transfer-extension
transfer-extension = token *( OWS ";" OWS transfer-parameter )
transfer-parameter = token BWS "=" BWS ( token / quoted-string )
*/
for (;;) {
/* transfer-coding */
bool parse_error;
/* *( OWS ";" OWS transfer-parameter ) */
parse_error = FALSE;
for (;;) {
/* OWS ";" OWS */
break;
/* attribute */
parse_error = TRUE;
break;
}
/* BWS "=" BWS */
parse_error = TRUE;
break;
}
/* token / quoted-string */
parse_error = TRUE;
break;
}
}
if (parse_error)
break;
} else {
/* RFC 7230, Section 7: ABNF List Extension: #rule
For compatibility with legacy list rules, a recipient MUST parse
and ignore a reasonable number of empty list elements: enough to
handle common mistakes by senders that merge values, but not so
much that they could be used as a denial-of-service mechanism.
*/
// FIXME: limit allowed number of empty list elements
// FIXME: handle invalid transfer encoding
}
break;
}
return -1;
}
return 0;
}
break;
default:
break;
}
return 0;
}
{
const unsigned char *field_data;
int ret;
/* *( header-field CRLF ) CRLF */
if (field_name == NULL) {
/* EOH */
/* Create empty header if there is none */
/* handle HTTP/1.0 persistence */
!msg->connection_close) {
const char *const *option;
break;
}
}
}
}
return 1;
}
return -1;
}
if (ret < 0) {
} else {
}
}
return ret;
}
static const char *
{
}
{
chunked_last = TRUE;
"Unexpected parameter `%s' specified"
/* recoverable */
}
} else if (chunked_last) {
return -1;
/* recoverable */
}
}
if (chunked_last) {
} else if (!request) {
/* RFC 7230, Section 3.3.3: Message Body Length
If a Transfer-Encoding header field is present in a response and
the chunked transfer coding is not the final encoding, the
message body length is determined by reading the connection until
it is closed by the server.
*/
/* FIXME: enforce max payload size (relevant to http-client only) */
} else {
/* RFC 7230, Section 3.3.3: Message Body Length
If a Transfer-Encoding header field is present in a request and
the chunked transfer coding is not the final encoding, the
message body length cannot be determined reliably; the server
MUST respond with the 400 (Bad Request) status code and then
close the connection.
*/
return -1;
}
/* RFC 7230, Section 3.3.3: Message Body Length
If a message is received with both a Transfer-Encoding and a
Content-Length header field, the Transfer-Encoding overrides the
Content-Length. Such a message might indicate an attempt to
perform request smuggling (Section 9.5 of [RFC7230]) or response
splitting (Section 9.4 of [RFC7230]) and ought to be handled as
an error. A sender MUST remove the received Content-Length field
prior to forwarding such a message downstream.
*/
// FIXME: make this an error?
if (parser->max_payload_size > 0
return -1;
}
/* Got explicit message size from Content-Length: header */
/* Make sure we return failure if HTTP connection closes before
we've finished reading the full input. */
/* RFC 7230, Section 3.3.3: Message Body Length
6. If this is a request message and none of the above are true, then
the message body length is zero (no message body is present).
7. Otherwise, this is a response message without a declared message
body length, so the message body length is determined by the
number of octets received prior to the server closing the
connection
*/
// FIXME: enforce max payload size (relevant to http-client only)
// FIXME: handle request case correctly.
}
return -1;
return 0;
}