refactor: cleanup HTTP response logic

main
Sean McBride 4 years ago
parent 81e3a88a1f
commit 8d1b447e74

@ -72,6 +72,12 @@ struct sandbox {
/* The variable name "list" is used for ps_list's default name-based MACROS. */ /* The variable name "list" is used for ps_list's default name-based MACROS. */
struct ps_list list; struct ps_list list;
/*
* The length of the HTTP Request.
* This acts as an offset to the STDOUT of the Sandbox
*/
ssize_t request_length;
ssize_t request_response_data_length; /* Should be <= module->max_request_or_response_size */ ssize_t request_response_data_length; /* Should be <= module->max_request_or_response_size */
char request_response_data[1]; /* of request_response_data_length, following sandbox mem.. */ char request_response_data[1]; /* of request_response_data_length, following sandbox mem.. */
} PAGE_ALIGNED; } PAGE_ALIGNED;

@ -104,9 +104,14 @@ typedef void (*mod_libc_fn_t)(int32_t, int32_t);
#define HTTP_MAX_HEADER_LENGTH 32 #define HTTP_MAX_HEADER_LENGTH 32
#define HTTP_MAX_HEADER_VALUE_LENGTH 64 #define HTTP_MAX_HEADER_VALUE_LENGTH 64
#define HTTP_RESPONSE_200_OK "HTTP/1.1 200 OK\r\n" #define HTTP_RESPONSE_200_OK "HTTP/1.1 200 OK\r\n"
#define HTTP_RESPONSE_CONTENT_LENGTH "Content-length: \r\n\r\n" /* content body follows this */
#define HTTP_RESPONSE_CONTENT_TYPE "Content-type: \r\n" #define HTTP_RESPONSE_CONTENT_LENGTH "Content-length: "
#define HTTP_RESPONSE_CONTENT_LENGTH_TERMINATOR " \r\n\r\n" /* content body follows this */
#define HTTP_RESPONSE_CONTENT_TYPE "Content-type: "
#define HTTP_RESPONSE_CONTENT_TYPE_PLAIN "text/plain" #define HTTP_RESPONSE_CONTENT_TYPE_PLAIN "text/plain"
#define HTTP_RESPONSE_CONTENT_TYPE_TERMINATOR " \r\n"
#define JSON_MAX_ELEMENT_COUNT 16 #define JSON_MAX_ELEMENT_COUNT 16
#define JSON_MAX_ELEMENT_SIZE 1024 #define JSON_MAX_ELEMENT_SIZE 1024

@ -106,6 +106,7 @@ sandbox_receive_and_parse_client_request(struct sandbox *sandbox)
return 0 return 0
}; };
#endif #endif
sandbox->request_length = sandbox->request_response_data_length;
return 1; return 1;
} }
@ -118,37 +119,73 @@ sandbox_build_and_send_client_response(struct sandbox *sandbox)
{ {
assert(sandbox != NULL); assert(sandbox != NULL);
int sndsz = 0; /*
int response_header_length = strlen(HTTP_RESPONSE_200_OK) + strlen(HTTP_RESPONSE_CONTENT_TYPE) * At this point the HTTP Request has filled the buffer up to request_length, after which
+ strlen(HTTP_RESPONSE_CONTENT_LENGTH); * the STDOUT of the sandbox has been appended. We assume that our HTTP Response header is
int body_length = sandbox->request_response_data_length - response_header_length; * smaller than the HTTP Request header, which allows us to use memmove once without copying
* to an intermediate buffer.
*/
memset(sandbox->request_response_data, 0, sandbox->request_length);
/*
* We use this cursor to keep track of our position in the buffer and later assert that we
* haven't overwritten body data.
*/
size_t response_cursor = 0;
memset(sandbox->request_response_data, 0, /* Append 200 OK */
strlen(HTTP_RESPONSE_200_OK) + strlen(HTTP_RESPONSE_CONTENT_TYPE)
+ strlen(HTTP_RESPONSE_CONTENT_LENGTH));
strncpy(sandbox->request_response_data, HTTP_RESPONSE_200_OK, strlen(HTTP_RESPONSE_200_OK)); strncpy(sandbox->request_response_data, HTTP_RESPONSE_200_OK, strlen(HTTP_RESPONSE_200_OK));
sndsz += strlen(HTTP_RESPONSE_200_OK); response_cursor += strlen(HTTP_RESPONSE_200_OK);
/* Content Type */
strncpy(sandbox->request_response_data + response_cursor, HTTP_RESPONSE_CONTENT_TYPE,
strlen(HTTP_RESPONSE_CONTENT_TYPE));
response_cursor += strlen(HTTP_RESPONSE_CONTENT_TYPE);
if (body_length == 0) goto done; /* Custom content type if provided, text/plain by default */
strncpy(sandbox->request_response_data + sndsz, HTTP_RESPONSE_CONTENT_TYPE, strlen(HTTP_RESPONSE_CONTENT_TYPE));
if (strlen(sandbox->module->response_content_type) <= 0) { if (strlen(sandbox->module->response_content_type) <= 0) {
strncpy(sandbox->request_response_data + sndsz + strlen("Content-type: "), strncpy(sandbox->request_response_data + response_cursor, HTTP_RESPONSE_CONTENT_TYPE_PLAIN,
HTTP_RESPONSE_CONTENT_TYPE_PLAIN, strlen(HTTP_RESPONSE_CONTENT_TYPE_PLAIN)); strlen(HTTP_RESPONSE_CONTENT_TYPE_PLAIN));
response_cursor += strlen(HTTP_RESPONSE_CONTENT_TYPE_PLAIN);
} else { } else {
strncpy(sandbox->request_response_data + sndsz + strlen("Content-type: "), strncpy(sandbox->request_response_data + response_cursor, sandbox->module->response_content_type,
sandbox->module->response_content_type, strlen(sandbox->module->response_content_type)); strlen(sandbox->module->response_content_type));
response_cursor += strlen(sandbox->module->response_content_type);
} }
sndsz += strlen(HTTP_RESPONSE_CONTENT_TYPE);
char len[10] = { 0 }; strncpy(sandbox->request_response_data + response_cursor, HTTP_RESPONSE_CONTENT_TYPE_TERMINATOR,
sprintf(len, "%d", body_length); strlen(HTTP_RESPONSE_CONTENT_TYPE_TERMINATOR));
strncpy(sandbox->request_response_data + sndsz, HTTP_RESPONSE_CONTENT_LENGTH, response_cursor += strlen(HTTP_RESPONSE_CONTENT_TYPE_TERMINATOR);
/* Content Length */
strncpy(sandbox->request_response_data + response_cursor, HTTP_RESPONSE_CONTENT_LENGTH,
strlen(HTTP_RESPONSE_CONTENT_LENGTH)); strlen(HTTP_RESPONSE_CONTENT_LENGTH));
strncpy(sandbox->request_response_data + sndsz + strlen("Content-length: "), len, strlen(len)); response_cursor += strlen(HTTP_RESPONSE_CONTENT_LENGTH);
sndsz += strlen(HTTP_RESPONSE_CONTENT_LENGTH);
sndsz += body_length;
done: size_t body_size = sandbox->request_response_data_length - sandbox->request_length;
assert(sndsz == sandbox->request_response_data_length);
char len[10] = { 0 };
sprintf(len, "%zu", body_size);
strncpy(sandbox->request_response_data + response_cursor, len, strlen(len));
response_cursor += strlen(len);
strncpy(sandbox->request_response_data + response_cursor, HTTP_RESPONSE_CONTENT_LENGTH_TERMINATOR,
strlen(HTTP_RESPONSE_CONTENT_LENGTH_TERMINATOR));
response_cursor += strlen(HTTP_RESPONSE_CONTENT_LENGTH_TERMINATOR);
/*
* Assumption: Our response header is smaller than the request header, so we do not overwrite
* actual data that the program appended to the HTTP Request. If proves to be a bad assumption,
* we have to copy the STDOUT string to a temporary buffer before writing the header
*/
assert(response_cursor < sandbox->request_length);
/* Move the Sandbox's Data after the HTTP Response Data */
memmove(sandbox->request_response_data + response_cursor - 1,
sandbox->request_response_data + sandbox->request_length, body_size);
response_cursor += body_size;
/* Capture Timekeeping data for end-to-end latency */
uint64_t end_time = __getcycles(); uint64_t end_time = __getcycles();
sandbox->total_time = end_time - sandbox->request_arrival_timestamp; sandbox->total_time = end_time - sandbox->request_arrival_timestamp;
uint64_t total_time_us = sandbox->total_time / runtime_processor_speed_MHz; uint64_t total_time_us = sandbox->total_time / runtime_processor_speed_MHz;
@ -157,13 +194,14 @@ done:
sandbox->module->relative_deadline_us, total_time_us); sandbox->module->relative_deadline_us, total_time_us);
#ifndef USE_HTTP_UVIO #ifndef USE_HTTP_UVIO
int r = send(sandbox->client_socket_descriptor, sandbox->request_response_data, sndsz, 0); int r = send(sandbox->client_socket_descriptor, sandbox->request_response_data, response_cursor, 0);
if (r < 0) { if (r < 0) {
perror("send"); perror("send");
return -1; return -1;
} }
while (r < sndsz) { while (r < response_cursor) {
int s = send(sandbox->client_socket_descriptor, sandbox->request_response_data + r, sndsz - r, 0); int s = send(sandbox->client_socket_descriptor, sandbox->request_response_data + r, response_cursor - r,
0);
if (s < 0) { if (s < 0) {
perror("send"); perror("send");
return -1; return -1;
@ -174,7 +212,7 @@ done:
uv_write_t req = { uv_write_t req = {
.data = sandbox, .data = sandbox,
}; };
uv_buf_t bufv = uv_buf_init(sandbox->request_response_data, sndsz); uv_buf_t bufv = uv_buf_init(sandbox->request_response_data, response_cursor);
int r = uv_write(&req, (uv_stream_t *)&sandbox->client_libuv_stream, &bufv, 1, int r = uv_write(&req, (uv_stream_t *)&sandbox->client_libuv_stream, &bufv, 1,
libuv_callbacks_on_write_wakeup_sandbox); libuv_callbacks_on_write_wakeup_sandbox);
worker_thread_process_io(); worker_thread_process_io();

Loading…
Cancel
Save