int main(void) { SXE_HTTPD httpd; SXE * client; SXE * client2; SXE * server; SXE * server2; tap_ev event; plan_tests(14); test_sxe_register_and_init(1000); sxe_httpd_construct(&httpd, 2, 10, 512, 0); SXE_HTTPD_SET_HANDLER(&httpd, connect, h_connect); SXE_HTTPD_SET_HANDLER(&httpd, request, h_request); SXE_HTTPD_SET_HANDLER(&httpd, close, h_close); ok((listener = test_httpd_listen(&httpd, "0.0.0.0", 0)) != NULL, "HTTPD listening"); /* Starts two connections, then make a new connection, the oldest will be reaped by the server */ tap_test_case_name("reap connections"); /* 1st connection */ SXEA1((client = test_new_tcp(NULL, "0.0.0.0", 0, client_connect, client_read, client_close)) != NULL, "Failed to allocate client SXE"); SXEA1(sxe_connect(client, "127.0.0.1", SXE_LOCAL_PORT(listener)) == SXE_RETURN_OK, "Failed to connect to HTTPD"); is_eq(test_tap_ev_queue_identifier_wait(q_client, TEST_WAIT, &event), "client_connect", "Got 1st client connected event"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &event), "h_connect", "Got 1st server connect event"); server = SXE_CAST(SXE *, tap_ev_arg(event, "this")); /* 1st client: send a complete request line */ TEST_SXE_SEND_LITERAL(client, "GET /good HTTP/1.1\r\n", client_sent, q_client, TEST_WAIT, &event); /* Waiting for 1st client request state "stable" on "STATE_HEADER" to make * sure there is no more state updates on this request object, then the following * usleep will guarantee the 1st connection is older than the 2nd one. */ is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &event), "h_request", "Got 1st server request event"); is(tap_ev_arg(event, "this"), server, "It's the 1st server"); usleep(300000); /* 2nd connection, reaping happens, the 1st one got reaped */ SXEA1((client2 = test_new_tcp(NULL, "0.0.0.0", 0, client_connect, client_read, client_close)) != NULL, "Failed to allocate client SXE"); SXEA1(sxe_connect(client2, "127.0.0.1", SXE_LOCAL_PORT(listener)) == SXE_RETURN_OK, "Failed to connect to HTTPD"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &event), "h_connect", "Got 2nd server connect event"); server2 = SXE_CAST(SXE *, tap_ev_arg(event, "this")); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &event), "h_close", "Got a server close event"); is(tap_ev_arg(event, "this"), server, "It's the 1st server"); /* Pull these two arguments off in any order */ test_process_all_libev_events(); ok((event = tap_ev_queue_shift_next(q_client, "client_connect")) != NULL, "Got 2nd client connected event"); ok((event = tap_ev_queue_shift_next(q_client, "client_close")) != NULL, "Got a client close event"); is(tap_ev_arg(event, "this"), client, "It's the 1st client"); is(tap_ev_queue_length(q_httpd), 0, "No server events lurking"); is(tap_ev_queue_length(q_client), 0, "No client events lurking"); sxe_close(listener); return exit_status(); }
unsigned test_tap_ev_length_nowait(void) { test_process_all_libev_events(); return tap_ev_length(); }
int main(void) { SXE_HTTPD httpd; SXE_HTTPD_REQUEST * request; tap_ev ev; SXE * listener; SXE * c; SXE * c2; char buffer[1024]; tap_plan(24, TAP_FLAG_ON_FAILURE_EXIT, NULL); test_sxe_register_and_init(12); sxe_httpd_construct(&httpd, 3, 10, 512, 0); SXE_HTTPD_SET_HANDLER(&httpd, connect, h_connect); SXE_HTTPD_SET_HANDLER(&httpd, request, h_request); SXE_HTTPD_SET_HANDLER(&httpd, header, h_header); SXE_HTTPD_SET_HANDLER(&httpd, eoh, h_eoh); SXE_HTTPD_SET_HANDLER(&httpd, body, h_body); SXE_HTTPD_SET_HANDLER(&httpd, respond, h_respond); SXE_HTTPD_SET_HANDLER(&httpd, close, h_close); listener = test_httpd_listen(&httpd, "0.0.0.0", 0); c = test_new_tcp(NULL, "0.0.0.0", 0, client_connect, client_read, NULL); sxe_connect(c, "127.0.0.1", SXE_LOCAL_PORT(listener)); is_eq(test_tap_ev_queue_identifier_wait(q_client, TEST_WAIT, &ev), "client_connect", "1st Client connected to HTTPD"); TEST_SXE_SEND_LITERAL(c, "POST /this/is/a/URL HTTP/1.1\r\nContent-Length: 10\r\n\r\n12345678\r\n", client_sent, q_client, TEST_WAIT, &ev); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_connect", "HTTPD: connected"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_request", "HTTPD: new request"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_header", "HTTPD: header event"); is_strncmp(tap_ev_arg(ev, "key"), "Content-Length", SXE_LITERAL_LENGTH("Content-Length"), "HTTPD: header was 'Connect'"); is_strncmp(tap_ev_arg(ev, "value"), "10", SXE_LITERAL_LENGTH("10"), "HTTPD: header value was 'whatever'"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_eoh", "HTTPD: eoh (end of headers) event"); test_ev_queue_wait_read(q_httpd, TEST_WAIT, &ev, NULL, "h_body", buffer, 10, "HTTPD body handler"); is_strncmp(buffer, "12345678\r\n", SXE_LITERAL_LENGTH("12345678\r\n"), "HTTPD: read correct body"); /* httpd is still in "req_response" state */ is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_respond", "HTTPD: respond event"); /* Extra data from client, e.g., "content-length" is wrong and shorter than real packet */ TEST_SXE_SEND_LITERAL(c, "AB", client_sent, q_client, TEST_WAIT, &ev); /* Send another valid request again, the connection is in "sink" mode now, data will get ignored */ TEST_SXE_SEND_LITERAL(c, "POST /this/is/a/URL HTTP/1.1\r\nContent-Length: 10\r\n\r\n12345678\r\n", client_sent, q_client, TEST_WAIT, &ev); test_process_all_libev_events(); /* In sink mode, no more httpd events */ is(tap_ev_queue_length(q_httpd), 0, "No lurking httpd events"); /* New client connection should not be affected */ c2 = test_new_tcp(NULL, "0.0.0.0", 0, client_connect, client_read, client_close); sxe_connect(c2, "127.0.0.1", SXE_LOCAL_PORT(listener)); is_eq(test_tap_ev_queue_identifier_wait(q_client, TEST_WAIT, &ev), "client_connect", "2nd Client connected to HTTPD"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_connect", "HTTPD: connected"); TEST_SXE_SEND_LITERAL(c2, "GET /simple HTTP/1.1\r\n\r\n", client_sent, q_client, TEST_WAIT, &ev); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_request", "HTTPD: new request"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_eoh", "HTTPD: eoh (end of headers) event"); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_respond", "HTTPD: respond event"); request = (SXE_HTTPD_REQUEST *)(long)tap_ev_arg(ev, "request"); sxe_httpd_response_simple(request, h_sent, NULL, 200, "OK", NULL, "Connection", "close", NULL); is_eq(test_tap_ev_queue_identifier_wait(q_httpd, TEST_WAIT, &ev), "h_sent", "HTTPD: finished responding"); sxe_close(request->sxe); #define TEST_200_CLOSE_RESPONSE "HTTP/1.1 200 OK\r\nConnection: close\r\nContent-Length: 0\r\n\r\n" test_ev_queue_wait_read(q_client, TEST_WAIT, &ev, c2, "client_read", buffer, SXE_LITERAL_LENGTH(TEST_200_CLOSE_RESPONSE), "client"); is_strncmp(buffer, TEST_200_CLOSE_RESPONSE, SXE_LITERAL_LENGTH(TEST_200_CLOSE_RESPONSE), "GET response is a 200 OK with close"); is_eq(test_tap_ev_queue_identifier_wait(q_client, TEST_WAIT, &ev), "client_close", "Got a client close event"); return exit_status(); }