1 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "str.h"
5 #include "istream.h"
6 #include "http-parser.h"
7 #include "http-date.h"
8 #include "http-message-parser.h"
9 #include "http-response-parser.h"
10 
11 #include <ctype.h>
12 
13 enum http_response_parser_state {
14 	HTTP_RESPONSE_PARSE_STATE_INIT = 0,
15 	HTTP_RESPONSE_PARSE_STATE_VERSION,
16 	HTTP_RESPONSE_PARSE_STATE_SP1,
17 	HTTP_RESPONSE_PARSE_STATE_STATUS,
18 	HTTP_RESPONSE_PARSE_STATE_SP2,
19 	HTTP_RESPONSE_PARSE_STATE_REASON,
20 	HTTP_RESPONSE_PARSE_STATE_CR,
21 	HTTP_RESPONSE_PARSE_STATE_LF,
22 	HTTP_RESPONSE_PARSE_STATE_HEADER
23 };
24 
25 struct http_response_parser {
26 	struct http_message_parser parser;
27 	enum http_response_parser_state state;
28 
29 	unsigned int response_status;
30 	const char *response_reason;
31 
32 	uoff_t response_offset;
33 };
34 
35 struct http_response_parser *
http_response_parser_init(struct istream * input,const struct http_header_limits * hdr_limits,enum http_response_parse_flags flags)36 http_response_parser_init(struct istream *input,
37 	const struct http_header_limits *hdr_limits,
38 	enum http_response_parse_flags flags)
39 {
40 	struct http_response_parser *parser;
41 	enum http_message_parse_flags msg_flags = 0;
42 
43 	/* FIXME: implement status line limit */
44 	if ((flags & HTTP_RESPONSE_PARSE_FLAG_STRICT) != 0)
45 		msg_flags |= HTTP_MESSAGE_PARSE_FLAG_STRICT;
46 	parser = i_new(struct http_response_parser, 1);
47 	http_message_parser_init(&parser->parser,
48 		input, hdr_limits, 0, msg_flags);
49 	return parser;
50 }
51 
http_response_parser_deinit(struct http_response_parser ** _parser)52 void http_response_parser_deinit(struct http_response_parser **_parser)
53 {
54 	struct http_response_parser *parser = *_parser;
55 
56 	*_parser = NULL;
57 
58 	http_message_parser_deinit(&parser->parser);
59 	i_free(parser);
60 }
61 
62 static void
http_response_parser_restart(struct http_response_parser * parser)63 http_response_parser_restart(struct http_response_parser *parser)
64 {
65 	http_message_parser_restart(&parser->parser, NULL);
66 	parser->response_status = 0;
67 	parser->response_reason = NULL;
68 	parser->response_offset = UOFF_T_MAX;
69 }
70 
http_response_parse_status(struct http_response_parser * parser)71 static int http_response_parse_status(struct http_response_parser *parser)
72 {
73 	const unsigned char *p = parser->parser.cur;
74 	const size_t size = parser->parser.end - parser->parser.cur;
75 
76 	/* status-code   = 3DIGIT
77 	 */
78 	if (size < 3)
79 		return 0;
80 	if (!i_isdigit(p[0]) || !i_isdigit(p[1]) || !i_isdigit(p[2]))
81 		return -1;
82 	parser->response_status =
83 		(p[0] - '0')*100 + (p[1] - '0')*10 + (p[2] - '0');
84 	if (parser->response_status < 100 ||
85 		parser->response_status >= 600)
86 		return -1;
87 	parser->parser.cur += 3;
88 	return 1;
89 }
90 
http_response_parse_reason(struct http_response_parser * parser)91 static int http_response_parse_reason(struct http_response_parser *parser)
92 {
93 	const unsigned char *p = parser->parser.cur;
94 	pool_t pool;
95 
96 	/* reason-phrase = *( HTAB / SP / VCHAR / obs-text )
97 	 */
98 	// FIXME: limit length
99 	while (p < parser->parser.end && http_char_is_text(*p))
100 		p++;
101 
102 	if (p == parser->parser.end)
103 		return 0;
104 	pool = http_message_parser_get_pool(&parser->parser);
105 	parser->response_reason =
106 		p_strdup_until(pool, parser->parser.cur, p);
107 	parser->parser.cur = p;
108 	return 1;
109 }
110 
_reply_sanitize(struct http_message_parser * parser)111 static const char *_reply_sanitize(struct http_message_parser *parser)
112 {
113 	string_t *str = t_str_new(32);
114 	const unsigned char *p;
115 	unsigned int i;
116 	bool quote_open = FALSE;
117 
118 	i_assert(parser->cur < parser->end);
119 	for (p = parser->cur, i = 0; p < parser->end && i < 20; p++, i++) {
120 		if (*p >= 0x20 && *p < 0x7F) {
121 			if (!quote_open) {
122 				str_append_c(str, '`');
123 				quote_open = TRUE;
124 			}
125 			str_append_c(str, *p);
126 		} else {
127 			if (quote_open) {
128 				str_append_c(str, '\'');
129 				quote_open = FALSE;
130 			}
131 			if (*p == 0x0a)
132 				str_append(str, "<LF>");
133 			else if (*p == 0x0d)
134 				str_append(str, "<CR>");
135 			else
136 				str_printfa(str, "<0x%02x>", *p);
137 		}
138 	}
139 	if (quote_open)
140 		str_append_c(str, '\'');
141 	return str_c(str);
142 }
143 
http_response_parse(struct http_response_parser * parser)144 static int http_response_parse(struct http_response_parser *parser)
145 {
146 	struct http_message_parser *_parser = &parser->parser;
147 	int ret;
148 
149 	/* RFC 7230, Section 3.1.2: Status Line
150 
151 	   status-line   = HTTP-version SP status-code SP reason-phrase CRLF
152 	   status-code   = 3DIGIT
153 	   reason-phrase = *( HTAB / SP / VCHAR / obs-text )
154 	 */
155 	switch (parser->state) {
156 	case HTTP_RESPONSE_PARSE_STATE_INIT:
157 		parser->state = HTTP_RESPONSE_PARSE_STATE_VERSION;
158 		parser->response_offset = _parser->input->v_offset +
159 			(_parser->cur - _parser->begin);
160 		/* fall through */
161 	case HTTP_RESPONSE_PARSE_STATE_VERSION:
162 		if ((ret=http_message_parse_version(_parser)) <= 0) {
163 			if (ret < 0)
164 				_parser->error = t_strdup_printf(
165 					"Invalid HTTP version in response: %s",
166 					_reply_sanitize(_parser));
167 			return ret;
168 		}
169 		parser->state = HTTP_RESPONSE_PARSE_STATE_SP1;
170 		if (_parser->cur == _parser->end)
171 			return 0;
172 		/* fall through */
173 	case HTTP_RESPONSE_PARSE_STATE_SP1:
174 		if (*_parser->cur != ' ') {
175 			_parser->error = t_strdup_printf
176 				("Expected ' ' after response version, but found %s",
177 					_reply_sanitize(_parser));
178 			return -1;
179 		}
180 		_parser->cur++;
181 		parser->state = HTTP_RESPONSE_PARSE_STATE_STATUS;
182 		if (_parser->cur >= _parser->end)
183 			return 0;
184 		/* fall through */
185 	case HTTP_RESPONSE_PARSE_STATE_STATUS:
186 		if ((ret=http_response_parse_status(parser)) <= 0) {
187 			if (ret < 0)
188 				_parser->error = "Invalid HTTP status code in response";
189 			return ret;
190 		}
191 		parser->state = HTTP_RESPONSE_PARSE_STATE_SP2;
192 		if (_parser->cur == _parser->end)
193 			return 0;
194 		/* fall through */
195 	case HTTP_RESPONSE_PARSE_STATE_SP2:
196 		if (*_parser->cur != ' ') {
197 			_parser->error = t_strdup_printf
198 				("Expected ' ' after response status code, but found %s",
199 					_reply_sanitize(_parser));
200 			return -1;
201 		}
202 		_parser->cur++;
203 		parser->state = HTTP_RESPONSE_PARSE_STATE_REASON;
204 		if (_parser->cur >= _parser->end)
205 			return 0;
206 		/* fall through */
207 	case HTTP_RESPONSE_PARSE_STATE_REASON:
208 		if ((ret=http_response_parse_reason(parser)) <= 0) {
209 			i_assert(ret == 0);
210 			return 0;
211 		}
212 		parser->state = HTTP_RESPONSE_PARSE_STATE_CR;
213 		if (_parser->cur == _parser->end)
214 			return 0;
215 		/* fall through */
216 	case HTTP_RESPONSE_PARSE_STATE_CR:
217 		if (*_parser->cur == '\r')
218 			_parser->cur++;
219 		parser->state = HTTP_RESPONSE_PARSE_STATE_LF;
220 		if (_parser->cur == _parser->end)
221 			return 0;
222 		/* fall through */
223 	case HTTP_RESPONSE_PARSE_STATE_LF:
224 		if (*_parser->cur != '\n') {
225 			_parser->error = t_strdup_printf
226 				("Expected line end after response, but found %s",
227 					_reply_sanitize(_parser));
228 			return -1;
229 		}
230 		_parser->cur++;
231 		parser->state = HTTP_RESPONSE_PARSE_STATE_HEADER;
232 		return 1;
233 	case HTTP_RESPONSE_PARSE_STATE_HEADER:
234 	default:
235 		break;
236 	}
237 
238 	i_unreached();
239 	return -1;
240 }
241 
242 static int
http_response_parse_status_line(struct http_response_parser * parser)243 http_response_parse_status_line(struct http_response_parser *parser)
244 {
245 	struct http_message_parser *_parser = &parser->parser;
246 	const unsigned char *begin;
247 	size_t size, old_bytes = 0;
248 	int ret;
249 
250 	while ((ret = i_stream_read_bytes(_parser->input, &begin, &size,
251 					  old_bytes + 1)) > 0) {
252 		_parser->begin = _parser->cur = begin;
253 		_parser->end = _parser->begin + size;
254 
255 		if ((ret = http_response_parse(parser)) < 0)
256 			return -1;
257 
258 		i_stream_skip(_parser->input, _parser->cur - begin);
259 		if (ret > 0)
260 			return 1;
261 		old_bytes = i_stream_get_data_size(_parser->input);
262 	}
263 
264 	if (ret == -2) {
265 		_parser->error = "HTTP status line is too long";
266 		return -1;
267 	}
268 	if (ret < 0) {
269 		if (_parser->input->eof &&
270 		    parser->state == HTTP_RESPONSE_PARSE_STATE_INIT)
271 			return 0;
272 		_parser->error = t_strdup_printf("Stream error: %s",
273 			i_stream_get_error(_parser->input));
274 		return -1;
275 	}
276 	return 0;
277 }
278 
279 static int
http_response_parse_retry_after(const char * hdrval,time_t resp_time,time_t * retry_after_r)280 http_response_parse_retry_after(const char *hdrval, time_t resp_time,
281 	time_t *retry_after_r)
282 {
283 	time_t delta;
284 
285 	/* RFC 7231, Section 7.1.3: Retry-After
286 
287 	   The value of this field can be either an HTTP-date or a number of
288 	   seconds to delay after the response is received.
289 
290 	     Retry-After = HTTP-date / delta-seconds
291 
292 	   A delay-seconds value is a non-negative decimal integer, representing
293 	   time in seconds.
294 
295        delta-seconds  = 1*DIGIT
296 	 */
297 	if (str_to_time(hdrval, &delta) >= 0) {
298 		if (resp_time == (time_t)-1) {
299 			return -1;
300 		}
301 		*retry_after_r = resp_time + delta;
302 		return 0;
303 	}
304 
305 	return (http_date_parse
306 		((const unsigned char *)hdrval, strlen(hdrval), retry_after_r) ? 0 : -1);
307 }
308 
http_response_parser_get_last_offset(struct http_response_parser * parser)309 uoff_t http_response_parser_get_last_offset(struct http_response_parser *parser)
310 {
311 	return parser->response_offset;
312 }
313 
http_response_parse_next(struct http_response_parser * parser,enum http_response_payload_type payload_type,struct http_response * response,const char ** error_r)314 int http_response_parse_next(struct http_response_parser *parser,
315 			     enum http_response_payload_type payload_type,
316 			     struct http_response *response, const char **error_r)
317 {
318 	const char *hdrval;
319 	time_t retry_after = (time_t)-1;
320 	int ret;
321 
322 	i_zero(response);
323 
324 	/* make sure we finished streaming payload from previous response
325 	   before we continue. */
326 	if ((ret = http_message_parse_finish_payload(&parser->parser)) <= 0) {
327 		*error_r = parser->parser.error;
328 		return ret;
329 	}
330 
331 	if (parser->state == HTTP_RESPONSE_PARSE_STATE_INIT)
332 		http_response_parser_restart(parser);
333 
334 	/* RFC 7230, Section 3:
335 
336 	   HTTP-message   = start-line
337 	                   *( header-field CRLF )
338 	                    CRLF
339 	                    [ message-body ]
340 	 */
341 	if (parser->state != HTTP_RESPONSE_PARSE_STATE_HEADER) {
342 		if ((ret = http_response_parse_status_line(parser)) <= 0) {
343 			*error_r = parser->parser.error;
344 			return ret;
345 		}
346 	}
347 	if ((ret = http_message_parse_headers(&parser->parser)) <= 0) {
348 		*error_r = parser->parser.error;
349 		return ret;
350 	}
351 
352 	/* RFC 7230, Section 3.3.2: Content-Length
353 
354 	   A server MUST NOT send a Content-Length header field in any response
355 	   with a status code of 1xx (Informational) or 204 (No Content).
356 	 */
357 	if ((parser->response_status / 100 == 1 || parser->response_status == 204) &&
358 	    parser->parser.msg.content_length > 0) {
359 		*error_r = t_strdup_printf(
360 			"Unexpected Content-Length header field for %u response "
361 			"(length=%"PRIuUOFF_T")", parser->response_status,
362 			parser->parser.msg.content_length);
363 		return -1;
364 	}
365 
366 	/* RFC 7230, Section 3.3.3: Message Body Length
367 
368 	   1.  Any response to a HEAD request and any response with a 1xx
369 	       (Informational), 204 (No Content), or 304 (Not Modified) status
370 	       code is always terminated by the first empty line after the
371 	       header fields, regardless of the header fields present in the
372 	       message, and thus cannot contain a message body.
373 	 */
374 	if (parser->response_status / 100 == 1 || parser->response_status == 204
375 		|| parser->response_status == 304) { // HEAD is handled in caller
376 		payload_type = HTTP_RESPONSE_PAYLOAD_TYPE_NOT_PRESENT;
377 	}
378 
379 	if ((payload_type == HTTP_RESPONSE_PAYLOAD_TYPE_ALLOWED) ||
380 		(payload_type == HTTP_RESPONSE_PAYLOAD_TYPE_ONLY_UNSUCCESSFUL &&
381 			parser->response_status / 100 != 2)) {
382 		/* [ message-body ] */
383 		if (http_message_parse_body(&parser->parser, FALSE) < 0) {
384 			*error_r = parser->parser.error;
385  			return -1;
386 		}
387 	}
388 
389 	/* RFC 7231, Section 7.1.3: Retry-After
390 
391 	   Servers send the "Retry-After" header field to indicate how long the
392 	   user agent ought to wait before making a follow-up request.  When
393 	   sent with a 503 (Service Unavailable) response, Retry-After indicates
394 	   how long the service is expected to be unavailable to the client.
395 	   When sent with any 3xx (Redirection) response, Retry-After indicates
396 	   the minimum time that the user agent is asked to wait before issuing
397 	   the redirected request.
398 	 */
399 	if (parser->response_status == 503 || (parser->response_status / 100) == 3) {
400 		hdrval = http_header_field_get(parser->parser.msg.header, "Retry-After");
401 		if (hdrval != NULL) {
402 			(void)http_response_parse_retry_after
403 				(hdrval, parser->parser.msg.date, &retry_after);
404 			/* broken Retry-After header is ignored */
405 		}
406 	}
407 
408 	parser->state = HTTP_RESPONSE_PARSE_STATE_INIT;
409 
410 	response->status = parser->response_status;
411 	response->reason = parser->response_reason;
412 	response->version_major = parser->parser.msg.version_major;
413 	response->version_minor = parser->parser.msg.version_minor;
414 	response->location = parser->parser.msg.location;
415 	response->date = parser->parser.msg.date;
416 	response->retry_after = retry_after;
417 	response->payload = parser->parser.payload;
418 	response->header = parser->parser.msg.header;
419 	response->connection_options = parser->parser.msg.connection_options;
420 	response->connection_close = parser->parser.msg.connection_close;
421 	return 1;
422 }
423