diff --git a/runtime/include/http.h b/runtime/include/http.h index df3b9f5..cab6f34 100644 --- a/runtime/include/http.h +++ b/runtime/include/http.h @@ -13,12 +13,17 @@ #define HTTP_MAX_QUERY_PARAM_COUNT 16 #define HTTP_MAX_QUERY_PARAM_LENGTH 32 -#define HTTP_RESPONSE_200_OK \ - "HTTP/1.1 200 OK\r\n" \ - "Server: SLEdge\r\n" \ - "Connection: close\r\n" \ +#define HTTP_RESPONSE_200_TEMPLATE \ + "HTTP/1.1 200 OK\r\n" \ + "Server: SLEdge\r\n" \ + "Connection: close\r\n" \ + "Content-Type: %s\r\n" \ + "Content-Length: %lu\r\n" \ "\r\n" +/* The sum of format specifier characters in the template above */ +#define HTTP_RESPONSE_200_TEMPLATE_FORMAT_SPECIFIER_LENGTH 5 + #define HTTP_RESPONSE_400_BAD_REQUEST \ "HTTP/1.1 400 Bad Request\r\n" \ "Server: SLEdge\r\n" \ @@ -61,10 +66,6 @@ http_header_build(int status_code) const char *response; int rc; switch (status_code) { - case 200: - response = HTTP_RESPONSE_200_OK; - http_total_increment_2XX(); - break; case 400: response = HTTP_RESPONSE_400_BAD_REQUEST; http_total_increment_4XX(); @@ -100,8 +101,6 @@ static inline size_t http_header_len(int status_code) { switch (status_code) { - case 200: - return strlen(HTTP_RESPONSE_200_OK); case 400: return strlen(HTTP_RESPONSE_400_BAD_REQUEST); case 404: diff --git a/runtime/include/http_session.h b/runtime/include/http_session.h index ad2b6cf..5e3acf8 100644 --- a/runtime/include/http_session.h +++ b/runtime/include/http_session.h @@ -38,6 +38,8 @@ enum http_session_state HTTP_SESSION_SENT_RESPONSE }; +#define HTTP_SESSION_RESPONSE_HEADER_CAPACITY 256 + struct http_session { enum http_session_state state; struct sockaddr client_address; /* client requesting connection! */ @@ -45,7 +47,7 @@ struct http_session { struct http_parser http_parser; struct http_request http_request; struct vec_u8 request_buffer; - const char *response_header; + char response_header[HTTP_SESSION_RESPONSE_HEADER_CAPACITY]; size_t response_header_length; size_t response_header_written; struct vec_u8 response_buffer; @@ -161,13 +163,25 @@ http_session_free(struct http_session *session) * @param status_code */ static inline void -http_session_set_response_header(struct http_session *session, int status_code) +http_session_set_response_header(struct http_session *session, int status_code, const char *content_type, + size_t content_length) { assert(session != NULL); - assert(status_code >= 100 && status_code <= 599); - - session->response_header = http_header_build(status_code); - session->response_header_length = http_header_len(status_code); + assert(status_code >= 200 && status_code <= 599); + + if (status_code == 200) { + session->response_header_length = snprintf(session->response_header, + HTTP_SESSION_RESPONSE_HEADER_CAPACITY, + HTTP_RESPONSE_200_TEMPLATE, content_type, content_length); + } else { + size_t header_len = http_header_len(status_code); + size_t to_copy = HTTP_SESSION_RESPONSE_HEADER_CAPACITY < header_len + ? HTTP_SESSION_RESPONSE_HEADER_CAPACITY + : header_len; + + strncpy(session->response_header, http_header_build(status_code), to_copy - 1); + session->response_header_length = to_copy; + } } static inline void @@ -215,7 +229,6 @@ static inline int http_session_send_response_body(struct http_session *session, void_star_cb on_eagain) { assert(session != NULL); - assert(session->response_buffer.buffer != NULL); while (session->response_buffer_written < session->response_buffer.length) { ssize_t sent = @@ -367,11 +380,14 @@ http_session_receive_request(struct http_session *session, void_star_cb on_eagai (char *)&session->request_buffer.buffer[session->request_buffer.length], session->request_buffer.capacity - session->request_buffer.length, on_eagain, session); - if (bytes_received == -EAGAIN) goto err_eagain; + if (bytes_received == -3) goto err_eagain; if (bytes_received == -1) goto err; /* If we received an EOF before we were able to parse a complete HTTP message, request is malformed */ if (bytes_received == 0 && !session->http_request.message_end) goto err; + assert(bytes_received > 0); + assert(session->request_buffer.length < session->request_buffer.capacity); + session->request_buffer.length += bytes_received; ssize_t bytes_parsed = http_session_parse(session, bytes_received); diff --git a/runtime/include/sandbox_set_as_error.h b/runtime/include/sandbox_set_as_error.h index 4b949d8..35b6be9 100644 --- a/runtime/include/sandbox_set_as_error.h +++ b/runtime/include/sandbox_set_as_error.h @@ -59,7 +59,7 @@ sandbox_set_as_error(struct sandbox *sandbox, sandbox_state_t last_state) admissions_control_subtract(sandbox->admissions_estimate); /* Return HTTP session to listener core to be written back to client */ - http_session_set_response_header(sandbox->http, 500); + http_session_set_response_header(sandbox->http, 500, NULL, 0); sandbox->http->state = HTTP_SESSION_EXECUTION_COMPLETE; http_session_send_response(sandbox->http, (void_star_cb)listener_thread_register_http_session); sandbox->http = NULL; diff --git a/runtime/include/sandbox_set_as_returned.h b/runtime/include/sandbox_set_as_returned.h index f54e49a..3a20fc9 100644 --- a/runtime/include/sandbox_set_as_returned.h +++ b/runtime/include/sandbox_set_as_returned.h @@ -51,7 +51,8 @@ sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state) sandbox_state_totals_increment(SANDBOX_RETURNED); sandbox_state_totals_decrement(last_state); - http_session_set_response_header(sandbox->http, 200); + http_session_set_response_header(sandbox->http, 200, sandbox->route->response_content_type, + sandbox->http->response_buffer.length); sandbox->http->state = HTTP_SESSION_EXECUTION_COMPLETE; http_session_send_response(sandbox->http, (void_star_cb)listener_thread_register_http_session); sandbox->http = NULL; diff --git a/runtime/src/listener_thread.c b/runtime/src/listener_thread.c index 14202cb..5ab1c65 100644 --- a/runtime/src/listener_thread.c +++ b/runtime/src/listener_thread.c @@ -164,7 +164,7 @@ on_client_request_arrival(int client_socket, const struct sockaddr *client_addre /* Failed to allocate memory */ debuglog("Failed to allocate http session\n"); session->state = HTTP_SESSION_EXECUTION_COMPLETE; - http_session_set_response_header(session, 500); + http_session_set_response_header(session, 500, NULL, 0); on_client_response_header_sending(session); return; } @@ -185,13 +185,13 @@ on_client_request_receiving(struct http_session *session) /* Failed to grow request buffer */ debuglog("Failed to grow http request buffer\n"); session->state = HTTP_SESSION_EXECUTION_COMPLETE; - http_session_set_response_header(session, 500); + http_session_set_response_header(session, 500, NULL, 0); on_client_response_header_sending(session); return; } else if (rc == -1) { debuglog("Failed to receive or parse request\n"); session->state = HTTP_SESSION_EXECUTION_COMPLETE; - http_session_set_response_header(session, 400); + http_session_set_response_header(session, 400, NULL, 0); on_client_response_header_sending(session); return; } @@ -208,7 +208,7 @@ on_client_request_received(struct http_session *session) if (route == NULL) { debuglog("Did not match any routes\n"); session->state = HTTP_SESSION_EXECUTION_COMPLETE; - http_session_set_response_header(session, 404); + http_session_set_response_header(session, 404, NULL, 0); on_client_response_header_sending(session); return; } @@ -221,7 +221,7 @@ on_client_request_received(struct http_session *session) uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate); if (work_admitted == 0) { session->state = HTTP_SESSION_EXECUTION_COMPLETE; - http_session_set_response_header(session, 429); + http_session_set_response_header(session, 429, NULL, 0); on_client_response_header_sending(session); return; } @@ -232,7 +232,7 @@ on_client_request_received(struct http_session *session) if (unlikely(sandbox == NULL)) { debuglog("Failed to allocate sandbox\n"); session->state = HTTP_SESSION_EXECUTION_COMPLETE; - http_session_set_response_header(session, 500); + http_session_set_response_header(session, 500, NULL, 0); on_client_response_header_sending(session); return; } @@ -242,7 +242,7 @@ on_client_request_received(struct http_session *session) debuglog("Failed to add sandbox to global queue\n"); sandbox_free(sandbox); session->state = HTTP_SESSION_EXECUTION_COMPLETE; - http_session_set_response_header(session, 429); + http_session_set_response_header(session, 429, NULL, 0); on_client_response_header_sending(session); } }