mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-17 18:29:46 +00:00
More work on rhizome web server.
Can now serve lists of manifest/file IDs.
This commit is contained in:
parent
9c8ea5908c
commit
c380ab0450
@ -45,6 +45,7 @@ typedef struct rhizome_http_request {
|
|||||||
// #define RHIZOME_HTTP_REQUEST_BUNDLEMANIFEST 32
|
// #define RHIZOME_HTTP_REQUEST_BUNDLEMANIFEST 32
|
||||||
// for anything too big, we can just use a blob
|
// for anything too big, we can just use a blob
|
||||||
#define RHIZOME_HTTP_REQUEST_BLOB 64
|
#define RHIZOME_HTTP_REQUEST_BLOB 64
|
||||||
|
#define RHIZOME_HTTP_REQUEST_FAVICON 128
|
||||||
|
|
||||||
/* Local buffer of data to be sent.
|
/* Local buffer of data to be sent.
|
||||||
If a RHIZOME_HTTP_REQUEST_FROMBUFFER, then the buffer is sent, and when empty
|
If a RHIZOME_HTTP_REQUEST_FROMBUFFER, then the buffer is sent, and when empty
|
||||||
@ -60,6 +61,8 @@ typedef struct rhizome_http_request {
|
|||||||
request types */
|
request types */
|
||||||
unsigned char source[1024];
|
unsigned char source[1024];
|
||||||
long long source_index;
|
long long source_index;
|
||||||
|
long long source_count;
|
||||||
|
int source_record_size;
|
||||||
|
|
||||||
char *blob_table;
|
char *blob_table;
|
||||||
char *blob_column;
|
char *blob_column;
|
||||||
@ -183,3 +186,4 @@ int rhizome_server_simple_http_response(rhizome_http_request *r,int result, char
|
|||||||
long long sqlite_exec_int64(char *sqlformat,...);
|
long long sqlite_exec_int64(char *sqlformat,...);
|
||||||
int rhizome_server_http_response_header(rhizome_http_request *r,int result,
|
int rhizome_server_http_response_header(rhizome_http_request *r,int result,
|
||||||
char *mime_type,unsigned long long bytes);
|
char *mime_type,unsigned long long bytes);
|
||||||
|
int rhizome_server_sql_query_fill_buffer(int rn,rhizome_http_request *r);
|
||||||
|
238
rhizome_http.c
238
rhizome_http.c
@ -36,6 +36,31 @@ int sigIoFlag=0;
|
|||||||
rhizome_http_request *rhizome_live_http_requests[RHIZOME_SERVER_MAX_LIVE_REQUESTS];
|
rhizome_http_request *rhizome_live_http_requests[RHIZOME_SERVER_MAX_LIVE_REQUESTS];
|
||||||
int rhizome_server_live_request_count=0;
|
int rhizome_server_live_request_count=0;
|
||||||
|
|
||||||
|
// Format icon data using:
|
||||||
|
// od -vt u1 ~/Downloads/favicon.ico | cut -c9- | sed 's/ */,/g'
|
||||||
|
unsigned char favicon_bytes[]={
|
||||||
|
0,0,1,0,1,0,16,16,16,0,0,0,0,0,40,1
|
||||||
|
,0,0,22,0,0,0,40,0,0,0,16,0,0,0,32,0
|
||||||
|
,0,0,1,0,4,0,0,0,0,0,128,0,0,0,0,0
|
||||||
|
,0,0,0,0,0,0,16,0,0,0,0,0,0,0,104,158
|
||||||
|
,168,0,163,233,247,0,104,161,118,0,0,0,0,0,0,0
|
||||||
|
,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,17
|
||||||
|
,17,17,17,18,34,17,17,18,34,17,17,18,34,17,17,2
|
||||||
|
,34,17,17,18,34,17,16,18,34,1,17,17,1,17,1,17
|
||||||
|
,1,16,1,16,17,17,17,17,1,17,16,16,17,17,17,17
|
||||||
|
,1,17,18,34,17,17,17,16,17,17,2,34,17,17,17,16
|
||||||
|
,17,16,18,34,17,17,17,16,17,1,17,1,17,17,17,18
|
||||||
|
,34,17,17,16,17,17,17,18,34,17,17,18,34,17,17,18
|
||||||
|
,34,17,17,18,34,17,17,16,17,17,17,18,34,17,17,16
|
||||||
|
,17,17,17,17,17,0,17,1,17,17,17,17,17,17,0,0
|
||||||
|
,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||||
|
int favicon_len=318;
|
||||||
|
|
||||||
void sigPipeHandler(int signal)
|
void sigPipeHandler(int signal)
|
||||||
{
|
{
|
||||||
sigPipeFlag++;
|
sigPipeFlag++;
|
||||||
@ -248,31 +273,200 @@ int rhizome_server_get_fds(struct pollfd *fds,int *fdcount,int fdmax)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hexFilter(char *s)
|
||||||
|
{
|
||||||
|
int l=strlen(s);
|
||||||
|
int i;
|
||||||
|
int o=0;
|
||||||
|
int e=0;
|
||||||
|
for(i=0;i<l;i++)
|
||||||
|
{
|
||||||
|
if ((s[i]>='0'&&s[i]<='9')
|
||||||
|
||(s[i]>='a'&&s[i]<='f')
|
||||||
|
||(s[i]>='A'&&s[i]<='F'))
|
||||||
|
s[o++]=s[i];
|
||||||
|
else e++;
|
||||||
|
}
|
||||||
|
s[o]=0;
|
||||||
|
return -e;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rhizome_server_sql_query_http_response(int rn,rhizome_http_request *r,
|
||||||
|
char *column,char *query_body,
|
||||||
|
int bytes_per_row)
|
||||||
|
{
|
||||||
|
/* Run the provided SQL query progressively and return the values of the first
|
||||||
|
column it returns. As the result list may be very long, we will add the
|
||||||
|
LIMIT <skip>,<count> clause to do it piece by piece.
|
||||||
|
|
||||||
|
Otherwise, the response is prefixed by a 256 byte header, including the public
|
||||||
|
key of the sending node, and allowing space for information about encryption of
|
||||||
|
the body, although encryption is not yet implemented here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char query[1024];
|
||||||
|
|
||||||
|
if (r->buffer) { free(r->buffer); r->buffer=NULL; }
|
||||||
|
r->buffer_size=16384;
|
||||||
|
r->buffer=malloc(r->buffer_size);
|
||||||
|
if (!r->buffer) return WHY("malloc() failed to allocate response buffer");
|
||||||
|
r->buffer_length=0;
|
||||||
|
r->buffer_offset=0;
|
||||||
|
|
||||||
|
snprintf(query,1024,"SELECT COUNT(*) %s",query_body);
|
||||||
|
query[1023]=0;
|
||||||
|
|
||||||
|
r->source_record_size=bytes_per_row;
|
||||||
|
r->source_count=sqlite_exec_int64(query);
|
||||||
|
|
||||||
|
if (r->source_count<1) r->source_count=0;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
printf("headers consumed %d bytes.\n",r->buffer_length);
|
||||||
|
|
||||||
|
/* Clear and prepare response header */
|
||||||
|
bzero(&r->buffer[r->buffer_length],256);
|
||||||
|
|
||||||
|
r->buffer[r->buffer_length]=0x01; /* type of response (list) */
|
||||||
|
r->buffer[r->buffer_length+1]=0x01; /* version of response */
|
||||||
|
|
||||||
|
printf("Found %lld records.\n",r->source_count);
|
||||||
|
/* Number of records we intend to return */
|
||||||
|
r->buffer[r->buffer_length+4]=(r->source_count>>0)&0xff;
|
||||||
|
r->buffer[r->buffer_length+5]=(r->source_count>>8)&0xff;
|
||||||
|
r->buffer[r->buffer_length+6]=(r->source_count>>16)&0xff;
|
||||||
|
r->buffer[r->buffer_length+7]=(r->source_count>>24)&0xff;
|
||||||
|
|
||||||
|
r->buffer_length+=256;
|
||||||
|
|
||||||
|
/* copy our public key in to bytes 32+ */
|
||||||
|
WHY("no function yet exists to obtain our public key?");
|
||||||
|
|
||||||
|
/* build templated query */
|
||||||
|
snprintf(query,1024,"SELECT %s %s",column,query_body);
|
||||||
|
query[1023]=0;
|
||||||
|
bcopy(query,r->source,1024);
|
||||||
|
r->source_index=0;
|
||||||
|
|
||||||
|
printf("buffer_length=%d\n",r->buffer_length);
|
||||||
|
|
||||||
|
/* Populate spare space in buffer with rows of data */
|
||||||
|
return rhizome_server_sql_query_fill_buffer(rn,r);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rhizome_server_sql_query_fill_buffer(int rn,rhizome_http_request *r)
|
||||||
|
{
|
||||||
|
printf("populating with sql rows at offset %d\n",r->buffer_length);
|
||||||
|
if (r->source_index>=r->source_count)
|
||||||
|
{
|
||||||
|
/* All done */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int record_count=(r->buffer_size-r->buffer_length)/r->source_record_size;
|
||||||
|
if (record_count<1) {
|
||||||
|
printf("r->buffer_size=%d, r->buffer_length=%d, r->source_record_size=%d\n",
|
||||||
|
r->buffer_size, r->buffer_length, r->source_record_size);
|
||||||
|
return WHY("Not enough space to fit any records");
|
||||||
|
}
|
||||||
|
|
||||||
|
char query[1024];
|
||||||
|
snprintf(query,1024,"%s LIMIT %lld,%d",r->source,r->source_index,record_count);
|
||||||
|
|
||||||
|
sqlite3_stmt *statement;
|
||||||
|
WHY(query);
|
||||||
|
switch (sqlite3_prepare_v2(rhizome_db,query,-1,&statement,NULL))
|
||||||
|
{
|
||||||
|
case SQLITE_OK: case SQLITE_DONE: case SQLITE_ROW:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
sqlite3_close(rhizome_db);
|
||||||
|
rhizome_db=NULL;
|
||||||
|
WHY(query);
|
||||||
|
WHY(sqlite3_errmsg(rhizome_db));
|
||||||
|
return WHY("Could not prepare sql statement.");
|
||||||
|
}
|
||||||
|
while(((r->buffer_length+r->source_record_size)<r->buffer_size)
|
||||||
|
&&(sqlite3_step(statement)==SQLITE_ROW))
|
||||||
|
{
|
||||||
|
r->source_index++;
|
||||||
|
|
||||||
|
if (sqlite3_column_count(statement)!=1) {
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
return WHY("sqlite3 returned multiple columns for a single column query");
|
||||||
|
}
|
||||||
|
const unsigned char *value;
|
||||||
|
if (sqlite3_column_type(statement, 0)==SQLITE_TEXT)
|
||||||
|
value=sqlite3_column_text(statement, 0);
|
||||||
|
else
|
||||||
|
/* improper column type, so don't include in report */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bcopy(value,&r->buffer[r->buffer_length],r->source_record_size);
|
||||||
|
r->buffer_length+=r->source_record_size;
|
||||||
|
|
||||||
|
printf("wrote row %lld, buffer_length=%d\n",
|
||||||
|
r->source_index,r->buffer_length);
|
||||||
|
}
|
||||||
|
sqlite3_finalize(statement);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int rhizome_server_parse_http_request(int rn,rhizome_http_request *r)
|
int rhizome_server_parse_http_request(int rn,rhizome_http_request *r)
|
||||||
{
|
{
|
||||||
WHY("not implemented. just returning an HTTP error for now.");
|
|
||||||
char id[1024];
|
char id[1024];
|
||||||
|
|
||||||
|
/* Clear request type flags */
|
||||||
|
r->request_type=0;
|
||||||
|
|
||||||
if (strlen(r->request)<1024) {
|
if (strlen(r->request)<1024) {
|
||||||
if (!strncasecmp("GET /rhizome/groups HTTP/1.",r->request,
|
if (!strncasecmp(r->request,"GET /favicon.ico HTTP/1.",
|
||||||
|
strlen("GET /favicon.ico HTTP/1.")))
|
||||||
|
{
|
||||||
|
r->request_type=RHIZOME_HTTP_REQUEST_FAVICON;
|
||||||
|
rhizome_server_http_response_header(r,200,"image/vnd.microsoft.icon",
|
||||||
|
favicon_len);
|
||||||
|
}
|
||||||
|
else if (!strncasecmp(r->request,"GET /rhizome/groups HTTP/1.",
|
||||||
strlen("GET /rhizome/groups HTTP/1.")))
|
strlen("GET /rhizome/groups HTTP/1.")))
|
||||||
{
|
{
|
||||||
/* Return the list of known groups */
|
/* Return the list of known groups */
|
||||||
printf("get /rhizome/groups (list of groups)\n");
|
printf("get /rhizome/groups (list of groups)\n");
|
||||||
rhizome_server_simple_http_response(r,200,"<html><h1>List of groups</h1></html>\r\n");
|
rhizome_server_sql_query_http_response(rn,r,"id","from groups",64);
|
||||||
}
|
}
|
||||||
else if (sscanf("GET /rhizome/file/%[0-9a-f] HTTP/1.",r->request,
|
else if (!strncasecmp(r->request,"GET /rhizome/files HTTP/1.",
|
||||||
|
strlen("GET /rhizome/files HTTP/1.")))
|
||||||
|
{
|
||||||
|
/* Return the list of known files */
|
||||||
|
printf("get /rhizome/files (list of files)\n");
|
||||||
|
rhizome_server_sql_query_http_response(rn,r,"id","from files",64);
|
||||||
|
}
|
||||||
|
else if (!strncasecmp(r->request,"GET /rhizome/manifests HTTP/1.",
|
||||||
|
strlen("GET /rhizome/manifests HTTP/1.")))
|
||||||
|
{
|
||||||
|
/* Return the list of known files */
|
||||||
|
printf("get /rhizome/manifests (list of manifests)\n");
|
||||||
|
rhizome_server_sql_query_http_response(rn,r,"id","from manifests",64);
|
||||||
|
}
|
||||||
|
else if (sscanf(r->request,"GET /rhizome/file/%s HTTP/1.",
|
||||||
id)==1)
|
id)==1)
|
||||||
{
|
{
|
||||||
/* Stream the specified file */
|
/* Stream the specified file */
|
||||||
int dud=0;
|
int dud=0;
|
||||||
int i;
|
int i;
|
||||||
|
hexFilter(id);
|
||||||
printf("get /rhizome/file/ [%s]\n",id);
|
printf("get /rhizome/file/ [%s]\n",id);
|
||||||
WHY("Check for range: header, and return 206 if returning partial content");
|
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++;
|
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");
|
if (dud) rhizome_server_simple_http_response(r,400,"<html><h1>That doesn't look like hex to me.</h1></html>\r\n");
|
||||||
else {
|
else {
|
||||||
unsigned long long rowid = sqlite_exec_int64("select rowid from files where id='%s';",id);
|
long long rowid = sqlite_exec_int64("select rowid from files where id='%s';",id);
|
||||||
sqlite3_blob *blob;
|
sqlite3_blob *blob;
|
||||||
if (rowid>=0)
|
if (rowid>=0)
|
||||||
if (sqlite3_blob_open(rhizome_db,"main","files","id",rowid,0,&blob)
|
if (sqlite3_blob_open(rhizome_db,"main","files","id",rowid,0,&blob)
|
||||||
@ -296,10 +490,11 @@ int rhizome_server_parse_http_request(int rn,rhizome_http_request *r)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (sscanf("GET /rhizome/manifest/%[0-9a-f] HTTP/1.",r->request,
|
else if (sscanf(r->request,"GET /rhizome/manifest/%s HTTP/1.",
|
||||||
id)==1)
|
id)==1)
|
||||||
{
|
{
|
||||||
/* Stream the specified manifest */
|
/* Stream the specified manifest */
|
||||||
|
hexFilter(id);
|
||||||
printf("get /rhizome/manifest/ [%s]\n",id);
|
printf("get /rhizome/manifest/ [%s]\n",id);
|
||||||
rhizome_server_simple_http_response(r,400,"<html><h1>A specific manifest</h1></html>\r\n"); }
|
rhizome_server_simple_http_response(r,400,"<html><h1>A specific manifest</h1></html>\r\n"); }
|
||||||
else
|
else
|
||||||
@ -332,6 +527,7 @@ char *httpResultString(int id) {
|
|||||||
|
|
||||||
int rhizome_server_simple_http_response(rhizome_http_request *r,int result, char *response)
|
int rhizome_server_simple_http_response(rhizome_http_request *r,int result, char *response)
|
||||||
{
|
{
|
||||||
|
if (r->buffer) free(r->buffer);
|
||||||
r->buffer_size=strlen(response)+strlen("HTTP/1.0 000 \r\n\r\n")+strlen(httpResultString(A_VALUE_GREATER_THAN_FOUR))+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);
|
r->buffer=(unsigned char *)malloc(r->buffer_size);
|
||||||
@ -365,13 +561,20 @@ int rhizome_server_http_send_bytes(int rn,rhizome_http_request *r)
|
|||||||
bytes=r->buffer_length-r->buffer_offset;
|
bytes=r->buffer_length-r->buffer_offset;
|
||||||
bytes=write(r->socket,&r->buffer[r->buffer_offset],bytes);
|
bytes=write(r->socket,&r->buffer[r->buffer_offset],bytes);
|
||||||
if (bytes>0) {
|
if (bytes>0) {
|
||||||
|
printf("wrote %d bytes\n",bytes);
|
||||||
|
dump("bytes written",&r->buffer[r->buffer_offset],bytes);
|
||||||
r->buffer_offset+=bytes;
|
r->buffer_offset+=bytes;
|
||||||
if (r->buffer_offset>=r->buffer_length) {
|
if (r->buffer_offset>=r->buffer_length) {
|
||||||
/* Our work is done. close socket and go home */
|
/* Our work is done. close socket and go home */
|
||||||
r->request_type&=~RHIZOME_HTTP_REQUEST_FROMBUFFER;
|
r->request_type&=~RHIZOME_HTTP_REQUEST_FROMBUFFER;
|
||||||
|
r->buffer_offset=0; r->buffer_length=0;
|
||||||
if (!r->request_type) {
|
if (!r->request_type) {
|
||||||
WHY("Finished sending data");
|
WHY("Finished sending data");
|
||||||
return rhizome_server_close_http_request(rn);
|
return rhizome_server_close_http_request(rn);
|
||||||
|
} else {
|
||||||
|
if (debug>1) { fprintf(stderr,"request type = 0x%x after sending buffer.\n",
|
||||||
|
r->request_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Still more stuff in the buffer, so return now */
|
/* Still more stuff in the buffer, so return now */
|
||||||
@ -382,6 +585,24 @@ int rhizome_server_http_send_bytes(int rn,rhizome_http_request *r)
|
|||||||
|
|
||||||
switch(r->request_type)
|
switch(r->request_type)
|
||||||
{
|
{
|
||||||
|
case RHIZOME_HTTP_REQUEST_FAVICON:
|
||||||
|
if (r->buffer_size<favicon_len) {
|
||||||
|
free(r->buffer);
|
||||||
|
r->buffer_size=0;
|
||||||
|
r->buffer=malloc(favicon_len);
|
||||||
|
if (!r->buffer) r->request_type=0;
|
||||||
|
}
|
||||||
|
if (r->buffer)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0;i<favicon_len;i++)
|
||||||
|
r->buffer[i]=favicon_bytes[i];
|
||||||
|
r->buffer_length=i;
|
||||||
|
printf("buffer_length for favicon is %d\n",r->buffer_length);
|
||||||
|
r->request_type=RHIZOME_HTTP_REQUEST_FROMBUFFER;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
case RHIZOME_HTTP_REQUEST_FROMBUFFER:
|
case RHIZOME_HTTP_REQUEST_FROMBUFFER:
|
||||||
/* This really shouldn't happen! */
|
/* This really shouldn't happen! */
|
||||||
|
|
||||||
@ -399,12 +620,13 @@ int rhizome_server_http_send_bytes(int rn,rhizome_http_request *r)
|
|||||||
int rhizome_server_http_response_header(rhizome_http_request *r,int result,
|
int rhizome_server_http_response_header(rhizome_http_request *r,int result,
|
||||||
char *mime_type,unsigned long long bytes)
|
char *mime_type,unsigned long long bytes)
|
||||||
{
|
{
|
||||||
|
if (!r->buffer) {
|
||||||
r->buffer_size=bytes+strlen("HTTP/1.0 000 \r\n\r\n")+strlen(httpResultString(A_VALUE_GREATER_THAN_FOUR))+100;
|
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);
|
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);
|
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=strlen((char *)r->buffer);
|
||||||
r->buffer_length=r->buffer_size-1;
|
|
||||||
r->buffer_offset=0;
|
r->buffer_offset=0;
|
||||||
|
|
||||||
r->request_type|=RHIZOME_HTTP_REQUEST_FROMBUFFER;
|
r->request_type|=RHIZOME_HTTP_REQUEST_FROMBUFFER;
|
||||||
|
Loading…
Reference in New Issue
Block a user