refactor: cleanup response header logic

mmap-opt
Sean McBride 4 years ago
parent a9d3b3199f
commit 29af1d7fa5

@ -3,6 +3,7 @@
#include <assert.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
@ -32,54 +33,54 @@ client_socket_close(int client_socket, struct sockaddr *client_address)
}
}
typedef void (*void_cb)(void);
/**
* Rejects request due to admission control or error
* @param client_socket - the client we are rejecting
* @param status_code - either 503 or 400
* @param buffer - buffer to write to socket
* @param on_eagain - cb to execute when client socket returns EAGAIN. If NULL, error out
* @returns 0
*/
static inline int
client_socket_send(int client_socket, int status_code)
client_socket_send(int client_socket, const char *buffer, size_t buffer_len, void_cb on_eagain)
{
const char *response;
int rc;
switch (status_code) {
case 503:
response = HTTP_RESPONSE_503_SERVICE_UNAVAILABLE;
http_total_increment_5XX();
break;
case 413:
response = HTTP_RESPONSE_413_PAYLOAD_TOO_LARGE;
http_total_increment_4XX();
break;
case 400:
response = HTTP_RESPONSE_400_BAD_REQUEST;
http_total_increment_4XX();
break;
default:
panic("%d is not a valid status code\n", status_code);
}
int rc;
size_t total_sent = 0;
size_t to_send = strlen(response);
size_t cursor = 0;
while (total_sent < to_send) {
ssize_t sent = write(client_socket, &response[total_sent], to_send - total_sent);
while (cursor < buffer_len) {
ssize_t sent = write(client_socket, &buffer[cursor], buffer_len - cursor);
if (sent < 0) {
if (errno == EAGAIN) {
debuglog("Unexpectedly blocking on write of %s\n", response);
if (on_eagain) {
on_eagain();
} else {
rc = -1;
goto done;
}
} else {
debuglog("Error with %s\n", strerror(errno));
goto send_err;
debuglog("Error sending to client: %s", strerror(errno));
rc = -1;
goto done;
}
}
total_sent += sent;
cursor += sent;
};
rc = 0;
done:
return rc;
send_err:
debuglog("Error sending to client: %s", strerror(errno));
rc = -1;
goto done;
}
/**
* Rejects request due to admission control or error
* @param client_socket - the client we are rejecting
* @param buffer - buffer to write to socket
* @returns 0
*/
static inline int
client_socket_send_oneshot(int client_socket, const char *buffer, size_t buffer_len)
{
return client_socket_send(client_socket, buffer, buffer_len, NULL);
}

@ -38,43 +38,20 @@ current_sandbox_send_response()
uint64_t end_time = __getcycles();
sandbox->total_time = end_time - sandbox->timestamp_of.request_arrival;
/* Send HTTP Response Headers */
ssize_t response_size = http_response_200_size(content_type, response_body_size);
char header_buffer[response_size + 1];
rc = sprintf(header_buffer, HTTP_RESPONSE_200_TEMPLATE, content_type, response_body_size);
/* Generate and send HTTP Response Headers */
ssize_t response_header_size = http_response_200_size(content_type, response_body_size);
char response_header_buffer[response_header_size + 1];
rc = http_header_200_build(response_header_buffer, content_type, response_body_size);
if (rc <= 0) {
perror("sprintf");
goto err;
}
while (sent < response_size) {
rc = write(sandbox->client_socket_descriptor, &header_buffer[sent], response_size - sent);
if (rc < 0) {
if (errno == EAGAIN)
current_sandbox_sleep();
else {
perror("write");
goto err;
}
}
sent += rc;
}
client_socket_send(sandbox->client_socket_descriptor, response_header_buffer, response_header_size,
current_sandbox_sleep);
/* Send HTTP Response Body */
sent = 0;
response_size = response_body_size;
while (sent < response_size) {
rc = write(sandbox->client_socket_descriptor, &sandbox->response.base[sent], response_size - sent);
if (rc < 0) {
if (errno == EAGAIN)
current_sandbox_sleep();
else {
perror("write");
goto err;
}
}
sent += rc;
}
client_socket_send(sandbox->client_socket_descriptor, sandbox->response.base, response_body_size,
current_sandbox_sleep);
http_total_increment_2xx();
rc = 0;

@ -2,6 +2,9 @@
#include <string.h>
#include "http_total.h"
#include "panic.h"
#define HTTP_MAX_HEADER_COUNT 16
#define HTTP_MAX_HEADER_LENGTH 32
#define HTTP_MAX_HEADER_VALUE_LENGTH 64
@ -54,3 +57,49 @@ http_response_200_size(const char *content_type, ssize_t content_length)
return size;
}
static inline int
http_header_200_build(char *buffer, const char *content_type, ssize_t content_length)
{
return sprintf(buffer, HTTP_RESPONSE_200_TEMPLATE, content_type, content_length);
}
static inline const char *
http_header_build(int status_code)
{
const char *response;
int rc;
switch (status_code) {
case 503:
response = HTTP_RESPONSE_503_SERVICE_UNAVAILABLE;
http_total_increment_5XX();
break;
case 413:
response = HTTP_RESPONSE_413_PAYLOAD_TOO_LARGE;
http_total_increment_4XX();
break;
case 400:
response = HTTP_RESPONSE_400_BAD_REQUEST;
http_total_increment_4XX();
break;
default:
panic("%d is not a valid status code\n", status_code);
}
return response;
}
static inline int
http_header_len(int status_code)
{
switch (status_code) {
case 503:
return strlen(HTTP_RESPONSE_503_SERVICE_UNAVAILABLE);
case 413:
return strlen(HTTP_RESPONSE_413_PAYLOAD_TOO_LARGE);
case 400:
return strlen(HTTP_RESPONSE_400_BAD_REQUEST);
default:
panic("%d is not a valid status code\n", status_code);
}
}

@ -58,7 +58,7 @@ scheduler_edf_get_next()
done:
return local_runqueue_get_next();
err_allocate:
client_socket_send(request->socket_descriptor, 503);
client_socket_send_oneshot(request->socket_descriptor, http_header_build(503), http_header_len(503));
client_socket_close(request->socket_descriptor, &request->socket_address);
free(request);
goto done;
@ -89,7 +89,7 @@ scheduler_fifo_get_next()
done:
return sandbox;
err_allocate:
client_socket_send(sandbox_request->socket_descriptor, 503);
client_socket_send_oneshot(sandbox_request->socket_descriptor, http_header_build(503), http_header_len(503));
client_socket_close(sandbox_request->socket_descriptor, &sandbox->client_address);
free(sandbox_request);
err:

@ -63,7 +63,8 @@ scheduler_execute_epoll_loop(void)
case SANDBOX_ERROR:
panic("Expected to have closed socket");
default:
client_socket_send(sandbox->client_socket_descriptor, 503);
client_socket_send_oneshot(sandbox->client_socket_descriptor,
http_header_build(503), http_header_len(503));
sandbox_close_http(sandbox);
sandbox_set_as_error(sandbox, sandbox->state);
}

@ -113,10 +113,12 @@ current_sandbox_init()
rc = sandbox_receive_request(sandbox);
if (rc == -2) {
/* Request size exceeded Buffer, send 413 Payload Too Large */
client_socket_send(sandbox->client_socket_descriptor, 413);
client_socket_send(sandbox->client_socket_descriptor, http_header_build(413), http_header_len(413),
current_sandbox_sleep);
goto err;
} else if (rc == -1) {
client_socket_send(sandbox->client_socket_descriptor, 400);
client_socket_send(sandbox->client_socket_descriptor, http_header_build(400), http_header_len(400),
current_sandbox_sleep);
goto err;
}

@ -169,7 +169,8 @@ listener_thread_main(void *dummy)
*/
uint64_t work_admitted = admissions_control_decide(module->admissions_info.estimate);
if (work_admitted == 0) {
client_socket_send(client_socket, 503);
client_socket_send_oneshot(client_socket, http_header_build(503),
http_header_len(503));
if (unlikely(close(client_socket) < 0))
debuglog("Error closing client socket - %s", strerror(errno));

Loading…
Cancel
Save