Mercurial > dovecot > original-hg > dovecot-2.2
changeset 16768:b92118278b06
lib-http: Created tests for http_request_parser.
author | Stephan Bosch <stephan@rename-it.nl> |
---|---|
date | Wed, 18 Sep 2013 23:24:30 +0300 |
parents | 9bf25c18ad33 |
children | 827ebbf9da5f |
files | src/lib-http/Makefile.am src/lib-http/test-http-request-parser.c |
diffstat | 2 files changed, 287 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-http/Makefile.am Wed Sep 18 23:24:22 2013 +0300 +++ b/src/lib-http/Makefile.am Wed Sep 18 23:24:30 2013 +0300 @@ -47,7 +47,8 @@ test-http-url \ test-http-header-parser \ test-http-transfer \ - test-http-response-parser + test-http-response-parser \ + test-http-request-parser test_nocheck_programs = \ test-http-client \ @@ -97,6 +98,20 @@ $(test_libs) test_http_response_parser_DEPENDENCIES = $(test_deps) +test_http_request_parser_SOURCES = test-http-request-parser.c +test_http_request_parser_LDADD = \ + http-date.lo \ + http-parser.lo \ + http-url.lo \ + http-header.lo \ + http-header-parser.lo \ + http-transfer-chunked.lo \ + http-message-parser.lo \ + http-request-parser.lo \ + $(test_libs) +test_http_request_parser_DEPENDENCIES = $(test_deps) + + test_http_client_SOURCES = test-http-client.c test_http_client_LDFLAGS = -export-dynamic test_http_client_LDADD = \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-http/test-http-request-parser.c Wed Sep 18 23:24:30 2013 +0300 @@ -0,0 +1,271 @@ +/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "buffer.h" +#include "str.h" +#include "str-sanitize.h" +#include "istream.h" +#include "ostream.h" +#include "test-common.h" +#include "http-url.h" +#include "http-request-parser.h" + +#include <time.h> + +struct http_request_parse_test { + const char *request; + const char *method; + const char *target_raw; + struct http_request_target target; + unsigned char version_major; + unsigned char version_minor; + uoff_t content_length; + const char *payload; +}; + +/* Valid header tests */ + +static const struct http_request_parse_test +valid_request_parse_tests[] = { + { .request = + "GET / HTTP/1.1\r\n" + "Host: example.com\r\n" + "\r\n", + .method = "GET", + .target_raw = "/", + .target = { + .format = HTTP_REQUEST_TARGET_FORMAT_ORIGIN + }, + .version_major = 1, .version_minor = 1, + },{ .request = + "OPTIONS * HTTP/1.0\r\n" + "Host: example.com\r\n" + "\r\n", + .method = "OPTIONS", + .target_raw = "*", + .target = { + .format = HTTP_REQUEST_TARGET_FORMAT_ASTERISK + }, + .version_major = 1, .version_minor = 0, + },{ .request = + "CONNECT example.com:443 HTTP/1.2\r\n" + "Host: example.com:443\r\n" + "\r\n", + .method = "CONNECT", + .target_raw = "example.com:443", + .target = { + .format = HTTP_REQUEST_TARGET_FORMAT_AUTHORITY + }, + .version_major = 1, .version_minor = 2, + },{ .request = + "GET https://www.example.com:443 HTTP/1.1\r\n" + "Host: www.example.com:80\r\n" + "\r\n", + .method = "GET", + .target_raw = "https://www.example.com:443", + .target = { + .format = HTTP_REQUEST_TARGET_FORMAT_ABSOLUTE + }, + .version_major = 1, .version_minor = 1, + },{ .request = + "POST http://api.example.com:8080/commit?user=dirk HTTP/1.1\r\n" + "Host: api.example.com:8080\r\n" + "Content-Length: 10\r\n" + "\r\n" + "Content!\r\n", + .method = "POST", + .target_raw = "http://api.example.com:8080/commit?user=dirk", + .target = { + .format = HTTP_REQUEST_TARGET_FORMAT_ABSOLUTE, + }, + .version_major = 1, .version_minor = 1, + .payload = "Content!\r\n" + } +}; + +unsigned int valid_request_parse_test_count = + N_ELEMENTS(valid_request_parse_tests); + +static const char * +_request_target_format(enum http_request_target_format target_format) +{ + switch (target_format) { + case HTTP_REQUEST_TARGET_FORMAT_ORIGIN: + return "origin"; + case HTTP_REQUEST_TARGET_FORMAT_ABSOLUTE: + return "absolute"; + case HTTP_REQUEST_TARGET_FORMAT_AUTHORITY: + return "authority"; + case HTTP_REQUEST_TARGET_FORMAT_ASTERISK: + return "asterisk"; + } + return t_strdup_printf("<<UNKNOWN: %u>>", target_format); +} + +static void test_http_request_parse_valid(void) +{ + unsigned int i; + buffer_t *payload_buffer = buffer_create_dynamic(default_pool, 1024); + + for (i = 0; i < valid_request_parse_test_count; i++) T_BEGIN { + struct istream *input; + struct ostream *output; + const struct http_request_parse_test *test; + struct http_request_parser *parser; + struct http_request request; + enum http_request_parse_error error_code; + const char *request_text, *payload, *error; + unsigned int pos, request_text_len; + int ret = 0; + + test = &valid_request_parse_tests[i]; + request_text = test->request; + request_text_len = strlen(request_text); + input = test_istream_create_data(request_text, request_text_len); + parser = http_request_parser_init(input, NULL); + + test_begin(t_strdup_printf("http request valid [%d]", i)); + + payload = NULL; + for (pos = 0; pos <= request_text_len && ret == 0; pos++) { + test_istream_set_size(input, pos); + ret = http_request_parse_next + (parser, FALSE, &request, &error_code, &error); + } + test_istream_set_size(input, request_text_len); + while (ret > 0) { + if (request.payload != NULL) { + buffer_set_used_size(payload_buffer, 0); + output = o_stream_create_buffer(payload_buffer); + test_out("payload receive", + o_stream_send_istream(output, request.payload)); + o_stream_destroy(&output); + payload = str_c(payload_buffer); + } else { + payload = NULL; + } + ret = http_request_parse_next + (parser, FALSE, &request, &error_code, &error); + } + + test_out_reason("parse success", ret == 0, error); + + if (ret == 0) { + /* verify last request only */ + if (request.method == NULL || test->method == NULL) { + test_out(t_strdup_printf("request->method = %s", test->method), + request.method == test->method); + } else { + test_out(t_strdup_printf("request->method = %s", test->method), + strcmp(request.method, test->method) == 0); + } + if (request.target_raw == NULL || test->target_raw == NULL) { + test_out(t_strdup_printf("request->target = %s", test->target_raw), + request.target_raw == test->target_raw); + } else { + test_out(t_strdup_printf("request->target = %s", test->target_raw), + strcmp(request.target_raw, test->target_raw) == 0); + } + test_out(t_strdup_printf("request->target_format = %s", + _request_target_format(test->target.format)), + request.target.format == test->target.format); + test_out(t_strdup_printf("request->version = %d.%d", + test->version_major, test->version_minor), + request.version_major == test->version_major && + request.version_minor == test->version_minor); + if (payload == NULL || test->payload == NULL) { + test_out(t_strdup_printf("request->payload = %s", + str_sanitize(payload, 80)), + payload == test->payload); + } else { + test_out(t_strdup_printf("request->payload = %s", + str_sanitize(payload, 80)), + strcmp(payload, test->payload) == 0); + } + } + test_end(); + http_request_parser_deinit(&parser); + } T_END; + + buffer_free(&payload_buffer); +} + +static const char *invalid_request_parse_tests[] = { + "GET: / HTTP/1.1\r\n" + "Host: example.com\r\n" + "\r\n", + "GET % HTTP/1.1\r\n" + "Host: example.com\r\n" + "\r\n", + "GET /frop\" HTTP/1.1\r\n" + "Host: example.com\r\n" + "\r\n", + "GET / HTCPCP/1.0\r\n" + "Host: example.com\r\n" + "\r\n", + "GET / HTTP/1.0.1\r\n" + "Host: example.com\r\n" + "\r\n", + "GET / HTTP/1.1\r\n" + "Host: \"example.com\r\n" + "\r\n", +}; + +static unsigned char invalid_request_with_nuls[] = + "GET / HTTP/1.1\r\n" + "Host: example.com\r\n" + "Null: text\0server\r\n" + "\r\n"; + +unsigned int invalid_request_parse_test_count = + N_ELEMENTS(invalid_request_parse_tests); + +static void test_http_request_parse_invalid(void) +{ + struct http_request_parser *parser; + struct http_request request; + enum http_request_parse_error error_code; + const char *request_text, *error; + struct istream *input; + int ret; + unsigned int i; + + for (i = 0; i < invalid_request_parse_test_count; i++) T_BEGIN { + const char *test; + + test = invalid_request_parse_tests[i]; + request_text = test; + input = i_stream_create_from_data(request_text, strlen(request_text)); + parser = http_request_parser_init(input, NULL); + + test_begin(t_strdup_printf("http request invalid [%d]", i)); + + while ((ret=http_request_parse_next + (parser, FALSE, &request, &error_code, &error)) > 0); + + test_out_reason("parse failure", ret < 0, error); + test_end(); + http_request_parser_deinit(&parser); + } T_END; + + /* parse failure guarantees http_request_header.size equals + strlen(http_request_header.value) */ + test_begin("http request with NULs"); + input = i_stream_create_from_data(invalid_request_with_nuls, + sizeof(invalid_request_with_nuls)-1); + parser = http_request_parser_init(input, 0); + while ((ret=http_request_parse_next + (parser, FALSE, &request, &error_code, &error)) > 0); + test_assert(ret < 0); + test_end(); +} + +int main(void) +{ + static void (*test_functions[])(void) = { + test_http_request_parse_valid, + test_http_request_parse_invalid, + NULL + }; + return test_run(test_functions); +}