mirror of
https://github.com/cesanta/mongoose.git
synced 2026-11-01 13:10:43 +00:00
Removed mg_connect() and mg_fetch(). Added mg_download()
This commit is contained in:
1 parent
179761fd99
commit
75d9a6c844
4 files changed
+255
-220
No files matched your search
+7
-8
@@ -167,7 +167,7 @@ kill_spawned_child();
|
||||
|
||||
# Spawn the server on port $port
|
||||
my $cmd = "$exe ".
|
||||
"-listening_ports $port ".
|
||||
"-listening_ports 127.0.0.1:$port ".
|
||||
"-access_log_file access.log ".
|
||||
"-error_log_file debug.log ".
|
||||
"-cgi_environment CGI_FOO=foo,CGI_BAR=bar,CGI_BAZ=baz " .
|
||||
@@ -220,11 +220,10 @@ write_file("$root/a+.txt", '');
|
||||
o("GET /a+.txt HTTP/1.0\n\n", 'HTTP/1.1 200 OK', 'URL-decoding, + in URI');
|
||||
|
||||
# Test HTTP version parsing
|
||||
o("GET / HTTPX/1.0\r\n\r\n", '400 Bad Request', 'Bad HTTP Version', 0);
|
||||
o("GET / HTTP/x.1\r\n\r\n", '505 HTTP', 'Bad HTTP maj Version');
|
||||
o("GET / HTTP/1.1z\r\n\r\n", '505 HTTP', 'Bad HTTP min Version');
|
||||
o("GET / HTTP/02.0\r\n\r\n", '505 HTTP version not supported',
|
||||
'HTTP Version >1.1');
|
||||
o("GET / HTTPX/1.0\r\n\r\n", '^HTTP/1.1 500', 'Bad HTTP Version', 0);
|
||||
o("GET / HTTP/x.1\r\n\r\n", '^HTTP/1.1 505', 'Bad HTTP maj Version', 0);
|
||||
o("GET / HTTP/1.1z\r\n\r\n", '^HTTP/1.1 505', 'Bad HTTP min Version', 0);
|
||||
o("GET / HTTP/02.0\r\n\r\n", '^HTTP/1.1 505', 'HTTP Version >1.1', 0);
|
||||
|
||||
# File with leading single dot
|
||||
o("GET /.leading.dot.txt HTTP/1.0\n\n", 'abc123', 'Leading dot 1');
|
||||
@@ -463,7 +462,7 @@ sub do_unit_test {
|
||||
|
||||
sub do_embedded_test {
|
||||
my $cmd = "cc -W -Wall -o $embed_exe $root/embed.c mongoose.c -I. ".
|
||||
"-pthread -DNO_SSL -DLISTENING_PORT=\\\"$port\\\"";
|
||||
"-pthread -DNO_SSL -DLISTENING_PORT=\\\"127.0.0.1:$port\\\"";
|
||||
if (on_windows()) {
|
||||
$cmd = "cl $root/embed.c mongoose.c /I. /nologo /DNO_SSL ".
|
||||
"/DLISTENING_PORT=\\\"$port\\\" /link /out:$embed_exe.exe ws2_32.lib ";
|
||||
@@ -514,7 +513,7 @@ sub do_embedded_test {
|
||||
'Remote user: \[\]'
|
||||
, 'request_info', 0);
|
||||
o("GET /not_exist HTTP/1.0\n\n", 'Error: \[404\]', '404 handler', 0);
|
||||
o("bad request\n\n", 'Error: \[400\]', '* error handler', 0);
|
||||
o("bad request\n\n", 'Error: \[500\]', '* error handler', 0);
|
||||
# o("GET /foo/secret HTTP/1.0\n\n",
|
||||
# '401 Unauthorized', 'mg_protect_uri', 0);
|
||||
# o("GET /foo/secret HTTP/1.0\nAuthorization: Digest username=bill\n\n",
|
||||
|
||||
+107
-72
@@ -21,6 +21,7 @@
|
||||
// Unit test for the mongoose web server. Tests embedded API.
|
||||
|
||||
#define USE_WEBSOCKET
|
||||
#define USE_LUA
|
||||
#include "mongoose.c"
|
||||
|
||||
#define FATAL(str, line) do { \
|
||||
@@ -29,24 +30,35 @@
|
||||
} while (0)
|
||||
#define ASSERT(expr) do { if (!(expr)) FATAL(#expr, __LINE__); } while (0)
|
||||
|
||||
#define LISTENING_ADDR "127.0.0.1:56789"
|
||||
#define HTTP_PORT "56789"
|
||||
#define HTTPS_PORT "56790"
|
||||
#define LISTENING_ADDR "127.0.0.1:" HTTP_PORT "r,127.0.0.1:" HTTPS_PORT "s"
|
||||
|
||||
static void test_parse_http_request() {
|
||||
static void test_parse_http_message() {
|
||||
struct mg_request_info ri;
|
||||
char req1[] = "GET / HTTP/1.1\r\n\r\n";
|
||||
char req2[] = "BLAH / HTTP/1.1\r\n\r\n";
|
||||
char req3[] = "GET / HTTP/1.1\r\nBah\r\n";
|
||||
char req4[] = "GET / HTTP/1.1\r\nA: foo bar\r\nB: bar\r\nbaz\r\n\r\n";
|
||||
char req5[] = "GET / HTTP/1.1\r\n\r\n";
|
||||
char req6[] = "G";
|
||||
char req7[] = " blah ";
|
||||
char req8[] = " HTTP/1.1 200 OK \n\n";
|
||||
|
||||
ASSERT(parse_http_request(req1, sizeof(req1), &ri) == sizeof(req1) - 1);
|
||||
ASSERT(parse_http_message(req1, sizeof(req1), &ri) == sizeof(req1) - 1);
|
||||
ASSERT(strcmp(ri.http_version, "1.1") == 0);
|
||||
ASSERT(ri.num_headers == 0);
|
||||
|
||||
ASSERT(parse_http_request(req2, sizeof(req2), &ri) == -1);
|
||||
ASSERT(parse_http_request(req3, sizeof(req3), &ri) == -1);
|
||||
ASSERT(parse_http_message(req2, sizeof(req2), &ri) == -1);
|
||||
ASSERT(parse_http_message(req3, sizeof(req3), &ri) == 0);
|
||||
ASSERT(parse_http_message(req6, sizeof(req6), &ri) == 0);
|
||||
ASSERT(parse_http_message(req7, sizeof(req7), &ri) == 0);
|
||||
ASSERT(parse_http_message("", 0, &ri) == 0);
|
||||
ASSERT(parse_http_message(req8, sizeof(req8), &ri) == sizeof(req8) - 1);
|
||||
|
||||
// TODO(lsm): Fix this. Header value may span multiple lines.
|
||||
ASSERT(parse_http_request(req4, sizeof(req4), &ri) == sizeof(req4) - 1);
|
||||
ASSERT(parse_http_message(req4, sizeof(req4), &ri) == sizeof(req4) - 1);
|
||||
ASSERT(strcmp(ri.http_version, "1.1") == 0);
|
||||
ASSERT(ri.num_headers == 3);
|
||||
ASSERT(strcmp(ri.http_headers[0].name, "A") == 0);
|
||||
ASSERT(strcmp(ri.http_headers[0].value, "foo bar") == 0);
|
||||
@@ -55,7 +67,9 @@ static void test_parse_http_request() {
|
||||
ASSERT(strcmp(ri.http_headers[2].name, "baz\r\n\r") == 0);
|
||||
ASSERT(strcmp(ri.http_headers[2].value, "") == 0);
|
||||
|
||||
// TODO(lsm): add more tests.
|
||||
ASSERT(parse_http_message(req5, sizeof(req5), &ri) == sizeof(req5) - 1);
|
||||
ASSERT(strcmp(ri.request_method, "GET") == 0);
|
||||
ASSERT(strcmp(ri.http_version, "1.1") == 0);
|
||||
}
|
||||
|
||||
static void test_should_keep_alive(void) {
|
||||
@@ -68,7 +82,8 @@ static void test_should_keep_alive(void) {
|
||||
|
||||
memset(&conn, 0, sizeof(conn));
|
||||
conn.ctx = &ctx;
|
||||
parse_http_request(req1, sizeof(req1), &conn.request_info);
|
||||
ASSERT(parse_http_message(req1, sizeof(req1), &conn.request_info) ==
|
||||
sizeof(req1) - 1);
|
||||
|
||||
ctx.config[ENABLE_KEEP_ALIVE] = "no";
|
||||
ASSERT(should_keep_alive(&conn) == 0);
|
||||
@@ -80,13 +95,13 @@ static void test_should_keep_alive(void) {
|
||||
ASSERT(should_keep_alive(&conn) == 0);
|
||||
|
||||
conn.must_close = 0;
|
||||
parse_http_request(req2, sizeof(req2), &conn.request_info);
|
||||
parse_http_message(req2, sizeof(req2), &conn.request_info);
|
||||
ASSERT(should_keep_alive(&conn) == 0);
|
||||
|
||||
parse_http_request(req3, sizeof(req3), &conn.request_info);
|
||||
parse_http_message(req3, sizeof(req3), &conn.request_info);
|
||||
ASSERT(should_keep_alive(&conn) == 0);
|
||||
|
||||
parse_http_request(req4, sizeof(req4), &conn.request_info);
|
||||
parse_http_message(req4, sizeof(req4), &conn.request_info);
|
||||
ASSERT(should_keep_alive(&conn) == 1);
|
||||
|
||||
conn.status_code = 401;
|
||||
@@ -143,7 +158,9 @@ static void test_remove_double_dots() {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(data); i++) {
|
||||
#if 0
|
||||
printf("[%s] -> [%s]\n", data[i].before, data[i].after);
|
||||
#endif
|
||||
remove_double_dots_and_double_slashes(data[i].before);
|
||||
ASSERT(strcmp(data[i].before, data[i].after) == 0);
|
||||
}
|
||||
@@ -162,14 +179,12 @@ static void *event_handler(enum mg_event event, struct mg_connection *conn) {
|
||||
return "";
|
||||
} else if (event == MG_OPEN_FILE) {
|
||||
const char *path = request_info->ev_data;
|
||||
printf("%s: [%s]\n", __func__, path);
|
||||
if (strcmp(path, "./blah") == 0) {
|
||||
mg_get_request_info(conn)->ev_data =
|
||||
(void *) (int) strlen(inmemory_file_data);
|
||||
return (void *) inmemory_file_data;
|
||||
}
|
||||
} else if (event == MG_EVENT_LOG) {
|
||||
printf("%s\n", (const char *) mg_get_request_info(conn)->ev_data);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -178,6 +193,7 @@ static void *event_handler(enum mg_event event, struct mg_connection *conn) {
|
||||
static const char *OPTIONS[] = {
|
||||
"document_root", ".",
|
||||
"listening_ports", LISTENING_ADDR,
|
||||
"ssl_certificate", "build/ssl_cert.pem",
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -187,69 +203,87 @@ static void test_mg_upload(void) {
|
||||
mg_stop(ctx);
|
||||
}
|
||||
|
||||
static void test_mg_fetch(void) {
|
||||
char buf[2000], buf2[2000];
|
||||
int n, length;
|
||||
struct mg_context *ctx;
|
||||
struct mg_request_info ri;
|
||||
const char *tmp_file = "temporary_file_name_for_unit_test.txt";
|
||||
struct file file;
|
||||
static char *read_file(const char *path, int *size) {
|
||||
FILE *fp;
|
||||
struct stat st;
|
||||
char *data = NULL;
|
||||
if ((fp = fopen(path, "r")) != NULL && !fstat(fileno(fp), &st)) {
|
||||
*size = st.st_size;
|
||||
ASSERT((data = malloc(*size)) != NULL);
|
||||
ASSERT(fread(data, 1, *size, fp) == (size_t) *size);
|
||||
fclose(fp);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static char *read_conn(struct mg_connection *conn, int *size) {
|
||||
char buf[100], *data = NULL;
|
||||
int len;
|
||||
*size = 0;
|
||||
while ((len = mg_read(conn, buf, sizeof(buf))) > 0) {
|
||||
*size += len;
|
||||
ASSERT((data = realloc(data, *size)) != NULL);
|
||||
memcpy(data + *size - len, buf, len);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static void test_mg_download(void) {
|
||||
char *p1, *p2, ebuf[100];
|
||||
int len1, len2, port = atoi(HTTPS_PORT);
|
||||
struct mg_connection *conn;
|
||||
struct mg_context *ctx;
|
||||
|
||||
ASSERT((ctx = mg_start(event_handler, NULL, OPTIONS)) != NULL);
|
||||
|
||||
// Failed fetch, pass invalid URL
|
||||
ASSERT(mg_fetch(ctx, "localhost", tmp_file, buf, sizeof(buf), &ri) == NULL);
|
||||
ASSERT(mg_fetch(ctx, LISTENING_ADDR, tmp_file,
|
||||
buf, sizeof(buf), &ri) == NULL);
|
||||
ASSERT(mg_fetch(ctx, "http://$$$.$$$", tmp_file,
|
||||
buf, sizeof(buf), &ri) == NULL);
|
||||
ASSERT(mg_download(NULL, port, 0, ebuf, sizeof(ebuf), "") == NULL);
|
||||
ASSERT(mg_download("localhost", 0, 0, ebuf, sizeof(ebuf), "") == NULL);
|
||||
ASSERT(mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "") == NULL);
|
||||
|
||||
// Failed fetch, pass invalid file name
|
||||
ASSERT(mg_fetch(ctx, "http://" LISTENING_ADDR "/data",
|
||||
"/this/file/must/not/exist/ever",
|
||||
buf, sizeof(buf), &ri) == NULL);
|
||||
// Fetch nonexistent file, should see 404
|
||||
ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s",
|
||||
"GET /gimbec HTTP/1.0\r\n\r\n")) != NULL);
|
||||
ASSERT(strcmp(conn->request_info.uri, "404") == 0);
|
||||
mg_close_connection(conn);
|
||||
|
||||
// Successful fetch
|
||||
ASSERT((fp = mg_fetch(ctx, "http://" LISTENING_ADDR "/data",
|
||||
tmp_file, buf, sizeof(buf), &ri)) != NULL);
|
||||
ASSERT(ri.num_headers == 2);
|
||||
ASSERT(!strcmp(ri.request_method, "HTTP/1.1"));
|
||||
ASSERT(!strcmp(ri.uri, "200"));
|
||||
ASSERT(!strcmp(ri.http_version, "OK"));
|
||||
ASSERT((length = ftell(fp)) == (int) strlen(fetch_data));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
ASSERT(fread(buf2, 1, length, fp) == (size_t) length);
|
||||
ASSERT(memcmp(buf2, fetch_data, length) == 0);
|
||||
fclose(fp);
|
||||
// Fetch mongoose.c, should succeed
|
||||
ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s",
|
||||
"GET /mongoose.c HTTP/1.0\r\n\r\n")) != NULL);
|
||||
ASSERT(!strcmp(conn->request_info.uri, "200"));
|
||||
ASSERT((p1 = read_conn(conn, &len1)) != NULL);
|
||||
ASSERT((p2 = read_file("mongoose.c", &len2)) != NULL);
|
||||
ASSERT(len1 == len2);
|
||||
ASSERT(memcmp(p1, p2, len1) == 0);
|
||||
free(p1), free(p2);
|
||||
mg_close_connection(conn);
|
||||
|
||||
// Fetch big file, mongoose.c
|
||||
ASSERT((fp = mg_fetch(ctx, "http://" LISTENING_ADDR "/mongoose.c",
|
||||
tmp_file, buf, sizeof(buf), &ri)) != NULL);
|
||||
ASSERT(mg_stat(fc(ctx), "mongoose.c", &file));
|
||||
ASSERT(file.size == ftell(fp));
|
||||
ASSERT(!strcmp(ri.request_method, "HTTP/1.1"));
|
||||
// Fetch in-memory file, should succeed.
|
||||
ASSERT((conn = mg_download("localhost", port, 1, ebuf, sizeof(ebuf), "%s",
|
||||
"GET /blah HTTP/1.1\r\n\r\n")) != NULL);
|
||||
ASSERT((p1 = read_conn(conn, &len1)) != NULL);
|
||||
ASSERT(len1 == (int) strlen(inmemory_file_data));
|
||||
ASSERT(memcmp(p1, inmemory_file_data, len1) == 0);
|
||||
free(p1);
|
||||
mg_close_connection(conn);
|
||||
|
||||
// Fetch nonexistent file, /blah
|
||||
ASSERT((fp = mg_fetch(ctx, "http://" LISTENING_ADDR "/boo",
|
||||
tmp_file, buf, sizeof(buf), &ri)) != NULL);
|
||||
ASSERT(!mg_strcasecmp(ri.uri, "404"));
|
||||
fclose(fp);
|
||||
// Test SSL redirect, IP address
|
||||
ASSERT((conn = mg_download("localhost", atoi(HTTP_PORT), 0,
|
||||
ebuf, sizeof(ebuf), "%s",
|
||||
"GET /foo HTTP/1.1\r\n\r\n")) != NULL);
|
||||
ASSERT(strcmp(conn->request_info.uri, "302") == 0);
|
||||
ASSERT(strcmp(mg_get_header(conn, "Location"),
|
||||
"https://127.0.0.1:" HTTPS_PORT "/foo") == 0);
|
||||
mg_close_connection(conn);
|
||||
|
||||
// Fetch existing inmemory file
|
||||
ASSERT((fp = mg_fetch(ctx, "http://" LISTENING_ADDR "/blah",
|
||||
tmp_file, buf, sizeof(buf), &ri)) != NULL);
|
||||
ASSERT(!mg_strcasecmp(ri.uri, "200"));
|
||||
n = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
printf("%s %d %d [%.*s]\n", __func__, n, (int) feof(fp), n, buf2);
|
||||
n = fread(buf2, 1, n, fp);
|
||||
printf("%s %d %d [%.*s]\n", __func__, n, (int) feof(fp), n, buf2);
|
||||
ASSERT((size_t) ftell(fp) == (size_t) strlen(inmemory_file_data));
|
||||
ASSERT(!memcmp(inmemory_file_data, buf2, ftell(fp)));
|
||||
fclose(fp);
|
||||
// Test SSL redirect, Host:
|
||||
ASSERT((conn = mg_download("localhost", atoi(HTTP_PORT), 0,
|
||||
ebuf, sizeof(ebuf), "%s",
|
||||
"GET /foo HTTP/1.1\r\nHost: a.b:77\n\n")) != NULL);
|
||||
ASSERT(strcmp(conn->request_info.uri, "302") == 0);
|
||||
ASSERT(strcmp(mg_get_header(conn, "Location"),
|
||||
"https://a.b:" HTTPS_PORT "/foo") == 0);
|
||||
mg_close_connection(conn);
|
||||
|
||||
remove(tmp_file);
|
||||
mg_stop(ctx);
|
||||
}
|
||||
|
||||
@@ -261,7 +295,6 @@ static void test_base64_encode(void) {
|
||||
|
||||
for (i = 0; in[i] != NULL; i++) {
|
||||
base64_encode((unsigned char *) in[i], strlen(in[i]), buf);
|
||||
printf("[%s] [%s]\n", out[i], buf);
|
||||
ASSERT(!strcmp(buf, out[i]));
|
||||
}
|
||||
}
|
||||
@@ -329,7 +362,9 @@ static void check_lua_expr(lua_State *L, const char *expr, const char *value) {
|
||||
luaL_dostring(L, buf);
|
||||
lua_getglobal(L, var_name);
|
||||
v = lua_tostring(L, -1);
|
||||
#if 0
|
||||
printf("%s: %s: [%s] [%s]\n", __func__, expr, v == NULL ? "null" : v, value);
|
||||
#endif
|
||||
ASSERT((value == NULL && v == NULL) ||
|
||||
(value != NULL && v != NULL && !strcmp(value, v)));
|
||||
}
|
||||
@@ -341,13 +376,12 @@ static void test_lua(void) {
|
||||
char http_request[] = "POST /foo/bar HTTP/1.1\r\n"
|
||||
"Content-Length: 12\r\n"
|
||||
"Connection: close\r\n\r\nhello world!";
|
||||
const char *page = "<? print('hi') ?>";
|
||||
lua_State *L = luaL_newstate();
|
||||
|
||||
conn.ctx = &ctx;
|
||||
conn.buf = http_request;
|
||||
conn.buf_size = conn.data_len = strlen(http_request);
|
||||
conn.request_len = parse_http_request(conn.buf, conn.data_len,
|
||||
conn.request_len = parse_http_message(conn.buf, conn.data_len,
|
||||
&conn.request_info);
|
||||
conn.content_len = conn.data_len - conn.request_len;
|
||||
|
||||
@@ -371,7 +405,7 @@ static void test_lua(void) {
|
||||
static void *user_data_tester(enum mg_event event, struct mg_connection *conn) {
|
||||
struct mg_request_info *ri = mg_get_request_info(conn);
|
||||
ASSERT(ri->user_data == (void *) 123);
|
||||
ASSERT(event == MG_NEW_REQUEST);
|
||||
ASSERT(event == MG_NEW_REQUEST || event == MG_INIT_SSL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -413,8 +447,8 @@ int __cdecl main(void) {
|
||||
test_match_prefix();
|
||||
test_remove_double_dots();
|
||||
test_should_keep_alive();
|
||||
test_parse_http_request();
|
||||
test_mg_fetch();
|
||||
test_parse_http_message();
|
||||
test_mg_download();
|
||||
test_mg_get_var();
|
||||
test_set_throttle();
|
||||
test_next_option();
|
||||
@@ -425,5 +459,6 @@ int __cdecl main(void) {
|
||||
test_lua();
|
||||
#endif
|
||||
test_skip_quoted();
|
||||
printf("%s\n", "PASSED");
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user