1
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
5
#include "http-parser.h"
7
#include "http-message-parser.h"
8
#include "http-response-parser.h"
12
enum http_response_parser_state {
13
HTTP_RESPONSE_PARSE_STATE_INIT = 0,
14
HTTP_RESPONSE_PARSE_STATE_VERSION,
15
HTTP_RESPONSE_PARSE_STATE_SP1,
16
HTTP_RESPONSE_PARSE_STATE_STATUS,
17
HTTP_RESPONSE_PARSE_STATE_SP2,
18
HTTP_RESPONSE_PARSE_STATE_REASON,
19
HTTP_RESPONSE_PARSE_STATE_CR,
20
HTTP_RESPONSE_PARSE_STATE_LF,
21
HTTP_RESPONSE_PARSE_STATE_HEADER
24
struct http_response_parser {
25
struct http_message_parser parser;
26
enum http_response_parser_state state;
28
unsigned int response_status;
29
const char *response_reason;
32
struct http_response_parser *
33
http_response_parser_init(struct istream *input,
34
const struct http_header_limits *hdr_limits)
36
struct http_response_parser *parser;
38
/* FIXME: implement status line limit */
39
parser = i_new(struct http_response_parser, 1);
40
http_message_parser_init(&parser->parser, input, hdr_limits, 0);
44
void http_response_parser_deinit(struct http_response_parser **_parser)
46
struct http_response_parser *parser = *_parser;
48
http_message_parser_deinit(&parser->parser);
53
http_response_parser_restart(struct http_response_parser *parser)
55
http_message_parser_restart(&parser->parser, NULL);
56
parser->response_status = 0;
57
parser->response_reason = NULL;
60
static int http_response_parse_status(struct http_response_parser *parser)
62
const unsigned char *p = parser->parser.cur;
63
const size_t size = parser->parser.end - parser->parser.cur;
65
/* status-code = 3DIGIT
69
if (!i_isdigit(p[0]) || !i_isdigit(p[1]) || !i_isdigit(p[2]))
71
parser->response_status =
72
(p[0] - '0')*100 + (p[1] - '0')*10 + (p[2] - '0');
73
parser->parser.cur += 3;
77
static int http_response_parse_reason(struct http_response_parser *parser)
79
const unsigned char *p = parser->parser.cur;
81
/* reason-phrase = *( HTAB / SP / VCHAR / obs-text )
83
// FIXME: limit length
84
while (p < parser->parser.end && http_char_is_text(*p))
87
if (p == parser->parser.end)
89
parser->response_reason =
90
p_strdup_until(parser->parser.msg.pool, parser->parser.cur, p);
91
parser->parser.cur = p;
95
static inline const char *_chr_sanitize(unsigned char c)
97
if (c >= 0x20 && c < 0x7F)
98
return t_strdup_printf("`%c'", c);
103
return t_strdup_printf("<0x%02x>", c);
106
static int http_response_parse(struct http_response_parser *parser)
108
struct http_message_parser *_parser = &parser->parser;
111
/* status-line = HTTP-version SP status-code SP reason-phrase CRLF
113
reason-phrase = *( HTAB / SP / VCHAR / obs-text )
116
switch (parser->state) {
117
case HTTP_RESPONSE_PARSE_STATE_INIT:
118
http_response_parser_restart(parser);
119
parser->state = HTTP_RESPONSE_PARSE_STATE_VERSION;
121
case HTTP_RESPONSE_PARSE_STATE_VERSION:
122
if ((ret=http_message_parse_version(_parser)) <= 0) {
124
_parser->error = "Invalid HTTP version in response";
127
parser->state = HTTP_RESPONSE_PARSE_STATE_SP1;
128
if (_parser->cur == _parser->end)
131
case HTTP_RESPONSE_PARSE_STATE_SP1:
132
if (*_parser->cur != ' ') {
133
_parser->error = t_strdup_printf
134
("Expected ' ' after response version, but found %s",
135
_chr_sanitize(*_parser->cur));
139
parser->state = HTTP_RESPONSE_PARSE_STATE_STATUS;
140
if (_parser->cur >= _parser->end)
143
case HTTP_RESPONSE_PARSE_STATE_STATUS:
144
if ((ret=http_response_parse_status(parser)) <= 0) {
146
_parser->error = "Invalid HTTP status code in response";
149
parser->state = HTTP_RESPONSE_PARSE_STATE_SP2;
150
if (_parser->cur == _parser->end)
153
case HTTP_RESPONSE_PARSE_STATE_SP2:
154
if (*_parser->cur != ' ') {
155
_parser->error = t_strdup_printf
156
("Expected ' ' after response status code, but found %s",
157
_chr_sanitize(*_parser->cur));
161
parser->state = HTTP_RESPONSE_PARSE_STATE_REASON;
162
if (_parser->cur >= _parser->end)
165
case HTTP_RESPONSE_PARSE_STATE_REASON:
166
if ((ret=http_response_parse_reason(parser)) <= 0) {
170
parser->state = HTTP_RESPONSE_PARSE_STATE_CR;
171
if (_parser->cur == _parser->end)
174
case HTTP_RESPONSE_PARSE_STATE_CR:
175
if (*_parser->cur == '\r')
177
parser->state = HTTP_RESPONSE_PARSE_STATE_LF;
178
if (_parser->cur == _parser->end)
181
case HTTP_RESPONSE_PARSE_STATE_LF:
182
if (*_parser->cur != '\n') {
183
_parser->error = t_strdup_printf
184
("Expected line end after response, but found %s",
185
_chr_sanitize(*_parser->cur));
189
parser->state = HTTP_RESPONSE_PARSE_STATE_HEADER;
191
case HTTP_RESPONSE_PARSE_STATE_HEADER:
201
http_response_parse_status_line(struct http_response_parser *parser)
203
struct http_message_parser *_parser = &parser->parser;
204
const unsigned char *begin;
205
size_t size, old_bytes = 0;
208
while ((ret = i_stream_read_data(_parser->input, &begin, &size,
210
_parser->cur = begin;
211
_parser->end = _parser->cur + size;
213
if ((ret = http_response_parse(parser)) < 0)
216
i_stream_skip(_parser->input, _parser->cur - begin);
219
old_bytes = i_stream_get_data_size(_parser->input);
223
_parser->error = "HTTP status line is too long";
227
if (_parser->input->eof &&
228
parser->state == HTTP_RESPONSE_PARSE_STATE_INIT)
230
_parser->error = "Stream error";
237
http_response_parse_retry_after(const char *hdrval, time_t resp_time,
238
time_t *retry_after_r)
242
/* http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-23
245
The value of this field can be either an HTTP-date or an integer
246
number of seconds (in decimal) after the time of the response.
247
Time spans are non-negative decimal integers, representing time in
250
Retry-After = HTTP-date / delta-seconds
251
delta-seconds = 1*DIGIT
253
if (str_to_time(hdrval, &delta) >= 0) {
254
if (resp_time == (time_t)-1) {
257
*retry_after_r = resp_time + delta;
261
return (http_date_parse
262
((unsigned char *)hdrval, strlen(hdrval), retry_after_r) ? 0 : -1);
265
int http_response_parse_next(struct http_response_parser *parser,
266
enum http_response_payload_type payload_type,
267
struct http_response *response, const char **error_r)
270
time_t retry_after = (time_t)-1;
273
/* make sure we finished streaming payload from previous response
274
before we continue. */
275
if ((ret = http_message_parse_finish_payload(&parser->parser)) <= 0) {
276
*error_r = parser->parser.error;
280
/* HTTP-message = start-line
281
*( header-field CRLF )
285
if (parser->state != HTTP_RESPONSE_PARSE_STATE_HEADER) {
286
if ((ret = http_response_parse_status_line(parser)) <= 0) {
287
*error_r = parser->parser.error;
291
if ((ret = http_message_parse_headers(&parser->parser)) <= 0) {
292
*error_r = parser->parser.error;
296
/* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-21
299
A server MUST NOT send a Content-Length header field in any response
300
with a status code of 1xx (Informational) or 204 (No Content). [...]
302
if ((parser->response_status / 100 == 1 || parser->response_status == 204) &&
303
parser->parser.msg.content_length > 0) {
304
*error_r = t_strdup_printf(
305
"Unexpected Content-Length header field for %u response "
306
"(length=%"PRIuUOFF_T")", parser->response_status,
307
parser->parser.msg.content_length);
311
/* http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-21
314
Any response to a HEAD request and any response with a 1xx
315
(Informational), 204 (No Content), or 304 (Not Modified) status
316
code is always terminated by the first empty line after the
317
header fields, regardless of the header fields present in the
318
message, and thus cannot contain a message body.
320
if (parser->response_status / 100 == 1 || parser->response_status == 204
321
|| parser->response_status == 304) { // HEAD is handled in caller
322
payload_type = HTTP_RESPONSE_PAYLOAD_TYPE_NOT_PRESENT;
325
if ((payload_type == HTTP_RESPONSE_PAYLOAD_TYPE_ALLOWED) ||
326
(payload_type == HTTP_RESPONSE_PAYLOAD_TYPE_ONLY_UNSUCCESSFUL &&
327
parser->response_status / 100 != 2)) {
328
/* [ message-body ] */
329
if (http_message_parse_body(&parser->parser, FALSE) < 0) {
330
*error_r = parser->parser.error;
335
/* http://tools.ietf.org/html/draft-ietf-httpbis-p2-semantics-23
338
Servers send the "Retry-After" header field to indicate how long the
339
user agent ought to wait before making a follow-up request. When
340
sent with a 503 (Service Unavailable) response, Retry-After indicates
341
how long the service is expected to be unavailable to the client.
342
When sent with any 3xx (Redirection) response, Retry-After indicates
343
the minimum time that the user agent is asked to wait before issuing
344
the redirected request.
346
if (parser->response_status == 503 || (parser->response_status / 100) == 3) {
347
hdrval = http_header_field_get(parser->parser.msg.header, "Retry-After");
348
if (hdrval != NULL) {
349
(void)http_response_parse_retry_after
350
(hdrval, parser->parser.msg.date, &retry_after);
351
/* broken Retry-After header is ignored */
355
parser->state = HTTP_RESPONSE_PARSE_STATE_INIT;
357
memset(response, 0, sizeof(*response));
358
response->status = parser->response_status;
359
response->reason = parser->response_reason;
360
response->version_major = parser->parser.msg.version_major;
361
response->version_minor = parser->parser.msg.version_minor;
362
response->location = parser->parser.msg.location;
363
response->date = parser->parser.msg.date;
364
response->retry_after = retry_after;
365
response->payload = parser->parser.payload;
366
response->header = parser->parser.msg.header;
367
response->headers = *http_header_get_fields(response->header); /* FIXME: remove in v2.3 */
368
response->connection_options = parser->parser.msg.connection_options;
369
response->connection_close = parser->parser.msg.connection_close;