mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-03-29 15:06:08 +00:00
Various fixes towards working internal web server.
This commit is contained in:
parent
d29efac21f
commit
9c8ea5908c
24
rhizome.h
24
rhizome.h
@ -36,12 +36,15 @@ typedef struct rhizome_http_request {
|
||||
/* Nature of the request */
|
||||
int request_type;
|
||||
#define RHIZOME_HTTP_REQUEST_RECEIVING -1
|
||||
#define RHIZOME_HTTP_REQUEST_FROMBUFFER 0
|
||||
#define RHIZOME_HTTP_REQUEST_FILE 1
|
||||
#define RHIZOME_HTTP_REQUEST_SUBSCRIBEDGROUPLIST 2
|
||||
#define RHIZOME_HTTP_REQUEST_ALLGROUPLIST 3
|
||||
#define RHIZOME_HTTP_REQUEST_BUNDLESINGROUP 4
|
||||
#define RHIZOME_HTTP_REQUEST_BUNDLEMANIFEST 5
|
||||
#define RHIZOME_HTTP_REQUEST_FROMBUFFER 1
|
||||
#define RHIZOME_HTTP_REQUEST_FILE 2
|
||||
#define RHIZOME_HTTP_REQUEST_SUBSCRIBEDGROUPLIST 4
|
||||
#define RHIZOME_HTTP_REQUEST_ALLGROUPLIST 8
|
||||
#define RHIZOME_HTTP_REQUEST_BUNDLESINGROUP 16
|
||||
// manifests are small enough to send from a buffer
|
||||
// #define RHIZOME_HTTP_REQUEST_BUNDLEMANIFEST 32
|
||||
// for anything too big, we can just use a blob
|
||||
#define RHIZOME_HTTP_REQUEST_BLOB 64
|
||||
|
||||
/* Local buffer of data to be sent.
|
||||
If a RHIZOME_HTTP_REQUEST_FROMBUFFER, then the buffer is sent, and when empty
|
||||
@ -58,6 +61,12 @@ typedef struct rhizome_http_request {
|
||||
unsigned char source[1024];
|
||||
long long source_index;
|
||||
|
||||
char *blob_table;
|
||||
char *blob_column;
|
||||
unsigned long long blob_rowid;
|
||||
/* source_index used for offset in blob */
|
||||
unsigned long long blob_end;
|
||||
|
||||
} rhizome_http_request;
|
||||
|
||||
#define RHIZOME_SERVER_MAX_LIVE_REQUESTS 32
|
||||
@ -171,3 +180,6 @@ int rhizome_server_close_http_request(int i);
|
||||
int rhizome_server_http_send_bytes(int rn,rhizome_http_request *r);
|
||||
int rhizome_server_parse_http_request(int rn,rhizome_http_request *r);
|
||||
int rhizome_server_simple_http_response(rhizome_http_request *r,int result, char *response);
|
||||
long long sqlite_exec_int64(char *sqlformat,...);
|
||||
int rhizome_server_http_response_header(rhizome_http_request *r,int result,
|
||||
char *mime_type,unsigned long long bytes);
|
||||
|
205
rhizome_http.c
205
rhizome_http.c
@ -117,57 +117,62 @@ int rhizome_server_poll()
|
||||
for(rn=0;rn<rhizome_server_live_request_count;rn++)
|
||||
{
|
||||
rhizome_http_request *r=rhizome_live_http_requests[rn];
|
||||
switch(r->request_type) {
|
||||
case RHIZOME_HTTP_REQUEST_RECEIVING:
|
||||
/* Keep reading until we have two CR/LFs in a row */
|
||||
|
||||
sigPipeFlag=0;
|
||||
|
||||
/* Make socket non-blocking */
|
||||
fcntl(r->socket,F_SETFL,fcntl(r->socket, F_GETFL, NULL)|O_NONBLOCK);
|
||||
|
||||
errno=0;
|
||||
int bytes=read(r->socket,&r->request[r->request_length],
|
||||
RHIZOME_HTTP_REQUEST_MAXLEN-r->request_length-1);
|
||||
|
||||
/* If we got some data, see if we have found the end of the HTTP request */
|
||||
if (bytes>0) {
|
||||
int i=r->request_length-160;
|
||||
int lfcount=0;
|
||||
if (i<0) i=0;
|
||||
r->request_length+=bytes;
|
||||
if (r->request_length<RHIZOME_HTTP_REQUEST_MAXLEN)
|
||||
r->request[r->request_length]=0;
|
||||
dump("request",(unsigned char *)r->request,r->request_length);
|
||||
for(;i<(r->request_length+bytes);i++)
|
||||
{
|
||||
switch(r->request[i]) {
|
||||
case '\n': lfcount++; break;
|
||||
case '\r': /* ignore CR */ break;
|
||||
case 0: /* ignore NUL (telnet inserts them) */ break;
|
||||
default: lfcount=0; break;
|
||||
}
|
||||
if (lfcount==2) break;
|
||||
}
|
||||
if (lfcount==2) {
|
||||
/* We have the request. Now parse it to see if we can respond to it */
|
||||
rhizome_server_parse_http_request(rn,r);
|
||||
}
|
||||
switch(r->request_type)
|
||||
{
|
||||
case RHIZOME_HTTP_REQUEST_RECEIVING:
|
||||
/* Keep reading until we have two CR/LFs in a row */
|
||||
WHY("receiving http request data");
|
||||
|
||||
r->request_length+=bytes;
|
||||
}
|
||||
sigPipeFlag=0;
|
||||
|
||||
/* Make socket non-blocking */
|
||||
fcntl(r->socket,F_SETFL,fcntl(r->socket, F_GETFL, NULL)|O_NONBLOCK);
|
||||
|
||||
errno=0;
|
||||
int bytes=read(r->socket,&r->request[r->request_length],
|
||||
RHIZOME_HTTP_REQUEST_MAXLEN-r->request_length-1);
|
||||
|
||||
/* If we got some data, see if we have found the end of the HTTP request */
|
||||
if (bytes>0) {
|
||||
int i=r->request_length-160;
|
||||
int lfcount=0;
|
||||
if (i<0) i=0;
|
||||
r->request_length+=bytes;
|
||||
if (r->request_length<RHIZOME_HTTP_REQUEST_MAXLEN)
|
||||
r->request[r->request_length]=0;
|
||||
dump("request",(unsigned char *)r->request,r->request_length);
|
||||
for(;i<(r->request_length+bytes);i++)
|
||||
{
|
||||
switch(r->request[i]) {
|
||||
case '\n': lfcount++; break;
|
||||
case '\r': /* ignore CR */ break;
|
||||
case 0: /* ignore NUL (telnet inserts them) */ break;
|
||||
default: lfcount=0; break;
|
||||
}
|
||||
if (lfcount==2) break;
|
||||
}
|
||||
if (lfcount==2) {
|
||||
/* We have the request. Now parse it to see if we can respond to it */
|
||||
rhizome_server_parse_http_request(rn,r);
|
||||
}
|
||||
|
||||
r->request_length+=bytes;
|
||||
}
|
||||
|
||||
/* Make socket blocking again for poll()/select() */
|
||||
fcntl(r->socket,F_SETFL,fcntl(r->socket, F_GETFL, NULL)&(~O_NONBLOCK));
|
||||
|
||||
if (sigPipeFlag||((bytes==0)&&(errno==0))) {
|
||||
/* broken pipe, so close connection */
|
||||
WHY("Closing connection due to sigpipe");
|
||||
rhizome_server_close_http_request(rn);
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
/* Make socket blocking again for poll()/select() */
|
||||
fcntl(r->socket,F_SETFL,fcntl(r->socket, F_GETFL, NULL)&(~O_NONBLOCK));
|
||||
|
||||
if (sigPipeFlag||((bytes==0)&&(errno==0))) {
|
||||
/* broken pipe, so close connection */
|
||||
WHY("Closing connection due to sigpipe");
|
||||
rhizome_server_close_http_request(rn);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Socket already has request -- so just try to send some data. */
|
||||
rhizome_server_http_send_bytes(rn,r);
|
||||
break;
|
||||
}
|
||||
WHY("Processing live HTTP requests not implemented.");
|
||||
}
|
||||
@ -209,7 +214,9 @@ int rhizome_server_close_http_request(int i)
|
||||
int rhizome_server_free_http_request(rhizome_http_request *r)
|
||||
{
|
||||
if (r->buffer&&r->buffer_size) free(r->buffer);
|
||||
|
||||
if (r->blob_table) free(r->blob_table);
|
||||
if (r->blob_column) free(r->blob_column);
|
||||
|
||||
free(r);
|
||||
return 0;
|
||||
}
|
||||
@ -258,8 +265,36 @@ int rhizome_server_parse_http_request(int rn,rhizome_http_request *r)
|
||||
id)==1)
|
||||
{
|
||||
/* Stream the specified file */
|
||||
int dud=0;
|
||||
int i;
|
||||
printf("get /rhizome/file/ [%s]\n",id);
|
||||
rhizome_server_simple_http_response(r,400,"<html><h1>A specific file</h1></html>\r\n");
|
||||
WHY("Check for range: header, and return 206 if returning partial content");
|
||||
for(i=0;i<strlen(id);i++) if ((id[i]<'0')||(id[i]>'f')||(id[i]=='\'')) dud++;
|
||||
if (dud) rhizome_server_simple_http_response(r,400,"<html><h1>That doesn't look like hex to me.</h1></html>\r\n");
|
||||
else {
|
||||
unsigned long long rowid = sqlite_exec_int64("select rowid from files where id='%s';",id);
|
||||
sqlite3_blob *blob;
|
||||
if (rowid>=0)
|
||||
if (sqlite3_blob_open(rhizome_db,"main","files","id",rowid,0,&blob)
|
||||
!=SQLITE_OK)
|
||||
rowid=-1;
|
||||
|
||||
if (rowid<0) {
|
||||
rhizome_server_simple_http_response(r,404,"<html><h1>Sorry, can't find that here.</h1></html>\r\n");
|
||||
WHY("File not found / blob not opened");
|
||||
}
|
||||
else {
|
||||
r->blob_table=strdup("files");
|
||||
r->blob_column=strdup("id");
|
||||
r->blob_rowid=rowid;
|
||||
r->source_index=0;
|
||||
r->blob_end=sqlite3_blob_bytes(blob);
|
||||
rhizome_server_http_response_header(r,200,"application/binary",
|
||||
r->blob_end-r->source_index);
|
||||
sqlite3_blob_close(blob);
|
||||
WHY("opened blob and file");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sscanf("GET /rhizome/manifest/%[0-9a-f] HTTP/1.",r->request,
|
||||
id)==1)
|
||||
@ -279,11 +314,28 @@ int rhizome_server_parse_http_request(int rn,rhizome_http_request *r)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* 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.";
|
||||
}
|
||||
}
|
||||
|
||||
int rhizome_server_simple_http_response(rhizome_http_request *r,int result, char *response)
|
||||
{
|
||||
r->buffer_size=strlen(response)+strlen("HTTP/1.0 XXX Foo\r\n\r\n")+100;
|
||||
r->buffer_size=strlen(response)+strlen("HTTP/1.0 000 \r\n\r\n")+strlen(httpResultString(A_VALUE_GREATER_THAN_FOUR))+100;
|
||||
|
||||
r->buffer=(unsigned char *)malloc(r->buffer_size);
|
||||
snprintf((char *)r->buffer,r->buffer_size,"HTTP/1.0 %03d FooContent-type: text/html\r\nContent-length: %d\r\n\r\n%s",result,(int)strlen(response),response);
|
||||
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;
|
||||
@ -293,24 +345,47 @@ int rhizome_server_simple_http_response(rhizome_http_request *r,int result, char
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
return codes:
|
||||
1: connection still open.
|
||||
0: connection finished.
|
||||
<0: an error occurred.
|
||||
*/
|
||||
int rhizome_server_http_send_bytes(int rn,rhizome_http_request *r)
|
||||
{
|
||||
int bytes;
|
||||
fcntl(r->socket,F_SETFL,fcntl(r->socket, F_GETFL, NULL)|O_NONBLOCK);
|
||||
|
||||
switch(r->request_type)
|
||||
if (debug>1) fprintf(stderr,"Request #%d, type=0x%x\n",rn,r->request_type);
|
||||
|
||||
/* Flush anything out of the buffer if present, before doing any further
|
||||
processing */
|
||||
if (r->request_type&RHIZOME_HTTP_REQUEST_FROMBUFFER)
|
||||
{
|
||||
case RHIZOME_HTTP_REQUEST_FROMBUFFER:
|
||||
bytes=r->buffer_length-r->buffer_offset;
|
||||
bytes=write(r->socket,&r->buffer[r->buffer_offset],bytes);
|
||||
if (bytes>0) {
|
||||
r->buffer_offset+=bytes;
|
||||
if (r->buffer_offset>=r->buffer_length) {
|
||||
/* Our work is done. close socket and go home */
|
||||
WHY("Finished sending data");
|
||||
return rhizome_server_close_http_request(rn);
|
||||
r->request_type&=~RHIZOME_HTTP_REQUEST_FROMBUFFER;
|
||||
if (!r->request_type) {
|
||||
WHY("Finished sending data");
|
||||
return rhizome_server_close_http_request(rn);
|
||||
}
|
||||
} else {
|
||||
/* Still more stuff in the buffer, so return now */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch(r->request_type)
|
||||
{
|
||||
case RHIZOME_HTTP_REQUEST_FROMBUFFER:
|
||||
/* This really shouldn't happen! */
|
||||
|
||||
return WHY("Something impossible happened.");
|
||||
break;
|
||||
default:
|
||||
WHY("sending data from this type of HTTP request not implemented");
|
||||
@ -318,5 +393,21 @@ int rhizome_server_http_send_bytes(int rn,rhizome_http_request *r)
|
||||
}
|
||||
|
||||
fcntl(r->socket,F_SETFL,fcntl(r->socket, F_GETFL, NULL)&(~O_NONBLOCK));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rhizome_server_http_response_header(rhizome_http_request *r,int result,
|
||||
char *mime_type,unsigned long long bytes)
|
||||
{
|
||||
r->buffer_size=bytes+strlen("HTTP/1.0 000 \r\n\r\n")+strlen(httpResultString(A_VALUE_GREATER_THAN_FOUR))+100;
|
||||
r->buffer=(unsigned char *)malloc(r->buffer_size);
|
||||
snprintf((char *)r->buffer,r->buffer_size,"HTTP/1.0 %03d \r\nContent-type: text/html\r\nContent-length: %lld\r\n\r\n",result,bytes);
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user