From ccf26e1fe02998a2662f0d6c6718cf92053c3502 Mon Sep 17 00:00:00 2001 From: gardners Date: Fri, 23 Dec 2011 04:25:18 +1030 Subject: [PATCH] Rhizome web server can now serve a 400 error message, which means that lots of the underlying stuff is now in place. --- rhizome.h | 44 +++++++++++++++ rhizome_http.c | 141 +++++++++++++++++++++++++++++-------------------- server.c | 13 +++-- 3 files changed, 135 insertions(+), 63 deletions(-) diff --git a/rhizome.h b/rhizome.h index 51392b51..cb09c34c 100644 --- a/rhizome.h +++ b/rhizome.h @@ -23,6 +23,45 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define RHIZOME_HTTP_PORT 4110 +typedef struct rhizome_http_request { + int socket; + long long last_activity; /* time of last activity in ms */ + long long initiate_time; /* time connection was initiated */ + + /* The HTTP request as currently received */ + int request_length; +#define RHIZOME_HTTP_REQUEST_MAXLEN 1024 + char request[RHIZOME_HTTP_REQUEST_MAXLEN]; + + /* 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 + + /* Local buffer of data to be sent. + If a RHIZOME_HTTP_REQUEST_FROMBUFFER, then the buffer is sent, and when empty + the request is closed. + Else emptying the buffer triggers a request to fetch more data. Only if no + more data is provided do we then close the request. */ + unsigned char *buffer; + int buffer_size; // size + int buffer_length; // number of bytes loaded into buffer + int buffer_offset; // where we are between [0,buffer_length) + + /* The source specification data which are used in different ways by different + request types */ + unsigned char source[1024]; + long long source_index; + +} rhizome_http_request; + +#define RHIZOME_SERVER_MAX_LIVE_REQUESTS 32 + #define RHIZOME_PRIORITY_HIGHEST RHIZOME_PRIORITY_SERVAL_CORE #define RHIZOME_PRIORITY_SERVAL_CORE 5 #define RHIZOME_PRIORITY_SUBSCRIBED 4 @@ -126,3 +165,8 @@ int rhizome_hex_to_bytes(char *in,unsigned char *out,int hexChars); int rhizome_store_keypair_bytes(unsigned char *p,unsigned char *s); int rhizome_find_keypair_bytes(unsigned char *p,unsigned char *s); rhizome_signature *rhizome_sign_hash(unsigned char *hash,unsigned char *publicKeyBytes); + +int rhizome_server_free_http_request(rhizome_http_request *r); +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); diff --git a/rhizome_http.c b/rhizome_http.c index dc8d7bf4..46490d02 100644 --- a/rhizome_http.c +++ b/rhizome_http.c @@ -33,48 +33,6 @@ int rhizome_server_socket=-1; int sigPipeFlag=0; int sigIoFlag=0; -typedef struct rhizome_http_request { - int socket; - long long last_activity; /* time of last activity in ms */ - long long initiate_time; /* time connection was initiated */ - - /* The HTTP request as currently received */ - int request_length; -#define RHIZOME_HTTP_REQUEST_MAXLEN 1024 - char request[RHIZOME_HTTP_REQUEST_MAXLEN]; - - /* 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 - - /* Local buffer of data to be sent. - If a RHIZOME_HTTP_REQUEST_FROMBUFFER, then the buffer is sent, and when empty - the request is closed. - Else emptying the buffer triggers a request to fetch more data. Only if no - more data is provided do we then close the request. */ - unsigned char *buffer; - int buffer_size; // size - int buffer_length; // number of bytes loaded into buffer - int buffer_offset; // where we are between [0,buffer_length) - - /* The source specification data which are used in different ways by different - request types */ - unsigned char source[1024]; - long long source_index; - -} rhizome_http_request; - -int rhizome_server_free_http_request(rhizome_http_request *r); -int rhizome_server_close_http_request(int i); - - -#define RHIZOME_SERVER_MAX_LIVE_REQUESTS 32 rhizome_http_request *rhizome_live_http_requests[RHIZOME_SERVER_MAX_LIVE_REQUESTS]; int rhizome_server_live_request_count=0; @@ -136,8 +94,6 @@ int rhizome_server_start() return WHY("listen() failed starting rhizome http server\n"); } - printf("server socket = %d\n",rhizome_server_socket); - return 0; } @@ -146,10 +102,8 @@ int rhizome_server_poll() struct sockaddr addr; unsigned int addr_len=0; int sock; - int i; + int rn; - printf("checking on rhizome server connections (and possibly accepting new connections)\n"); - /* Having the starting of the server here is helpful in that if the port is taken by someone else, we will grab it fairly swiftly once it becomes available. */ @@ -158,11 +112,11 @@ int rhizome_server_poll() /* Process the existing requests. XXX - should use poll or select here */ - if (debug) printf("Checking %d active connections\n", + if (debug>1) printf("Checking %d active connections\n", rhizome_server_live_request_count); - for(i=0;irequest_type) { case RHIZOME_HTTP_REQUEST_RECEIVING: /* Keep reading until we have two CR/LFs in a row */ @@ -174,8 +128,34 @@ int rhizome_server_poll() errno=0; int bytes=read(r->socket,&r->request[r->request_length], - RHIZOME_HTTP_REQUEST_MAXLEN-r->request_length); - printf("Read %d bytes, errno=%d\n",bytes,errno); + 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-10; + int lfcount=0; + if (i<0) i=0; + r->request_length+=bytes; + if (r->request_lengthrequest[r->request_length]=0; + dump("request",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)); @@ -183,7 +163,7 @@ int rhizome_server_poll() if (sigPipeFlag||((bytes==0)&&(errno==0))) { /* broken pipe, so close connection */ WHY("Closing connection due to sigpipe"); - rhizome_server_close_http_request(i); + rhizome_server_close_http_request(rn); continue; } @@ -200,7 +180,6 @@ int rhizome_server_poll() while ((rhizome_server_live_request_count-1)) { - printf("accepting connection.\n"); rhizome_http_request *request = calloc(sizeof(rhizome_http_request),1); request->socket=sock; /* We are now trying to read the HTTP request */ @@ -211,12 +190,12 @@ int rhizome_server_poll() fcntl(rhizome_server_socket,F_SETFL, fcntl(rhizome_server_socket, F_GETFL, NULL)&(~O_NONBLOCK)); - printf("done rhizome checking.\n"); return 0; } int rhizome_server_close_http_request(int i) { + close(rhizome_live_http_requests[i]->socket); rhizome_server_free_http_request(rhizome_live_http_requests[i]); /* Make it null, so that if we are the list in the list, the following assignment still yields the correct behaviour */ @@ -251,8 +230,58 @@ int rhizome_server_get_fds(struct pollfd *fds,int *fdcount,int fdmax) { if ((*fdcount)>=fdmax) return -1; fds[*fdcount].fd=rhizome_live_http_requests[i]->socket; - fds[*fdcount].events=POLLIN; + switch(rhizome_live_http_requests[i]->request_type) { + case RHIZOME_HTTP_REQUEST_RECEIVING: + fds[*fdcount].events=POLLIN; break; + default: + fds[*fdcount].events=POLLOUT; break; + } (*fdcount)++; } return 0; } + +int rhizome_server_parse_http_request(int rn,rhizome_http_request *r) +{ + WHY("not implemented. just returning an HTTP error for now."); + + r->buffer=(unsigned char *)strdup("HTTP/1.0 400 Bad Request\r\n\r\n

Sorry, couldn't parse your request.

\r\n"); + 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; + + /* Try sending data immediately. */ + rhizome_server_http_send_bytes(rn,r); + + return 0; +} + +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) + { + 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); + } + } + break; + default: + WHY("sending data from this type of HTTP request not implemented"); + break; + } + + fcntl(r->socket,F_SETFL,fcntl(r->socket, F_GETFL, NULL)&(~O_NONBLOCK)); + return 0; +} diff --git a/server.c b/server.c index d63cdabc..1e619ce9 100644 --- a/server.c +++ b/server.c @@ -534,20 +534,19 @@ int simpleServerMode() fds[0].fd=sock; fds[0].events=POLLIN; fdcount=1; rhizome_server_get_fds(fds,&fdcount,128); - printf("poll()ing file descriptors:"); - { int i; - for(i=0;i2) { + printf("poll()ing file descriptors:"); + { int i; + for(i=0;i