/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "istream.h"
#include "http-url.h"
#include "http-parser.h"
#include "http-message-parser.h"
#include "http-request-parser.h"
enum http_request_parser_state {
};
struct http_request_parser {
const char *request_method;
const char *request_target;
};
struct http_request_parser *
const struct http_request_limits *limits,
{
} else {
i_zero(&hdr_limits);
max_payload_size = 0;
}
/* substitute default limits */
if (parser->max_target_length == 0)
if (hdr_limits.max_size == 0)
if (hdr_limits.max_field_size == 0)
if (hdr_limits.max_fields == 0)
if (max_payload_size == 0)
if ((flags & HTTP_REQUEST_PARSE_FLAG_STRICT) != 0)
return parser;
}
{
}
static void
{
}
{
/* method = token
*/
p++;
return -1;
}
return 0;
return 1;
}
{
/* We'll just parse anything up to the first SP or a control char.
We could also implement workarounds for buggy HTTP clients and
parse anything up to the HTTP-version and return 301 with the
target properly encoded (FIXME). */
p++;
/* target is too long when explicit limit is exceeded or when input buffer
runs out of space */
/* FIXME: put limit on full request line rather than target and method
separately */
/* FIXME: is it wise to keep target in stream buffer? It can become very
large for some applications, increasing the stream buffer size */
return -1;
}
return 0;
return 1;
}
static inline const char *_chr_sanitize(unsigned char c)
{
if (c >= 0x20 && c < 0x7F)
return t_strdup_printf("`%c'", c);
if (c == 0x0a)
return "<LF>";
if (c == 0x0d)
return "<CR>";
return t_strdup_printf("<0x%02x>", c);
}
{
int ret;
/* RFC 7230, Section 3.1.1: Request Line
request-line = method SP request-target SP HTTP-version CRLF
method = token
*/
for (;;) {
return 0;
/* fall through */
if (parser->skipping_line) {
/* second extra CRLF; not allowed */
return -1;
}
/* HTTP/1.0 client sent one extra CRLF after body.
ignore it. */
break;
}
/* fall through */
return ret;
return 0;
/* fall through */
("Unexpected character %s in request method",
return -1;
}
return 0;
/* fall through */
return ret;
return 0;
/* fall through */
("Unexpected character %s in request target",
return -1;
}
return 0;
/* fall through */
if (ret < 0) {
}
return ret;
}
return 0;
/* fall through */
return 0;
/* fall through */
("Unexpected character %s at end of request line",
return -1;
}
if (!parser->skipping_line) {
return 1;
}
break;
default:
i_unreached();
}
}
i_unreached();
return -1;
}
{
const unsigned char *begin;
int ret;
old_bytes + 1)) > 0) {
return -1;
if (ret > 0)
return 1;
}
if (ret == -2) {
return -1;
}
if (ret < 0) {
return 0;
return -1;
}
return 0;
}
static inline enum http_request_parse_error
{
default:
break;
}
i_unreached();
}
struct http_request_parser *parser)
{
return FALSE;
}
static int
{
unsigned int num_expectations = 0;
/* RFC 7231, Section 5.1.1:
Expect = "100-continue"
*/
// FIXME: simplify; RFC 7231 discarded Expect extension mechanism
while (!parse_error) {
/* expect-name */
} else {
("Unknown Expectation `%s'", expect_name);
}
}
/* BWS "=" BWS */
break;
/* value */
parse_error = TRUE;
break;
}
("Expectation `%s' has unexpected value", expect_name);
}
}
/* *( OWS ";" [ OWS expect-param ] ) */
while (!parse_error) {
/* OWS ";" */
break;
/* expect-param */
parse_error = TRUE;
break;
}
/* BWS "=" BWS */
parse_error = TRUE;
break;
}
/* value */
parse_error = TRUE;
break;
}
("Expectation `%s' has unknown parameter `'%s'",
}
}
if (parse_error)
break;
}
break;
}
return -1;
}
return -1;
if (num_expectations == 0) {
return -1;
}
return 0;
}
static int
struct http_request *request)
{
int ret = 0;
/* Expect: */
if (ret < 0)
return -1;
}
return 0;
}
struct http_request_parser *parser,
const char **error_r)
{
int ret;
/* make sure we finished streaming payload from previous request
before we continue. */
if (ret < 0) {
}
}
return ret;
}
{
const char *error;
int ret;
/* initialize and get rid of any payload of previous request */
return ret;
/* RFC 7230, Section 3:
HTTP-message = start-line
*( header-field CRLF )
CRLF
[ message-body ]
*/
/* assign early for error reporting */
if (ret <= 0) {
if (ret < 0) {
}
return ret;
}
}
if (ret < 0) {
}
return ret;
}
return -1;
}
/* RFC 7230, Section 5.4: Host
A server MUST respond with a 400 (Bad Request) status code to any
HTTP/1.1 request message that lacks a Host header field and to any
request message that contains more than one Host header field or a
Host header field with an invalid field-value.
*/
if (ret == 0)
*error_r = "Missing Host header";
else
*error_r = "Duplicate Host header";
return -1;
}
return -1;
}
/* parse request-specific headers */
return -1;
}
/* reset this state early */
return 1;
}