|
|
@ -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();
|
|
|
|