/* Copyright (c) 2013-2018 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>
/*
* Test: valid requests
*/
struct http_request_valid_parse_test {
const char *request;
const char *method;
const char *target_raw;
struct {
} target;
unsigned char version_major;
unsigned char version_minor;
const char *payload;
bool connection_close;
bool expect_100_continue;
};
static const struct http_request_valid_parse_test
{ .request =
"GET / HTTP/1.1\r\n"
"Host: example.com\r\n"
"\r\n",
.method = "GET",
.target_raw = "/",
.target = {
},
},{ .request =
"OPTIONS * HTTP/1.0\r\n"
"Host: example.com\r\n"
"Connection: Keep-Alive\r\n"
"\r\n",
.method = "OPTIONS",
.target_raw = "*",
.target = {
},
},{ .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 = {
.url = {
.port = 443 }
},
},{ .request =
"GET https://www.example.com:443 HTTP/1.1\r\n"
"Host: www.example.com:80\r\n"
"\r\n",
.method = "GET",
.target = {
.url = {
.port = 443,
}
},
},{ .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 = {
.url = {
.port = 8080 }
},
.payload = "Content!\r\n"
},{ .request =
"GET http://www.example.com/index.php?seq=1 HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"Connection: close\r\n"
"\r\n",
.method = "GET",
.target = {
.url = {
},
},{ .request =
"GET http://www.example.com/index.html HTTP/1.0\r\n"
"Host: www.example.com\r\n"
"\r\n",
.method = "GET",
.target = {
},
},{ .request =
"GET http://www.example.com/index.html HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"Expect: 100-continue\r\n"
"\r\n",
.method = "GET",
.target = {
},
},{ .request =
"GET / HTTP/1.1\r\n"
"Date: Mon, 09 Kul 2018 02:24:29 GMT\r\n"
"Host: example.com\r\n"
"\r\n",
.method = "GET",
.target_raw = "/",
.target = {
},
},{ .request =
"GET / HTTP/1.1\r\n"
"Date: Sun, 07 Oct 2012 19:52:03 GMT\r\n"
"Host: example.com\r\n"
"Date: Sun, 13 Oct 2013 13:13:13 GMT\r\n"
"\r\n",
.method = "GET",
.target_raw = "/",
.target = {
},
}
};
static const unsigned int valid_request_parse_test_count =
static const char *
{
switch (target_format) {
return "origin";
return "absolute";
return "authority";
return "asterisk";
}
}
static void test_http_request_parse_valid(void)
{
unsigned int i;
for (i = 0; i < valid_request_parse_test_count; i++) T_BEGIN {
int ret = 0;
test = &valid_request_parse_tests[i];
}
while (ret > 0) {
test_out("payload receive",
} else {
}
}
if (ret == 0) {
/* verify last request only */
} else {
}
} else {
}
test_out("request->target.url = (null)",
} else {
} else {
}
test_out("request->target.url->port = (unspecified)",
} else {
}
}
} else {
}
}
test_end();
} T_END;
}
/*
* Test: invalid requests
*/
struct http_request_invalid_parse_test {
const char *request;
};
static const struct http_request_invalid_parse_test
{ .request =
"GET: / HTTP/1.1\r\n"
"Host: example.com\r\n"
"\r\n",
},{ .request =
"GET % HTTP/1.1\r\n"
"Host: example.com\r\n"
"\r\n",
},{ .request =
"GET /frop\" HTTP/1.1\r\n"
"Host: example.com\r\n"
"\r\n",
},{ .request =
"GET / HTCPCP/1.0\r\n"
"Host: example.com\r\n"
"\r\n",
},{ .request =
"GET / HTTP/1.0.1\r\n"
"Host: example.com\r\n"
"\r\n",
},{ .request =
"GET / HTTP/1.1\r\n"
"Host: \"example.com\r\n"
"\r\n",
},{ .request =
"GET / HTTP/1.1\r\n"
"\r\n",
},{ .request =
"GET / HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"Transfer-Encoding: gzip\r\n"
"\r\n",
},{ .request =
"GET / HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"Expect: payment\r\n"
"\r\n",
},{ .request =
"GET / HTTP/1.1\r\n"
"Host: www.example.com\r\n"
"Transfer-Encoding: cuneiform, chunked\r\n"
"\r\n",
},{
.request =
"GET / HTTP/1.1\r\n"
"Date: Mon, 09 Kul 2018 02:24:29 GMT\r\n"
"Host: example.com\r\n"
"\r\n",
},{
.request =
"GET / HTTP/1.1\r\n"
"Date: Sun, 07 Oct 2012 19:52:03 GMT\r\n"
"Host: example.com\r\n"
"Date: Sun, 13 Oct 2013 13:13:13 GMT\r\n"
"\r\n",
}
// FIXME: test request limits
};
static unsigned int invalid_request_parse_test_count =
static const char *
{
switch (error) {
return "none?!";
return "broken stream";
return "broken request";
return "bad request";
return "not implemented";
return "expectation failed";
return "method too long";
return "target too long";
return "payload too large";
}
}
static void test_http_request_parse_invalid(void)
{
int ret;
unsigned int i;
for (i = 0; i < invalid_request_parse_test_count; i++) T_BEGIN {
test = &invalid_request_parse_tests[i];
while ((ret=http_request_parse_next
if (ret < 0) {
}
test_end();
} T_END;
}
/*
* Bad request tests
*/
static const unsigned char bad_request_with_nuls[] =
"GET / HTTP/1.1\r\n"
"Host: example.com\r\n"
"User-Agent: text\0client\r\n"
"\r\n";
static void test_http_request_parse_bad(void)
{
int ret;
/* parse failure guarantees http_request_header.size equals
strlen(http_request_header.value) */
test_begin("http request with NULs (strict)");
sizeof(bad_request_with_nuls)-1);
while ((ret=http_request_parse_next
test_assert(ret < 0);
test_end();
/* even when lenient, bad characters like NUL must not be returned */
test_begin("http request with NULs (lenient)");
sizeof(bad_request_with_nuls)-1);
}
test_end();
}
int main(void)
{
static void (*const test_functions[])(void) = {
};
return test_run(test_functions);
}