diff --git a/examples/tinyhttpd.c b/examples/tinyhttpd.c index ee8134194..acdf69730 100644 --- a/examples/tinyhttpd.c +++ b/examples/tinyhttpd.c @@ -6,10 +6,10 @@ * @server bin/tinyhttpd 8000 * * @client bin/curl -v http://127.0.0.1:8000/ - * bin/curl -v http://127.0.0.1:8000/ping + * bin/curl -v http://127.0.0.1:8000/plaintext * bin/curl -v http://127.0.0.1:8000/echo -d "hello,world!" * - * @webbench bin/wrk http://127.0.0.1:8000/ping + * @webbench bin/wrk http://127.0.0.1:8000/plaintext * */ @@ -95,10 +95,16 @@ typedef struct { http_msg_t response; } http_conn_t; -static char s_date[32] = {0}; +static char s_date[32] = "Sun, 15 May 2022 12:34:56 GMT"; +static char s_plaintext_response_str[256] = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\nContent-Type: text/plain\r\nServer: libhv\r\nDate: Sun, 15 May 2022 12:34:56 GMT\r\n\r\nHello, World!"; +static int s_plaintext_response_len = 0; +static char* s_plaintext_date = NULL; static void update_date(htimer_t* timer) { uint64_t now = hloop_now(hevent_loop(timer)); gmtime_fmt(now, s_date); + if (s_plaintext_date) { + memcpy(s_plaintext_date, s_date, GMTIME_FMT_BUFLEN - 1); + } } static int http_response_dump(http_msg_t* msg, char* buf, int len) { @@ -106,17 +112,15 @@ static int http_response_dump(http_msg_t* msg, char* buf, int len) { // status line offset += snprintf(buf + offset, len - offset, "HTTP/%d.%d %d %s\r\n", msg->major_version, msg->minor_version, msg->status_code, msg->status_message); // headers - offset += snprintf(buf + offset, len - offset, "Server: libhv/%s\r\n", hv_version()); - offset += snprintf(buf + offset, len - offset, "Connection: %s\r\n", msg->keepalive ? "keep-alive" : "close"); if (msg->content_length > 0) { offset += snprintf(buf + offset, len - offset, "Content-Length: %d\r\n", msg->content_length); } if (*msg->content_type) { offset += snprintf(buf + offset, len - offset, "Content-Type: %s\r\n", msg->content_type); } - if (*s_date) { - offset += snprintf(buf + offset, len - offset, "Date: %s\r\n", s_date); - } + offset += snprintf(buf + offset, len - offset, "Server: libhv/%s\r\n", hv_version()); + offset += snprintf(buf + offset, len - offset, "Date: %s\r\n", s_date); + // offset += snprintf(buf + offset, len - offset, "Connection: %s\r\n", msg->keepalive ? "keep-alive" : "close"); // TODO: Add your headers offset += snprintf(buf + offset, len - offset, "\r\n"); // body @@ -199,7 +203,22 @@ static int http_serve_file(http_conn_t* conn) { static bool parse_http_request_line(http_conn_t* conn, char* buf, int len) { // GET / HTTP/1.1 http_msg_t* req = &conn->request; - sscanf(buf, "%s %s HTTP/%d.%d", req->method, req->path, &req->major_version, &req->minor_version); + // sscanf is slow + // sscanf(buf, "%s %s HTTP/%d.%d", req->method, req->path, &req->major_version, &req->minor_version); + + // method + char* src = buf; + char* dst = req->method; + while (*src != ' ') *dst++ = *src++; + *dst = '\0'; + // path + ++src; + dst = req->path; + while (*src != ' ') *dst++ = *src++; + *dst = '\0'; + + req->major_version = 1; + req->minor_version = 1; if (req->major_version != 1) return false; if (req->minor_version == 1) req->keepalive = 1; // printf("%s %s HTTP/%d.%d\r\n", req->method, req->path, req->major_version, req->minor_version); @@ -236,9 +255,10 @@ static int on_request(http_conn_t* conn) { http_msg_t* req = &conn->request; // TODO: router if (strcmp(req->method, "GET") == 0) { - // GET /ping HTTP/1.1\r\n - if (strcmp(req->path, "/ping") == 0) { - http_reply(conn, 200, "OK", TEXT_PLAIN, "pong", 4); + // GET /plaintext HTTP/1.1\r\n + if (strcmp(req->path, "/plaintext") == 0) { + // http_reply(conn, 200, "OK", TEXT_PLAIN, "Hello, World!", 13); + hio_write(conn->io, s_plaintext_response_str, s_plaintext_response_len); return 200; } else { // TODO: Add handler for your path @@ -305,12 +325,14 @@ static void on_recv(hio_t* io, void* buf, int readbytes) { if (readbytes == 2 && str[0] == '\r' && str[1] == '\n') { conn->state = s_head_end; } else { + /* str[readbytes - 2] = '\0'; if (parse_http_head(conn, str, readbytes - 2) == false) { fprintf(stderr, "Failed to parse http head:\n%s\n", str); hio_close(io); return; } + */ hio_readline(io); break; } @@ -345,8 +367,8 @@ static void on_recv(hio_t* io, void* buf, int readbytes) { if (req->keepalive) { // Connection: keep-alive\r\n // reset and receive next request - memset(&conn->request, 0, sizeof(http_msg_t)); - memset(&conn->response, 0, sizeof(http_msg_t)); + // memset(&conn->request, 0, sizeof(http_msg_t)); + // memset(&conn->response, 0, sizeof(http_msg_t)); conn->state = s_first_line; hio_readline(io); } else { @@ -375,7 +397,7 @@ static void new_conn_event(hevent_t* ev) { hio_setcb_close(io, on_close); hio_setcb_read(io, on_recv); - hio_set_keepalive_timeout(io, HTTP_KEEPALIVE_TIMEOUT); + // hio_set_keepalive_timeout(io, HTTP_KEEPALIVE_TIMEOUT); http_conn_t* conn = NULL; HV_ALLOC_SIZEOF(conn); @@ -395,6 +417,7 @@ static hloop_t* get_next_loop() { } static void on_accept(hio_t* io) { + tcp_nodelay(hio_fd(io), 1); hio_detach(io); hloop_t* worker_loop = get_next_loop(); @@ -418,9 +441,12 @@ static HTHREAD_ROUTINE(accept_thread) { if (listenio == NULL) { exit(1); } + tcp_nodelay(hio_fd(listenio), 1); printf("tinyhttpd listening on %s:%d, listenfd=%d, thread_num=%d\n", host, port, hio_fd(listenio), thread_num); // NOTE: add timer to update date every 1s + s_plaintext_response_len = strlen(s_plaintext_response_str); + s_plaintext_date = strstr(s_plaintext_response_str, "Date: ") + 6; htimer_add(loop, update_date, 1000, INFINITE); hloop_run(loop); return 0; @@ -442,7 +468,14 @@ int main(int argc, char** argv) { worker_loops = (hloop_t**)malloc(sizeof(hloop_t*) * thread_num); for (int i = 0; i < thread_num; ++i) { worker_loops[i] = hloop_new(HLOOP_FLAG_AUTO_FREE); - hthread_create(worker_thread, worker_loops[i]); + hthread_t th = hthread_create(worker_thread, worker_loops[i]); +#if defined(OS_LINUX) && HAVE_PTHREAD_H + cpu_set_t mask; + CPU_ZERO(&mask); + CPU_SET(i, &mask); + // printf("pthread_setaffinity_np %d\n", i); + pthread_setaffinity_np(th, sizeof(cpu_set_t), &mask); +#endif } accept_loop = hloop_new(HLOOP_FLAG_AUTO_FREE);