/** * Copyright (c) 2021 OceanBase * OceanBase CE is licensed under Mulan PubL v2. * You can use this software according to the terms and conditions of the Mulan PubL v2. * You may obtain a copy of Mulan PubL v2 at: * http://license.coscl.org.cn/MulanPubL-2.0 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * See the Mulan PubL v2 for more details. */ #include "io/easy_io.h" #include #include "util/easy_time.h" #include #include "packet/http/http_parser.h" #include "io/easy_connection.h" #include #include static void* test_realloc(void* ptr, size_t size) { return NULL; } /////////////////////////////////////////////////////////////////////////////////////////////////// TEST(easy_http_handler, create) { easy_http_packet_t* packet; easy_pool_t* pool; char *value, *key; int i; char data[16]; pool = easy_pool_create(1024); packet = easy_http_packet_create(pool); // add header for (i = 0; i < 128; i++) { lnprintf(data, 16, "key%d", i); key = easy_pool_strdup(pool, data); lnprintf(data, 16, "value%d", i); value = easy_pool_strdup(pool, data); easy_http_add_header(pool, packet->headers_out, key, value); } // get header for (i = 0; i < 128; i++) { lnprintf(data, 16, "key%d", i); value = easy_http_get_header(packet->headers_out, data); lnprintf(data, 16, "value%d", i); EXPECT_TRUE(memcmp(value, data, strlen(data)) == 0); } // del header for (i = 0; i < 128; i++) { if (i % 2) lnprintf(data, 16, "key%d", i); else lnprintf(data, 16, "Key%d", i); value = easy_http_del_header(packet->headers_out, data); lnprintf(data, 16, "value%d", i); if (value) { EXPECT_TRUE(memcmp(value, data, strlen(data)) == 0); } else { EXPECT_TRUE(0); } } // header again for (i = 0; i < 128; i++) { lnprintf(data, 16, "key%d", i); value = easy_http_del_header(packet->headers_out, data); EXPECT_TRUE(value == NULL); value = easy_http_get_header(packet->headers_out, data); EXPECT_TRUE(value == NULL); } easy_pool_destroy(pool); } TEST(easy_http_handler, urldecode) { char buffer[32]; int len; memcpy(buffer, "%41%41c", 8); len = easy_url_decode(buffer, strlen(buffer)); EXPECT_EQ(len, 3); EXPECT_TRUE(memcmp(buffer, "AAc", len) == 0); } TEST(easy_http_handler, string_end) { easy_pool_t* pool; easy_http_request_t p; easy_string_pair_t header; char buffer[2]; // easy_http_request_t memset(&p, 0, sizeof(easy_http_request_t)); memset(buffer, 'A', 2); p.str_fragment.len = 1; p.str_fragment.data--; buffer[1] = '\0'; easy_buf_string_set(&header.name, buffer); easy_buf_string_set(&header.value, buffer); pool = easy_pool_create(1024); p.headers_in = easy_header_create_table(pool); easy_hash_string_add(p.headers_in, &header); easy_pool_destroy(pool); } TEST(easy_http_hander, decode) { easy_pool_t* pool; easy_message_t* m; int size; void* ptr; // failure easy_log_level = (easy_log_level_t)0; pool = easy_pool_create(0); m = (easy_message_t*)easy_pool_calloc(pool, sizeof(easy_message_t)); size = pool->end - pool->last - sizeof(easy_buf_t); size = ((size < 0) ? EASY_POOL_ALIGNMENT : size); m->input = easy_buf_create(pool, size); m->pool = pool; easy_pool_set_allocator(test_realloc); ptr = easy_http_server_on_decode(m); easy_pool_set_allocator(easy_test_realloc); EXPECT_TRUE(ptr == NULL); // null string ptr = easy_http_server_on_decode(m); EXPECT_TRUE(ptr == NULL); // failure http size = sprintf(m->input->pos, "XXX http://1.taobao.com/ HTTP/1.1"); m->input->last = m->input->pos + size; ptr = easy_http_server_on_decode(m); EXPECT_TRUE(ptr == NULL); EXPECT_TRUE(m->status == EASY_ERROR); // parse m->user_data = NULL; m->status = 0; m->c = (easy_connection_t*)easy_pool_calloc(pool, sizeof(easy_connection_t)); size = sprintf(m->input->pos, "GET http://1.taobao.com/淘宝/a.html?a=y&b=c#test"); m->input->last = m->input->pos + size; ptr = easy_http_server_on_decode(m); EXPECT_TRUE(ptr == NULL); EXPECT_TRUE(m->status != EASY_ERROR); m->input->last += sprintf(m->input->last, " HTTP/1.1\r\nHost: x"); ptr = easy_http_server_on_decode(m); EXPECT_TRUE(ptr == NULL); EXPECT_TRUE(m->status != EASY_ERROR); m->input->last += sprintf(m->input->last, "yz.taobao"); ptr = easy_http_server_on_decode(m); EXPECT_TRUE(ptr == NULL); EXPECT_TRUE(m->status != EASY_ERROR); m->input->last += sprintf(m->input->last, ".com\r\nConnection: close\r\n\r\n"); ptr = easy_http_server_on_decode(m); EXPECT_TRUE(ptr != NULL); EXPECT_TRUE(m->status != EASY_ERROR); EXPECT_TRUE(m->c->wait_close == 1); if (ptr) { easy_http_request_t* p = (easy_http_request_t*)ptr; char* value = easy_http_get_header(p->headers_in, "Host"); EXPECT_TRUE(memcmp(value, "xyz.taobao.com", 14) == 0); if (p->str_host.len > 0) EXPECT_TRUE(strncmp((char*)p->str_host.data, "1.taobao.com", p->str_host.len) == 0); } easy_pool_destroy(pool); } TEST(easy_http_hander, server_on_encode) { easy_pool_t* pool; easy_request_t* r; easy_http_request_t* hr; easy_buf_t *b, *b1; easy_log_level = (easy_log_level_t)0; // raw header { pool = easy_pool_create(0); r = (easy_request_t*)easy_pool_calloc(pool, sizeof(easy_request_t)); hr = (easy_http_request_t*)easy_pool_calloc(pool, sizeof(easy_http_request_t)); r->ms = (easy_message_session_t*)easy_pool_calloc(pool, sizeof(easy_message_session_t)); r->ms->pool = pool; r->ms->c = (easy_connection_t*)easy_pool_calloc(pool, sizeof(easy_connection_t)); easy_list_init(&r->ms->c->output); easy_list_init(&hr->output); b = easy_buf_create(pool, 1); hr->is_raw_header = 1; easy_list_add_tail(&b->node, &hr->output); easy_http_server_on_encode(r, hr); b1 = easy_list_get_first(&r->ms->c->output, easy_buf_t, node); EXPECT_TRUE(b1 == b); easy_pool_destroy(pool); } // status line { pool = easy_pool_create(0); r = (easy_request_t*)easy_pool_calloc(pool, sizeof(easy_request_t)); hr = (easy_http_request_t*)easy_pool_calloc(pool, sizeof(easy_http_request_t)); r->ms = (easy_message_session_t*)easy_pool_calloc(pool, sizeof(easy_message_session_t)); r->ms->pool = pool; r->ms->c = (easy_connection_t*)easy_pool_calloc(pool, sizeof(easy_connection_t)); easy_list_init(&r->ms->c->output); easy_list_init(&hr->output); easy_buf_string_set(&hr->status_line, EASY_HTTP_STATUS_400); hr->headers_out = easy_header_create_table(pool); easy_http_add_header(pool, hr->headers_out, "Host", "a.taobao.com"); hr->parser.http_major = hr->parser.http_minor = 1; easy_http_server_on_encode(r, hr); b = easy_list_get_first(&r->ms->c->output, easy_buf_t, node); EXPECT_TRUE(memcmp(b->pos, "HTTP/1.1 400 Bad Request\r\nHost: a.taobao.com\r\n", 41) == 0); easy_pool_destroy(pool); } } TEST(easy_http_hander, client_on_encode) { easy_pool_t* pool; easy_request_t* r; easy_http_packet_t* hr; easy_buf_t *b, *b1; char* ptr; easy_log_level = (easy_log_level_t)0; // raw header { pool = easy_pool_create(0); r = (easy_request_t*)easy_pool_calloc(pool, sizeof(easy_request_t)); hr = (easy_http_packet_t*)easy_pool_calloc(pool, sizeof(easy_http_packet_t)); r->ms = (easy_message_session_t*)easy_pool_calloc(pool, sizeof(easy_message_session_t)); r->ms->pool = pool; r->ms->c = (easy_connection_t*)easy_pool_calloc(pool, sizeof(easy_connection_t)); easy_list_init(&r->ms->c->output); easy_list_init(&hr->output); b = easy_buf_create(pool, 1); hr->is_raw_header = 1; easy_list_add_tail(&b->node, &hr->output); easy_http_client_on_encode(r, hr); b1 = easy_list_get_first(&r->ms->c->output, easy_buf_t, node); EXPECT_TRUE(b1 == b); easy_pool_destroy(pool); } // post { pool = easy_pool_create(0); r = (easy_request_t*)easy_pool_calloc(pool, sizeof(easy_request_t)); hr = (easy_http_packet_t*)easy_pool_calloc(pool, sizeof(easy_http_packet_t)); r->ms = (easy_message_session_t*)easy_pool_calloc(pool, sizeof(easy_message_session_t)); r->ms->pool = pool; r->ms->c = (easy_connection_t*)easy_pool_calloc(pool, sizeof(easy_connection_t)); easy_list_init(&r->ms->c->output); easy_list_init(&hr->output); hr->method = HTTP_POST; hr->keep_alive = 1; hr->str_path.data = NULL; easy_buf_string_set(&hr->str_query_string, "a=y&c=d"); hr->headers_out = easy_header_create_table(pool); easy_http_add_header(pool, hr->headers_out, "Server", "apache"); easy_http_client_on_encode(r, hr); b = easy_list_get_first(&r->ms->c->output, easy_buf_t, node); ptr = "POST / HTTP/1.1\r\nServer: apache\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: " "7\r\nConnection: keep-alive\r\n\r\na=y&c=d"; EXPECT_TRUE(memcmp(b->pos, ptr, strlen(ptr)) == 0); easy_pool_destroy(pool); } // get { pool = easy_pool_create(0); r = (easy_request_t*)easy_pool_calloc(pool, sizeof(easy_request_t)); hr = (easy_http_packet_t*)easy_pool_calloc(pool, sizeof(easy_http_packet_t)); r->ms = (easy_message_session_t*)easy_pool_calloc(pool, sizeof(easy_message_session_t)); r->ms->pool = pool; r->ms->c = (easy_connection_t*)easy_pool_calloc(pool, sizeof(easy_connection_t)); easy_list_init(&r->ms->c->output); easy_list_init(&hr->output); hr->str_path.data = NULL; easy_buf_string_set(&hr->str_query_string, "a=y&c=d"); hr->headers_out = easy_header_create_table(pool); easy_http_add_header(pool, hr->headers_out, "Server", "apache"); easy_http_client_on_encode(r, hr); b = easy_list_get_first(&r->ms->c->output, easy_buf_t, node); EXPECT_TRUE(memcmp(b->pos, "GET /?a=y&c=d HTTP/1.1\r\nServer: apache\r\n", 40) == 0); easy_pool_destroy(pool); } } TEST(easy_http_hander, client_on_decode) { easy_pool_t* pool; easy_message_t* m; int size; void* ptr; easy_io_handler_pt handler; easy_http_handler_init(&handler, NULL); // failure easy_log_level = (easy_log_level_t)0; pool = easy_pool_create(0); m = (easy_message_t*)easy_pool_calloc(pool, sizeof(easy_message_t)); size = pool->end - pool->last - sizeof(easy_buf_t); size = ((size < 0) ? EASY_POOL_ALIGNMENT : size); m->input = easy_buf_create(pool, size); m->pool = pool; easy_pool_set_allocator(test_realloc); ptr = easy_http_client_on_decode(m); easy_pool_set_allocator(easy_test_realloc); EXPECT_TRUE(ptr == NULL); // null string ptr = easy_http_client_on_decode(m); EXPECT_TRUE(ptr == NULL); // failure http size = sprintf(m->input->pos, "XXX http://1.taobao.com/ HTTP/1.1"); m->input->last = m->input->pos + size; ptr = easy_http_client_on_decode(m); EXPECT_TRUE(ptr == NULL); EXPECT_TRUE(m->status == EASY_ERROR); // parse m->user_data = NULL; m->status = 0; m->c = (easy_connection_t*)easy_pool_calloc(pool, sizeof(easy_connection_t)); m->c->handler = &handler; size = sprintf(m->input->pos, "HTTP/1.1 200"); m->input->last = m->input->pos + size; ptr = easy_http_client_on_decode(m); EXPECT_TRUE(ptr == NULL); EXPECT_TRUE(m->status != EASY_ERROR); m->input->last += sprintf(m->input->last, " OK\r\nHost: x"); ptr = easy_http_client_on_decode(m); EXPECT_TRUE(ptr == NULL); EXPECT_TRUE(m->status != EASY_ERROR); m->input->last += sprintf(m->input->last, "yz.taobao"); ptr = easy_http_client_on_decode(m); EXPECT_TRUE(ptr == NULL); EXPECT_TRUE(m->status != EASY_ERROR); m->input->last += sprintf(m->input->last, ".com\r\nConnection: close\r\nContent-Length: 2\r\n\r\nab"); ptr = easy_http_client_on_decode(m); EXPECT_TRUE(ptr != NULL); EXPECT_TRUE(m->status != EASY_ERROR); EXPECT_TRUE(m->c->wait_close == 1); if (ptr) { easy_http_request_t* p = (easy_http_request_t*)ptr; char* value = easy_http_get_header(p->headers_in, "Host"); EXPECT_TRUE(memcmp(value, "xyz.taobao.com", 14) == 0); } easy_pool_destroy(pool); } TEST(easy_http_hander, init) { easy_io_handler_pt handler; easy_http_handler_init(&handler, NULL); EXPECT_TRUE(handler.decode == easy_http_server_on_decode); EXPECT_TRUE(handler.encode = easy_http_server_on_encode); } // int easy_url_decode(char *str, int len) TEST(easy_http_hander, url_decode) { char data[128], data1[28]; strcpy(data, "HTTP://a.taobao.com/%26%RR%0"); strcpy(data1, "HTTP://a.taobao.com/&%RR%0"); int n = easy_url_decode(data, strlen(data)); EXPECT_TRUE(n > 0); EXPECT_TRUE(strcmp(data, data1) == 0); } // int easy_http_merge_path(char *newpath, int len, const char *rootpath, const char *addpath) TEST(easy_http_hander, merge_path) { /* char newpath[128]; memset(newpath, 0, sizeof(newpath)); int n; n = easy_http_merge_path(newpath, 128, "/root", ".."); fprintf(stderr, "%s\n", newpath); EXPECT_NE(n, EASY_OK); n = easy_http_merge_path(newpath, 128, "/root", "../"); fprintf(stderr, "%s\n", newpath); EXPECT_NE(n, EASY_OK); n = easy_http_merge_path(newpath, 128, "/root", "aa/.."); fprintf(stderr, "%s\n", newpath); EXPECT_EQ(n, EASY_OK); n = easy_http_merge_path(newpath, 128, "/root", "aa/../"); fprintf(stderr, "%s\n", newpath); EXPECT_EQ(n, EASY_OK); n = easy_http_merge_path(newpath, 128, "/root", "aa/../."); fprintf(stderr, "%s\n", newpath); EXPECT_EQ(n, EASY_OK); n = easy_http_merge_path(newpath, 128, "/root", "aa/../.."); fprintf(stderr, "%s\n", newpath); EXPECT_NE(n, EASY_OK); */ } // int easy_http_request_printf(easy_http_request_t *r, const char *fmt, ...) TEST(easy_http_hander, printf) { easy_pool_t* pool; easy_http_request_t r; easy_buf_t* b; pool = easy_pool_create(0); r.m = (easy_message_t*)easy_pool_calloc(pool, sizeof(easy_message_t)); r.m->pool = pool; easy_list_init(&r.output); easy_http_request_printf(&r, "a: %04d, s: %s", 123, "test"); b = easy_list_get_first(&r.output, easy_buf_t, node); char* str = "a: 0123, s: test"; EXPECT_TRUE(strncmp(b->pos, str, strlen(str)) == 0); easy_pool_destroy(pool); } TEST(easy_http_hander, args) { easy_pool_t* pool; easy_http_request_t* p; easy_header_set_case_sensitive(0); pool = easy_pool_create(0); p = (easy_http_request_t*)easy_pool_calloc(pool, sizeof(easy_http_request_t)); memset(p, 0, sizeof(easy_http_request_t)); p->m = (easy_message_t*)easy_pool_calloc(pool, sizeof(easy_message_t)); p->m->pool = pool; easy_buf_string_set(&p->str_query_string, "a=b&c=d&x==&&=&Test=abc&a"); char* x = easy_http_get_args(p, "test"); EXPECT_TRUE(x != NULL); if (x != NULL) EXPECT_TRUE(strcmp(x, "abc") == 0); easy_pool_destroy(pool); } static int http_fetch_set_data(easy_request_t* r, const char* data, int len) { easy_buf_t* b = r->args; memcpy(b->last, data, len); b->last += len; return EASY_OK; } TEST(easy_http_hander, server_on_encode_chunked) { easy_pool_t* pool; easy_request_t* r; easy_http_request_t* hr; easy_buf_t* b; easy_message_t* m; easy_session_t* s; easy_io_handler_pt io_handler; // init easy_log_level = (easy_log_level_t)0; memset(&io_handler, 0, sizeof(easy_io_handler_pt)); io_handler.set_data = (void*)http_fetch_set_data; pool = easy_pool_create(0); r = (easy_request_t*)easy_pool_calloc(pool, sizeof(easy_request_t)); hr = (easy_http_request_t*)easy_pool_calloc(pool, sizeof(easy_http_request_t)); r->ms = (easy_message_session_t*)easy_pool_calloc(pool, sizeof(easy_message_session_t)); r->ms->pool = pool; r->ms->c = (easy_connection_t*)easy_pool_calloc(pool, sizeof(easy_connection_t)); easy_list_init(&r->ms->c->output); easy_list_init(&hr->output); r->ms->c->handler = &io_handler; r->ms->c->send_queue = easy_hash_create(pool, 32, offsetof(easy_session_t, send_queue_hash)); // encode chunked easy_buf_string_set(&hr->status_line, EASY_HTTP_STATUS_200); hr->headers_out = easy_header_create_table(pool); easy_http_add_header(pool, hr->headers_out, "hOst", "a.taobao.com"); easy_http_add_header(pool, hr->headers_out, "Transfer-Encoding", "chunked"); hr->parser.http_major = hr->parser.http_minor = 1; hr->send_chunk = 1; r->retcode = EASY_AGAIN; b = easy_buf_create(pool, 32); b->last = easy_strcpy(b->last, "test server on"); easy_list_add_tail(&b->node, &hr->output); easy_http_server_on_encode(r, hr); hr->is_raw_header = 1; b = easy_buf_create(pool, 32); b->last = easy_strcpy(b->last, " encode "); easy_list_add_tail(&b->node, &hr->output); easy_http_server_on_encode(r, hr); b = easy_buf_create(pool, 32); b->last = easy_strcpy(b->last, "chunked"); easy_list_add_tail(&b->node, &hr->output); r->retcode = EASY_OK; easy_http_server_on_encode(r, hr); // output encode m = (easy_message_t*)easy_pool_calloc(pool, sizeof(easy_message_t)); m->pool = pool; m->c = r->ms->c; m->input = easy_buf_create(pool, 1024); easy_list_for_each_entry(b, &r->ms->c->output, node) { m->input->last += lnprintf(m->input->last, 1024, "%.*s", (int)(b->last - b->pos), b->pos); } // decode chunked easy_header_set_case_sensitive(2); s = easy_session_create(512); s->r.args = easy_buf_create(pool, 1024); s->packet_id = easy_connection_get_packet_id(m->c, NULL, 0); easy_hash_dlist_add(m->c->send_queue, s->packet_id, &s->send_queue_hash, &s->send_queue_list); hr = easy_http_client_on_decode(m); if (hr) { char* value = easy_http_get_header(hr->headers_in, "Host"); EXPECT_TRUE(value); } b = s->r.args; EXPECT_TRUE(hr); EXPECT_TRUE(m->status == EASY_OK); EXPECT_TRUE(memcmp(b->pos, "test server on encode chunked", strlen("test server on encode chunked")) == 0); easy_header_set_case_sensitive(0); easy_session_destroy(s); easy_pool_destroy(pool); } easy_http_request_t* easy_test_query_string_decode(easy_message_t* m, char* query_str) { easy_http_request_t* ptr; int size; // parse m->input = easy_buf_create(m->pool, 4096); m->user_data = NULL; m->status = 0; m->c = (easy_connection_t*)easy_pool_calloc(m->pool, sizeof(easy_connection_t)); size = sprintf(m->input->pos, "GET http://1.taobao.com/淘宝/a.html%s HTTP/1.1\r\nHost: x.taobao.com\r\n\r\n", query_str); m->input->last = m->input->pos + size; ptr = easy_http_server_on_decode(m); EXPECT_TRUE(ptr); EXPECT_TRUE(m->status != EASY_ERROR); EXPECT_TRUE(m->c->wait_close == 0); return ptr; } #define easy_test_query_string_match(p, query_str) \ do { \ EXPECT_TRUE(p); \ if (p == NULL) \ break; \ EXPECT_EQ(strlen(query_str), p->str_query_string.len); \ if (p->str_query_string.len > 0) \ EXPECT_TRUE(strncmp((char*)p->str_query_string.data, query_str, p->str_query_string.len) == 0); \ } while (0) TEST(easy_http_hander, decode1) { easy_pool_t* pool; easy_message_t* m; easy_http_request_t* ptr; // failure easy_log_level = (easy_log_level_t)0; pool = easy_pool_create(0); m = (easy_message_t*)easy_pool_calloc(pool, sizeof(easy_message_t)); m->pool = pool; { char* query_str = "a=y&b=c"; char* dst_query_str = ""; ptr = easy_test_query_string_decode(m, query_str); easy_test_query_string_match(ptr, dst_query_str); } { char* query_str = "?a=y&b=c"; char* dst_query_str = query_str + 1; ptr = easy_test_query_string_decode(m, query_str); easy_test_query_string_match(ptr, dst_query_str); } { char* query_str = "?"; char* dst_query_str = ""; ptr = easy_test_query_string_decode(m, query_str); easy_test_query_string_match(ptr, dst_query_str); } { char* query_str = "??a=y&b=c"; char* dst_query_str = query_str + 1; ptr = easy_test_query_string_decode(m, query_str); easy_test_query_string_match(ptr, dst_query_str); } { char* query_str = "??"; char* dst_query_str = "?"; ptr = easy_test_query_string_decode(m, query_str); easy_test_query_string_match(ptr, dst_query_str); } { char* query_str = "???"; char* dst_query_str = query_str + 1; ptr = easy_test_query_string_decode(m, query_str); easy_test_query_string_match(ptr, dst_query_str); } { char* query_str = "?a=y&b=c?111"; char* dst_query_str = "a=y&b=c?111"; ptr = easy_test_query_string_decode(m, query_str); easy_test_query_string_match(ptr, dst_query_str); } { char* query_str = "?a=y&b=c?"; char* dst_query_str = "a=y&b=c?"; ptr = easy_test_query_string_decode(m, query_str); easy_test_query_string_match(ptr, dst_query_str); } { char* query_str = "?a=y&b=c#abc"; char* dst_query_str = "a=y&b=c"; ptr = easy_test_query_string_decode(m, query_str); easy_test_query_string_match(ptr, dst_query_str); } { char* query_str = "?a=y&b=c#abc??111"; char* dst_query_str = "a=y&b=c"; ptr = easy_test_query_string_decode(m, query_str); easy_test_query_string_match(ptr, dst_query_str); } { char* query_str = "?#abc??111"; char* dst_query_str = ""; ptr = easy_test_query_string_decode(m, query_str); easy_test_query_string_match(ptr, dst_query_str); } { char* query_str = "#?abc??111"; char* dst_query_str = ""; ptr = easy_test_query_string_decode(m, query_str); easy_test_query_string_match(ptr, dst_query_str); } { char* query_str = "#222?abc??111"; char* dst_query_str = ""; ptr = easy_test_query_string_decode(m, query_str); easy_test_query_string_match(ptr, dst_query_str); } easy_pool_destroy(pool); } static http_parser_settings test_easy_http_settings = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; TEST(easy_http_handler, parser) { char buffer[1024]; int size, n, i; int errnum = 0; int oknum = 0; int cnt = 10000 * 200; strcpy(buffer, "GET /index.php/0000000000/index.php/0000000000.html HTTP/1.0\r\nUser-Agent: ApacheBench/2.0.40-dev\r\nHost: " "test.taobao.com\r\nAccept: */*\r\n"); size = strlen(buffer); int64_t t1 = easy_time_now(); for (i = 0; i < cnt; i++) { http_parser parser; http_parser_init(&parser, HTTP_REQUEST); n = http_parser_execute(&parser, &test_easy_http_settings, buffer, size); if (http_parser_has_error(&parser) || n < 0) { errnum++; } else { oknum++; } } int64_t t2 = easy_time_now(); fprintf(stderr, "t: %" PRId64 ", speed: %.2f\n", (t2 - t1), cnt * 1000000.0 / (t2 - t1)); EXPECT_TRUE(errnum == 0); EXPECT_TRUE(oknum == cnt); } /////////////////////////////////////////////////////////////////////////////////////////////// static easy_thread_pool_t* test_thread_101_server_tp; static easy_list_t test_thread_101_list = EASY_LIST_HEAD_INIT(test_thread_101_list); static int test_thread_101_server_process(easy_request_t* r) { easy_thread_pool_push(test_thread_101_server_tp, r, easy_hash_key((uint64_t)(long)r)); return EASY_AGAIN; } static int test_thread_101_request_process(easy_request_t* r, void* args) { easy_list_add_tail(&r->request_list_node, &test_thread_101_list); easy_http_request_t* p; p = (easy_http_request_t*)r->ipacket; if (p->str_path.len != 5 || memcmp(p->str_path.data, "/done", 5) != 0) { return EASY_ABORT; } // reply easy_request_t *n1, *n2; easy_list_for_each_entry_safe(n1, n2, &test_thread_101_list, request_list_node) { easy_list_del(&n1->request_list_node); p = (easy_http_request_t*)n1->ipacket; n1->opacket = p; easy_http_request_printf(p, "%s", p->str_path.data); easy_request_wakeup(n1); } easy_list_init(&test_thread_101_list); return EASY_ABORT; } static void test_thread_101_server(int fd) { easy_listen_t* l; easy_io_handler_pt io_handler; int i, port; easy_log_level = (easy_log_level_t)0; easy_io_create(4); memset(&io_handler, 0, sizeof(easy_io_handler_pt)); io_handler.decode = easy_http_server_on_decode; io_handler.encode = easy_http_server_on_encode; io_handler.process = test_thread_101_server_process; test_thread_101_server_tp = easy_request_thread_create(1, test_thread_101_request_process, NULL); port = 2011; for (i = 0; i < 10; i++, port++) { if ((l = easy_io_add_listen(NULL, port, &io_handler)) != NULL) break; } easy_io_start(); i = write(fd, &port, 2); easy_io_wait(); easy_io_destroy(); } static int test_thread_101_disconnect(easy_connection_t* c) { easy_io_stop(); return EASY_OK; } static int test_thread_101_connect(easy_connection_t* c) { int retv = EASY_OK; char buffer[65536]; char text[20000]; int i, ret, idx = 0; memset(text, 'A', sizeof(text)); text[sizeof(text) - 1] = '\0'; text[2] = '='; for (i = 0; i < 3; i++) { idx += lnprintf(buffer + idx, 30000, "POST /request_%d HTTP/1.1\r\nContent-Length: %d\r\n" "Content-Type: application/x-www-form-urlencoded\r\n" "Host: test.com\r\nConnection: keep-alive\r\n\r\n%s", i, (int)strlen(text), text); } idx += lnprintf(buffer + idx, 4000, "GET /done HTTP/1.1\r\n" "Host: test.com\r\n" "Connection: keep-alive\r\n\r\n"); buffer[idx] = '\0'; char* p = buffer; while (idx > 0) { i = easy_min(idx, 1000); ret = write(c->fd, p, i); if (ret > 0) { p += ret; idx -= ret; } else if (errno != EAGAIN && errno != EINTR) { easy_error_log("write failure: %d:%s\n", errno, strerror(errno)); retv = EASY_ERROR; break; } usleep(100); } return retv; } static int test_thread_101_client_process(easy_request_t* r) { return EASY_OK; } static void test_thread_101_client(int port) { easy_io_handler_pt io_handler; easy_log_level = (easy_log_level_t)0; easy_io_create(4); easy_io_start(); memset(&io_handler, 0, sizeof(easy_io_handler_pt)); io_handler.decode = easy_http_server_on_decode; io_handler.encode = easy_http_server_on_encode; io_handler.process = test_thread_101_client_process; io_handler.on_connect = test_thread_101_connect; io_handler.on_disconnect = test_thread_101_disconnect; // connect easy_addr_t addr = easy_inet_str_to_addr("localhost", port); int i = easy_io_connect(addr, &io_handler, 0, NULL); EXPECT_TRUE(i == EASY_OK); easy_io_wait(); easy_io_destroy(); } TEST(easy_http_hander, thread_101) { int pfd[2]; pid_t pid1, pid2; int ret = 0; int port = 0; if (pipe(pfd) == -1) return; // server if ((pid1 = fork()) == 0) { close(pfd[0]); test_thread_101_server(pfd[1]); close(pfd[1]); exit(easy_test_retval); } else { close(pfd[1]); ret = read(pfd[0], &port, 2); close(pfd[0]); } // client if ((pid2 = fork()) == 0) { test_thread_101_client(port); exit(easy_test_retval); } waitpid(pid2, &ret, 0); EXPECT_EQ(WEXITSTATUS(ret), 0); kill(pid1, SIGINT); usleep(1000); waitpid(pid1, &ret, 0); EXPECT_EQ(WEXITSTATUS(ret), 0); }