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"; char req9[] = "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n"; ASSERT(get_request_len("\r\n", 3) == -1); ASSERT(get_request_len("\r\n", 2) == 0); ASSERT(get_request_len("GET", 3) == 0); ASSERT(get_request_len("\n\n", 2) == 2); ASSERT(get_request_len("\n\r\n", 3) == 3); ASSERT(get_request_len("\xdd\xdd", 2) == 0); ASSERT(get_request_len("\xdd\x03", 2) == -1); ASSERT(parse_http_message(req9, sizeof(req9), &ri) == sizeof(req9) - 1); ASSERT(ri.num_headers == 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_message(req2, sizeof(req2) - 1, &ri) == -1); ASSERT(parse_http_message(req3, sizeof(req3) - 1, &ri) == 0); ASSERT(parse_http_message(req6, sizeof(req6) - 1, &ri) == 0); ASSERT(parse_http_message(req7, sizeof(req7) - 1, &ri) == 0); ASSERT(parse_http_message("", 0, &ri) == 0); ASSERT(parse_http_message(req8, sizeof(req8) - 1, &ri) == sizeof(req8) - 1); // TODO(lsm): Fix this. Header value may span multiple lines. ASSERT(parse_http_message(req4, sizeof(req4) - 1, &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); ASSERT(strcmp(ri.http_headers[1].name, "B") == 0); ASSERT(strcmp(ri.http_headers[1].value, "bar") == 0); ASSERT(strcmp(ri.http_headers[2].name, "baz\r\n\r") == 0); ASSERT(strcmp(ri.http_headers[2].value, "") == 0); ASSERT(parse_http_message(req5, sizeof(req5) - 1, &ri) == sizeof(req5) - 1); ASSERT(strcmp(ri.request_method, "GET") == 0); ASSERT(strcmp(ri.http_version, "1.1") == 0); }
END_TEST START_TEST(test_should_keep_alive) { /* Adapted from unit_test.c */ /* Copyright (c) 2013-2015 the Civetweb developers */ /* Copyright (c) 2004-2013 Sergey Lyubka */ struct mg_connection conn; struct mg_context ctx; char req1[] = "GET / HTTP/1.1\r\n\r\n"; char req2[] = "GET / HTTP/1.0\r\n\r\n"; char req3[] = "GET / HTTP/1.1\r\nConnection: close\r\n\r\n"; char req4[] = "GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"; char yes[] = "yes"; char no[] = "no"; memset(&conn, 0, sizeof(conn)); conn.ctx = &ctx; ck_assert_int_eq(parse_http_message(req1, sizeof(req1), &conn.request_info), sizeof(req1) - 1); ctx.config[ENABLE_KEEP_ALIVE] = no; ck_assert_int_eq(should_keep_alive(&conn), 0); ctx.config[ENABLE_KEEP_ALIVE] = yes; ck_assert_int_eq(should_keep_alive(&conn), 1); conn.must_close = 1; ck_assert_int_eq(should_keep_alive(&conn), 0); conn.must_close = 0; parse_http_message(req2, sizeof(req2), &conn.request_info); ck_assert_int_eq(should_keep_alive(&conn), 0); parse_http_message(req3, sizeof(req3), &conn.request_info); ck_assert_int_eq(should_keep_alive(&conn), 0); parse_http_message(req4, sizeof(req4), &conn.request_info); ck_assert_int_eq(should_keep_alive(&conn), 1); conn.status_code = 401; ck_assert_int_eq(should_keep_alive(&conn), 0); conn.status_code = 200; conn.must_close = 1; ck_assert_int_eq(should_keep_alive(&conn), 0); }
static void test_lua(void) { static struct mg_connection conn; static struct mg_context ctx; char http_request[] = "POST /foo/bar HTTP/1.1\r\n" "Content-Length: 12\r\n" "Connection: close\r\n\r\nhello world!"; 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_message(conn.buf, conn.data_len, &conn.request_info); conn.content_len = conn.data_len - conn.request_len; prepare_lua_environment(&conn, L); ASSERT(lua_gettop(L) == 0); check_lua_expr(L, "'hi'", "hi"); check_lua_expr(L, "mg.request_info.request_method", "POST"); check_lua_expr(L, "mg.request_info.uri", "/foo/bar"); check_lua_expr(L, "mg.request_info.num_headers", "2"); check_lua_expr(L, "mg.request_info.remote_ip", "0"); check_lua_expr(L, "mg.request_info.http_headers['Content-Length']", "12"); check_lua_expr(L, "mg.request_info.http_headers['Connection']", "close"); (void) luaL_dostring(L, "post = mg.read()"); check_lua_expr(L, "# post", "12"); check_lua_expr(L, "post", "hello world!"); lua_close(L); }
static int parse_http_request(char *buf, int len, struct mg_request_info *ri) { int result = parse_http_message(buf, len, ri); if (result > 0 && is_valid_http_method(ri->request_method) && !strncmp(ri->http_version, "HTTP/", 5)) { ri->http_version += 5; // Skip "HTTP/" } else { result = -1; } return result; }
static void test_should_keep_alive(void) { struct mg_connection conn; struct mg_context ctx; char req1[] = "GET / HTTP/1.1\r\n\r\n"; char req2[] = "GET / HTTP/1.0\r\n\r\n"; char req3[] = "GET / HTTP/1.1\r\nConnection: close\r\n\r\n"; char req4[] = "GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"; memset(&conn, 0, sizeof(conn)); conn.ctx = &ctx; 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); ctx.config[ENABLE_KEEP_ALIVE] = "yes"; ASSERT(should_keep_alive(&conn) == 1); conn.must_close = 1; ASSERT(should_keep_alive(&conn) == 0); conn.must_close = 0; parse_http_message(req2, sizeof(req2), &conn.request_info); ASSERT(should_keep_alive(&conn) == 0); parse_http_message(req3, sizeof(req3), &conn.request_info); ASSERT(should_keep_alive(&conn) == 0); parse_http_message(req4, sizeof(req4), &conn.request_info); ASSERT(should_keep_alive(&conn) == 1); conn.status_code = 401; ASSERT(should_keep_alive(&conn) == 0); conn.status_code = 200; conn.must_close = 1; ASSERT(should_keep_alive(&conn) == 0); }
static const char *test_should_keep_alive(void) { struct mg_connection conn; char req1[] = "GET / HTTP/1.1\r\n\r\n"; char req2[] = "GET / HTTP/1.0\r\n\r\n"; char req3[] = "GET / HTTP/1.1\r\nConnection: close\r\n\r\n"; char req4[] = "GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n"; memset(&conn, 0, sizeof(conn)); ASSERT(parse_http_message(req1, sizeof(req1) - 1, &conn) == sizeof(req1) - 1); ASSERT(should_keep_alive(&conn) != 0); parse_http_message(req2, sizeof(req2) - 1, &conn); ASSERT(should_keep_alive(&conn) == 0); parse_http_message(req3, sizeof(req3) - 1, &conn); ASSERT(should_keep_alive(&conn) == 0); parse_http_message(req4, sizeof(req4) - 1, &conn); ASSERT(should_keep_alive(&conn) != 0); return NULL; }
static int parse_http_response(char *buf, int len, struct mg_request_info *ri) { int result = parse_http_message(buf, len, ri); return result > 0 && !strncmp(ri->request_method, "HTTP/", 5) ? result : -1; }