mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-18 02:39:44 +00:00
Refactor rhizome HTTP response headers
This commit is contained in:
parent
41f3228300
commit
dd225bbb7f
208
rhizome_http.c
208
rhizome_http.c
@ -72,13 +72,12 @@ typedef struct rhizome_http_request {
|
||||
|
||||
} rhizome_http_request;
|
||||
|
||||
int rhizome_server_free_http_request(rhizome_http_request *r);
|
||||
int rhizome_server_http_send_bytes(rhizome_http_request *r);
|
||||
int rhizome_server_parse_http_request(rhizome_http_request *r);
|
||||
int rhizome_server_simple_http_response(rhizome_http_request *r,int result, char *response);
|
||||
int rhizome_server_http_response_header(rhizome_http_request *r,int result,
|
||||
char *mime_type,unsigned long long bytes);
|
||||
int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *table, char *column);
|
||||
static int rhizome_server_free_http_request(rhizome_http_request *r);
|
||||
static int rhizome_server_http_send_bytes(rhizome_http_request *r);
|
||||
static int rhizome_server_parse_http_request(rhizome_http_request *r);
|
||||
static int rhizome_server_simple_http_response(rhizome_http_request *r, int result, const char *response);
|
||||
static int rhizome_server_http_response_header(rhizome_http_request *r, int result, const char *mime_type, unsigned long long bytes);
|
||||
static int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *table, char *column);
|
||||
|
||||
#define RHIZOME_SERVER_MAX_LIVE_REQUESTS 32
|
||||
|
||||
@ -283,7 +282,8 @@ void rhizome_server_poll(struct sched_ent *alarm)
|
||||
while ((sock = accept(rhizome_server_socket, &addr, &addr_len)) != -1) {
|
||||
if (addr.sa_family == AF_INET) {
|
||||
struct sockaddr_in *peerip = (struct sockaddr_in *)&addr;
|
||||
INFOF("HTTP ACCEPT addrlen=%u family=%u port=%u addr=%u.%u.%u.%u",
|
||||
if (debug & DEBUG_RHIZOME_TX)
|
||||
DEBUGF("HTTP ACCEPT addrlen=%u family=%u port=%u addr=%u.%u.%u.%u",
|
||||
addr_len, peerip->sin_family, peerip->sin_port,
|
||||
((unsigned char*)&peerip->sin_addr.s_addr)[0],
|
||||
((unsigned char*)&peerip->sin_addr.s_addr)[1],
|
||||
@ -291,40 +291,48 @@ void rhizome_server_poll(struct sched_ent *alarm)
|
||||
((unsigned char*)&peerip->sin_addr.s_addr)[3]
|
||||
);
|
||||
} else {
|
||||
INFOF("HTTP ACCEPT addrlen=%u family=%u data=%s",
|
||||
if (debug & DEBUG_RHIZOME_TX)
|
||||
DEBUGF("HTTP ACCEPT addrlen=%u family=%u data=%s",
|
||||
addr_len, addr.sa_family, alloca_tohex((unsigned char *)addr.sa_data, sizeof addr.sa_data));
|
||||
}
|
||||
rhizome_http_request *request = calloc(sizeof(rhizome_http_request),1);
|
||||
/* We are now trying to read the HTTP request */
|
||||
request->request_type=RHIZOME_HTTP_REQUEST_RECEIVING;
|
||||
request->alarm.function = rhizome_client_poll;
|
||||
connection_stats.name="rhizome_client_poll";
|
||||
request->alarm.stats=&connection_stats;
|
||||
request->alarm.poll.fd=sock;
|
||||
request->alarm.poll.events=POLLIN;
|
||||
request->alarm.alarm = overlay_gettime_ms()+RHIZOME_IDLE_TIMEOUT;
|
||||
// watch for the incoming http request
|
||||
watch(&request->alarm);
|
||||
// set an inactivity timeout to close the connection
|
||||
schedule(&request->alarm);
|
||||
rhizome_http_request *request = calloc(sizeof(rhizome_http_request), 1);
|
||||
if (request == NULL) {
|
||||
WHYF_perror("calloc(%u, 1)", sizeof(rhizome_http_request));
|
||||
WHY("Cannot respond to request, out of memory");
|
||||
} else {
|
||||
/* We are now trying to read the HTTP request */
|
||||
request->request_type=RHIZOME_HTTP_REQUEST_RECEIVING;
|
||||
request->alarm.function = rhizome_client_poll;
|
||||
connection_stats.name="rhizome_client_poll";
|
||||
request->alarm.stats=&connection_stats;
|
||||
request->alarm.poll.fd=sock;
|
||||
request->alarm.poll.events=POLLIN;
|
||||
request->alarm.alarm = overlay_gettime_ms()+RHIZOME_IDLE_TIMEOUT;
|
||||
// watch for the incoming http request
|
||||
watch(&request->alarm);
|
||||
// set an inactivity timeout to close the connection
|
||||
schedule(&request->alarm);
|
||||
}
|
||||
}
|
||||
if (errno != EAGAIN) {
|
||||
WARN_perror("accept");
|
||||
}
|
||||
}
|
||||
|
||||
int rhizome_server_free_http_request(rhizome_http_request *r)
|
||||
static int rhizome_server_free_http_request(rhizome_http_request *r)
|
||||
{
|
||||
unwatch(&r->alarm);
|
||||
unschedule(&r->alarm);
|
||||
close(r->alarm.poll.fd);
|
||||
if (r->buffer&&r->buffer_size) free(r->buffer);
|
||||
if (r->blob) sqlite3_blob_close(r->blob);
|
||||
if (r->buffer)
|
||||
free(r->buffer);
|
||||
if (r->blob)
|
||||
sqlite3_blob_close(r->blob);
|
||||
free(r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rhizome_server_sql_query_http_response(rhizome_http_request *r,
|
||||
static int rhizome_server_sql_query_http_response(rhizome_http_request *r,
|
||||
char *column,char *table,char *query_body,
|
||||
int bytes_per_row,int dehexP)
|
||||
{
|
||||
@ -337,10 +345,17 @@ int rhizome_server_sql_query_http_response(rhizome_http_request *r,
|
||||
the body, although encryption is not yet implemented here.
|
||||
*/
|
||||
|
||||
if (r->buffer) { free(r->buffer); r->buffer=NULL; }
|
||||
r->buffer_size=16384;
|
||||
r->buffer=malloc(r->buffer_size);
|
||||
if (!r->buffer) return WHY_perror("malloc");
|
||||
if (r->buffer == NULL || r->buffer_size < 16384) {
|
||||
if (r->buffer)
|
||||
free(r->buffer);
|
||||
r->buffer_size = 16384;
|
||||
r->buffer = malloc(r->buffer_size);
|
||||
if (r->buffer == NULL) {
|
||||
r->buffer_size = 0;
|
||||
WHY_perror("malloc");
|
||||
return WHY("Cannot send response, out of memory");
|
||||
}
|
||||
}
|
||||
r->buffer_length=0;
|
||||
r->buffer_offset=0;
|
||||
r->source_record_size=bytes_per_row;
|
||||
@ -349,10 +364,9 @@ int rhizome_server_sql_query_http_response(rhizome_http_request *r,
|
||||
|
||||
/* Work out total response length */
|
||||
long long response_bytes=256+r->source_count*r->source_record_size;
|
||||
rhizome_server_http_response_header(r,200,"servalproject.org/rhizome-list",
|
||||
response_bytes);
|
||||
rhizome_server_http_response_header(r, 200, "servalproject.org/rhizome-list", response_bytes);
|
||||
if (debug & DEBUG_RHIZOME_TX)
|
||||
DEBUGF("headers consumed %d bytes",r->buffer_length);
|
||||
DEBUGF("headers consumed %d bytes", r->buffer_length);
|
||||
|
||||
/* Clear and prepare response header */
|
||||
bzero(&r->buffer[r->buffer_length],256);
|
||||
@ -387,7 +401,7 @@ int rhizome_server_sql_query_http_response(rhizome_http_request *r,
|
||||
return rhizome_server_sql_query_fill_buffer(r, table, column);
|
||||
}
|
||||
|
||||
int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *table, char *column)
|
||||
static int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *table, char *column)
|
||||
{
|
||||
unsigned char blob_value[r->source_record_size*2+1];
|
||||
|
||||
@ -495,7 +509,7 @@ static int strcmp_prefix(char *str, const char *prefix, char **afterp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rhizome_server_parse_http_request(rhizome_http_request *r)
|
||||
static int rhizome_server_parse_http_request(rhizome_http_request *r)
|
||||
{
|
||||
/* Switching to writing, so update the call-back */
|
||||
r->alarm.poll.events=POLLOUT;
|
||||
@ -514,7 +528,7 @@ int rhizome_server_parse_http_request(rhizome_http_request *r)
|
||||
DEBUGF("GET %s", path);
|
||||
if (strcmp(path, "/favicon.ico") == 0) {
|
||||
r->request_type = RHIZOME_HTTP_REQUEST_FAVICON;
|
||||
rhizome_server_http_response_header(r, 200, "image/vnd.microsoft.icon", favicon_len);
|
||||
rhizome_server_http_response_header(r, 200, "image/vnd.microsoft.icon", favicon_len);
|
||||
} else if (strcmp(path, "/rhizome/groups") == 0) {
|
||||
/* Return the list of known groups */
|
||||
rhizome_server_sql_query_http_response(r, "id", "groups", "from groups", 32, 1);
|
||||
@ -560,43 +574,89 @@ int rhizome_server_parse_http_request(rhizome_http_request *r)
|
||||
|
||||
|
||||
/* Return appropriate message for HTTP response codes, both known and unknown. */
|
||||
#define A_VALUE_GREATER_THAN_FOUR (2+3)
|
||||
char *httpResultString(int id) {
|
||||
switch (id) {
|
||||
case 200: return "OK"; break;
|
||||
case 206: return "Partial Content"; break;
|
||||
case 404: return "Not found"; break;
|
||||
default:
|
||||
case A_VALUE_GREATER_THAN_FOUR:
|
||||
if (id>4) return "A suffusion of yellow";
|
||||
/* The following MUST be the longest string returned by this function */
|
||||
else return "THE JUDGEMENT OF KING WEN: Chun Signifies Difficulties At Outset, As Of Blade Of Grass Pushing Up Against Stone.";
|
||||
static const char *httpResultString(int response_code) {
|
||||
switch (response_code) {
|
||||
case 200: return "OK";
|
||||
case 206: return "Partial Content";
|
||||
case 404: return "Not found";
|
||||
case 500: return "Internal server error";
|
||||
default: return "A suffusion of yellow";
|
||||
}
|
||||
}
|
||||
|
||||
int rhizome_server_simple_http_response(rhizome_http_request *r,int result, char *response)
|
||||
struct http_response {
|
||||
unsigned int result_code;
|
||||
const char * content_type;
|
||||
unsigned long long content_length;
|
||||
const char * body;
|
||||
};
|
||||
|
||||
static strbuf strbuf_build_http_response(strbuf sb, const struct http_response *h)
|
||||
{
|
||||
if (r->buffer) free(r->buffer);
|
||||
r->buffer_size=strlen(response)+strlen("HTTP/1.0 000 \r\n\r\nContent-type: text/html\r\nContent-length: 0000\r\n\r\n")+strlen(httpResultString(result))+strlen(response)+100;
|
||||
strbuf_sprintf(sb, "HTTP/1.0 %03u %s\r\n", h->result_code, httpResultString(h->result_code));
|
||||
strbuf_sprintf(sb, "Content-type: %s\r\n", h->content_type);
|
||||
strbuf_sprintf(sb, "Content-length: %llu\r\n", h->content_length);
|
||||
strbuf_puts(sb, "\r\n");
|
||||
if (h->body)
|
||||
strbuf_puts(sb, h->body);
|
||||
return sb;
|
||||
}
|
||||
|
||||
r->buffer=(unsigned char *)malloc(r->buffer_size);
|
||||
snprintf((char *)r->buffer,r->buffer_size,"HTTP/1.0 %03d %s\r\nContent-type: text/html\r\nContent-length: %d\r\n\r\n%s",result,httpResultString(result),(int)strlen(response),response);
|
||||
|
||||
r->buffer_size=strlen((char *)r->buffer)+1;
|
||||
r->buffer_length=r->buffer_size-1;
|
||||
r->buffer_offset=0;
|
||||
|
||||
r->request_type=RHIZOME_HTTP_REQUEST_FROMBUFFER;
|
||||
static int rhizome_server_set_response(rhizome_http_request *r, const struct http_response *h)
|
||||
{
|
||||
strbuf b = strbuf_local((char *) r->buffer, r->buffer_size);
|
||||
strbuf_build_http_response(b, h);
|
||||
if (r->buffer == NULL || strbuf_overrun(b)) {
|
||||
// Need a bigger buffer
|
||||
if (r->buffer)
|
||||
free(r->buffer);
|
||||
r->buffer_size = strbuf_count(b) + 1;
|
||||
r->buffer = malloc(r->buffer_size);
|
||||
if (r->buffer == NULL) {
|
||||
WHYF_perror("malloc(%u)", r->buffer_size);
|
||||
r->buffer_size = 0;
|
||||
return WHY("Cannot send response, out of memory");
|
||||
}
|
||||
strbuf_init(b, (char *) r->buffer, r->buffer_size);
|
||||
strbuf_build_http_response(b, h);
|
||||
if (strbuf_overrun(b))
|
||||
return WHYF("Bug! Cannot send response, buffer not big enough");
|
||||
}
|
||||
r->buffer_length = strbuf_len(b);
|
||||
r->buffer_offset = 0;
|
||||
r->request_type |= RHIZOME_HTTP_REQUEST_FROMBUFFER;
|
||||
if (debug & DEBUG_RHIZOME_TX)
|
||||
DEBUGF("Sending HTTP response: %s", alloca_toprint(120, r->buffer, r->buffer_length));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rhizome_server_simple_http_response(rhizome_http_request *r, int result, const char *response)
|
||||
{
|
||||
struct http_response hr;
|
||||
hr.result_code = result;
|
||||
hr.content_type = "text/html";
|
||||
hr.content_length = strlen(response);
|
||||
hr.body = response;
|
||||
return rhizome_server_set_response(r, &hr);
|
||||
}
|
||||
|
||||
static int rhizome_server_http_response_header(rhizome_http_request *r, int result, const char *mime_type, unsigned long long bytes)
|
||||
{
|
||||
struct http_response hr;
|
||||
hr.result_code = result;
|
||||
hr.content_type = mime_type;
|
||||
hr.content_length = bytes;
|
||||
hr.body = NULL;
|
||||
return rhizome_server_set_response(r, &hr);
|
||||
}
|
||||
|
||||
/*
|
||||
return codes:
|
||||
1: connection still open.
|
||||
0: connection finished.
|
||||
<0: an error occurred.
|
||||
*/
|
||||
int rhizome_server_http_send_bytes(rhizome_http_request *r)
|
||||
static int rhizome_server_http_send_bytes(rhizome_http_request *r)
|
||||
{
|
||||
// keep writing until the write would block or we run out of data
|
||||
while(r->request_type){
|
||||
@ -700,33 +760,3 @@ int rhizome_server_http_send_bytes(rhizome_http_request *r)
|
||||
if (!r->request_type) return rhizome_server_free_http_request(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rhizome_server_http_response_header(rhizome_http_request *r,int result,
|
||||
char *mime_type,unsigned long long bytes)
|
||||
{
|
||||
int min_buff = strlen("HTTP/1.0 000 \r\nContent-type: \r\nContent-length: \r\n\r\n")
|
||||
+strlen(httpResultString(result))
|
||||
+strlen(mime_type)+20;
|
||||
|
||||
if (min_buff+bytes > 65536){
|
||||
min_buff = 65536;
|
||||
}else{
|
||||
min_buff += bytes;
|
||||
}
|
||||
|
||||
if (r->buffer_size < min_buff) {
|
||||
if (r->buffer)
|
||||
free(r->buffer);
|
||||
r->buffer=(unsigned char *)malloc(min_buff);
|
||||
r->buffer_size=min_buff;
|
||||
}
|
||||
|
||||
snprintf((char *)r->buffer,r->buffer_size,"HTTP/1.0 %03d %s\r\nContent-type: %s\r\nContent-length: %lld\r\n\r\n",result,httpResultString(result),mime_type,bytes);
|
||||
|
||||
r->buffer_length=strlen((char *)r->buffer);
|
||||
r->buffer_offset=0;
|
||||
|
||||
r->request_type|=RHIZOME_HTTP_REQUEST_FROMBUFFER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
2
serval.h
2
serval.h
@ -791,7 +791,7 @@ char *catv(const char *data, char *buf, size_t len);
|
||||
int dump(char *name, unsigned char *addr, size_t len);
|
||||
char *toprint(char *dstStr, size_t dstChars, const unsigned char *srcBuf, size_t srcBytes);
|
||||
|
||||
#define alloca_toprint(dstlen,buf,len) toprint((char *)alloca((dstlen) + 1), (dstlen) + 1, (buf), (len) + 1)
|
||||
#define alloca_toprint(dstlen,buf,len) toprint((char *)alloca((dstlen) + 1), (dstlen) + 1, (buf), (len))
|
||||
|
||||
#define alloca_tohex(buf,len) tohex((char *)alloca((len)*2+1), (buf), (len))
|
||||
#define alloca_tohex_sid(sid) alloca_tohex((sid), SID_SIZE)
|
||||
|
Loading…
Reference in New Issue
Block a user