Refactor rhizome HTTP request parsing

Replace DEBUG_RHIZOMESYNC with DEBUG_RHIZOME_TX
This commit is contained in:
Andrew Bettison 2012-07-13 11:06:10 +09:30
parent dcf7209304
commit 41f3228300
6 changed files with 100 additions and 141 deletions

2
log.c
View File

@ -239,7 +239,7 @@ unsigned int debugFlagMask(const char *flagname) {
else if (!strcasecmp(flagname,"routing")) return DEBUG_OVERLAYROUTING;
else if (!strcasecmp(flagname,"security")) return DEBUG_SECURITY;
else if (!strcasecmp(flagname,"rhizome")) return DEBUG_RHIZOME;
else if (!strcasecmp(flagname,"rhizomesync")) return DEBUG_RHIZOMESYNC;
else if (!strcasecmp(flagname,"rhizometx")) return DEBUG_RHIZOME_TX;
else if (!strcasecmp(flagname,"rhizomerx")) return DEBUG_RHIZOME_RX;
else if (!strcasecmp(flagname,"monitorroutes")) return DEBUG_OVERLAYROUTEMONITOR;
else if (!strcasecmp(flagname,"queues")) return DEBUG_QUEUES;

View File

@ -51,7 +51,7 @@ int rhizome_enabled()
int rhizome_bundle_import(rhizome_manifest *m_in, rhizome_manifest **m_out,
const char *bundle, int ttl)
{
if (debug&DEBUG_RHIZOMESYNC)
if (debug & DEBUG_RHIZOME)
DEBUGF("rhizome_bundle_import(m_in=%p, m_out=%p, bundle=%s, ttl=%d)",
m_in, m_out, bundle ? bundle : "(null)", ttl);
if (m_out) *m_out = NULL;
@ -80,9 +80,6 @@ int rhizome_bundle_import(rhizome_manifest *m_in, rhizome_manifest **m_out,
rhizome_manifest_free(m);
return WHY("Could not verify manifest file.");
}
} else {
if (debug&DEBUG_RHIZOMESYNC)
DEBUGF("Importing direct from manifest structure fileHashedP=%d", m->fileHashedP);
}
/* Add the manifest and its associated file to the Rhizome database. */
@ -299,7 +296,7 @@ int rhizome_manifest_check_duplicate(rhizome_manifest *m_in,rhizome_manifest **m
int rhizome_add_manifest(rhizome_manifest *m_in,int ttl)
{
if (debug&DEBUG_RHIZOMESYNC)
if (debug & DEBUG_RHIZOME)
DEBUGF("rhizome_add_manifest(m_in=%p, ttl=%d)",m_in, ttl);
if (m_in->finalised==0)

View File

@ -143,7 +143,7 @@ int rhizome_http_server_start()
if (now_ms < rhizome_server_last_start_attempt + 5000)
return 2;
rhizome_server_last_start_attempt = now_ms;
if (debug&DEBUG_RHIZOME)
if (debug & DEBUG_RHIZOME_TX)
DEBUGF("Starting rhizome HTTP server");
unsigned short port;
@ -216,59 +216,52 @@ success:
void rhizome_client_poll(struct sched_ent *alarm)
{
rhizome_http_request *r = (rhizome_http_request *)alarm;
if (alarm->poll.revents == 0){
rhizome_server_free_http_request(r);
return;
}
switch(r->request_type)
{
case RHIZOME_HTTP_REQUEST_RECEIVING:
/* Keep reading until we have two CR/LFs in a row */
r->request[r->request_length]=0;
r->request[r->request_length] = '\0';
sigPipeFlag=0;
errno=0;
int bytes=read(r->alarm.poll.fd,&r->request[r->request_length],
RHIZOME_HTTP_REQUEST_MAXLEN-r->request_length-1);
int bytes = read_nonblock(r->alarm.poll.fd, &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) {
// reset inactivity timer
r->alarm.alarm = overlay_gettime_ms() + RHIZOME_IDLE_TIMEOUT;
unschedule(&r->alarm);
schedule(&r->alarm);
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;
if (0)
dump("request", (unsigned char *)r->request,r->request_length);
for(;i<(r->request_length+bytes);i++)
{
int lfcount;
for(lfcount = 0; lfcount < 2 && 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;
case '\n': ++lfcount; break;
case '\r': break;
case '\0': break; // ignore NUL (telnet inserts them)
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(r);
}
} else {
if (debug & DEBUG_RHIZOME_TX)
DEBUG("Empty read, closing connection");
rhizome_server_free_http_request(r);
return;
}
if (sigPipeFlag||((bytes==0)&&(errno==0))) {
/* broken pipe, so close connection */
if (debug & DEBUG_RHIZOMESYNC)
DEBUG("Closing connection due to sigpipe");
if (sigPipeFlag) {
if (debug & DEBUG_RHIZOME_TX)
DEBUG("Received SIGPIPE, closing connection");
rhizome_server_free_http_request(r);
return;
}
@ -331,15 +324,6 @@ int rhizome_server_free_http_request(rhizome_http_request *r)
return 0;
}
void hexFilter(char *s)
{
char *t;
for (t = s; *s; ++s)
if (isxdigit(*s))
*t++ = *s;
*t = '\0';
}
int rhizome_server_sql_query_http_response(rhizome_http_request *r,
char *column,char *table,char *query_body,
int bytes_per_row,int dehexP)
@ -367,7 +351,7 @@ int rhizome_server_sql_query_http_response(rhizome_http_request *r,
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);
if (debug & DEBUG_RHIZOMESYNC)
if (debug & DEBUG_RHIZOME_TX)
DEBUGF("headers consumed %d bytes",r->buffer_length);
/* Clear and prepare response header */
@ -376,7 +360,7 @@ int rhizome_server_sql_query_http_response(rhizome_http_request *r,
r->buffer[r->buffer_length]=0x01; /* type of response (list) */
r->buffer[r->buffer_length+1]=0x01; /* version of response */
if (debug & DEBUG_RHIZOMESYNC)
if (debug & DEBUG_RHIZOME_TX)
DEBUGF("Found %lld records",r->source_count);
/* Number of records we intend to return */
r->buffer[r->buffer_length+4]=(r->source_count>>0)&0xff;
@ -407,7 +391,7 @@ int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *table, c
{
unsigned char blob_value[r->source_record_size*2+1];
if (debug & DEBUG_RHIZOMESYNC)
if (debug & DEBUG_RHIZOME_TX)
DEBUGF("populating with sql rows at offset %d",r->buffer_length);
if (r->source_index>=r->source_count)
{
@ -417,7 +401,7 @@ int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *table, c
int record_count=(r->buffer_size-r->buffer_length)/r->source_record_size;
if (record_count<1) {
if (debug & DEBUG_RHIZOMESYNC)
if (debug & DEBUG_RHIZOME_TX)
DEBUGF("r->buffer_size=%d, r->buffer_length=%d, r->source_record_size=%d",
r->buffer_size, r->buffer_length, r->source_record_size);
return WHY("Not enough space to fit any records");
@ -427,7 +411,7 @@ int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *table, c
snprintf(query,1024,"%s LIMIT %lld,%d",r->source,r->source_index,record_count);
sqlite3_stmt *statement;
if (debug & DEBUG_RHIZOMESYNC)
if (debug & DEBUG_RHIZOME_TX)
DEBUG(query);
switch (sqlite3_prepare_v2(rhizome_db,query,-1,&statement,NULL))
{
@ -456,7 +440,7 @@ int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *table, c
switch(column_type) {
case SQLITE_TEXT: value=sqlite3_column_text(statement, 0); break;
case SQLITE_BLOB:
if (debug & DEBUG_RHIZOMESYNC)
if (debug & DEBUG_RHIZOME_TX)
DEBUGF("table='%s',col='%s',rowid=%lld", table, column, sqlite3_column_int64(statement,1));
if (sqlite3_blob_open(rhizome_db,"main",table,column,
sqlite3_column_int64(statement,1) /* rowid */,
@ -500,96 +484,73 @@ int rhizome_server_sql_query_fill_buffer(rhizome_http_request *r, char *table, c
return 0;
}
static int strcmp_prefix(char *str, const char *prefix, char **afterp)
{
while (*prefix && *str && *prefix == *str)
++prefix, ++str;
if (*prefix)
return (unsigned char)*str - (unsigned char)*prefix;
if (afterp)
*afterp = str;
return 0;
}
int rhizome_server_parse_http_request(rhizome_http_request *r)
{
char id[1024];
/* Switching to writing, so update the call-back */
r->alarm.poll.events=POLLOUT;
watch(&r->alarm);
/* Clear request type flags */
r->request_type=0;
if (strlen(r->request)<1024) {
if (!strncasecmp(r->request,"GET /favicon.ico HTTP/1.",
strlen("GET /favicon.ico HTTP/1.")))
{
char path[1024];
if (sscanf(r->request, "GET %1024s HTTP/1.%*1[01]%*[\r\n]", path) != 1) {
if (debug & DEBUG_RHIZOME_TX)
DEBUGF("Received malformed HTTP request: %s", alloca_toprint(120, (unsigned char *)r->request, r->request_length));
rhizome_server_simple_http_response(r, 400, "<html><h1>Malformed request</h1></html>\r\n");
} else {
char *id = NULL;
if (debug & DEBUG_RHIZOME_TX)
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);
}
else if (!strncasecmp(r->request,"GET /rhizome/groups HTTP/1.",
strlen("GET /rhizome/groups HTTP/1.")))
{
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 */
if (debug & DEBUG_RHIZOMESYNC)
DEBUGF("GET /rhizome/groups");
rhizome_server_sql_query_http_response(r, "id", "groups", "from groups", 32, 1);
}
else if (!strncasecmp(r->request,"GET /rhizome/files HTTP/1.",
strlen("GET /rhizome/files HTTP/1.")))
{
} else if (strcmp(path, "/rhizome/files") == 0) {
/* Return the list of known files */
if (debug & DEBUG_RHIZOMESYNC)
DEBUGF("GET /rhizome/files");
rhizome_server_sql_query_http_response(r, "id", "files", "from files", 32, 1);
}
else if (!strncasecmp(r->request,"GET /rhizome/bars HTTP/1.", strlen("GET /rhizome/bars HTTP/1.")))
{
/* Return the list of known files */
if (debug & DEBUG_RHIZOMESYNC)
DEBUGF("GET /rhizome/bars");
} else if (strcmp(path, "/rhizome/bars") == 0) {
/* Return the list of known BARs */
rhizome_server_sql_query_http_response(r, "bar", "manifests", "from manifests", 32, 0);
}
else if (sscanf(r->request,"GET /rhizome/file/%s HTTP/1.", id)==1)
{
/* Stream the specified file */
int dud=0;
int i;
hexFilter(id);
if (debug & DEBUG_RHIZOMESYNC)
DEBUGF("GET /rhizome/file/%s", id);
// Check for range: header, and return 206 if returning partial content
for(i=0;i<strlen(id);i++) if (!isxdigit(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 {
} else if (strcmp_prefix(path, "/rhizome/file/", &id) == 0) {
/* Stream the specified payload */
if (!rhizome_str_is_file_hash(id)) {
rhizome_server_simple_http_response(r, 400, "<html><h1>Invalid payload ID</h1></html>\r\n");
} else {
// TODO: Check for Range: header and return 206 if returning partial content
str_toupper_inplace(id);
long long rowid = -1;
sqlite_exec_int64(&rowid, "select rowid from files where id='%s';", id);
if (rowid>=0)
if (sqlite3_blob_open(rhizome_db,"main","files","data",rowid,0,&r->blob) !=SQLITE_OK)
if (rowid >= 0 && sqlite3_blob_open(rhizome_db, "main", "files", "data", rowid, 0, &r->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");
if (debug & DEBUG_RHIZOMESYNC)
DEBUG("File not found / blob not opened");
}
else {
if (rowid == -1) {
rhizome_server_simple_http_response(r, 404, "<html><h1>Payload not found</h1></html>\r\n");
} else {
r->source_index = 0;
r->blob_end = sqlite3_blob_bytes(r->blob);
rhizome_server_http_response_header(r,200,"application/binary",
r->blob_end - r->source_index);
rhizome_server_http_response_header(r, 200, "application/binary", r->blob_end - r->source_index);
r->request_type |= RHIZOME_HTTP_REQUEST_BLOB;
}
}
} else if (strcmp_prefix(path, "/rhizome/manifest/", &id) == 0) {
/* TODO: Stream the specified manifest */
rhizome_server_simple_http_response(r, 500, "<html><h1>Not implemented</h1></html>\r\n");
} else {
rhizome_server_simple_http_response(r, 404, "<html><h1>Not found</h1></html>\r\n");
}
else if (sscanf(r->request,"GET /rhizome/manifest/%s HTTP/1.", id)==1)
{
/* Stream the specified manifest */
hexFilter(id);
if (debug & DEBUG_RHIZOMESYNC)
DEBUGF("GET /rhizome/manifest/%s",id);
rhizome_server_simple_http_response(r,400,"<html><h1>A specific manifest</h1></html>\r\n");
}
else
rhizome_server_simple_http_response(r,400,"<html><h1>Sorry, couldn't parse your request.</h1></html>\r\n");
}
else
rhizome_server_simple_http_response(r,400,"<html><h1>Sorry, your request was too long.</h1></html>\r\n");
/* Try sending data immediately. */
rhizome_server_http_send_bytes(r);
@ -687,7 +648,7 @@ int rhizome_server_http_send_bytes(rhizome_http_request *r)
for(i=0;i<favicon_len;i++)
r->buffer[i]=favicon_bytes[i];
r->buffer_length=i;
if (debug & DEBUG_RHIZOMESYNC)
if (debug & DEBUG_RHIZOME_TX)
DEBUGF("favicon buffer_length=%d\n", r->buffer_length);
r->request_type=RHIZOME_HTTP_REQUEST_FROMBUFFER;
}

View File

@ -388,7 +388,7 @@ int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now)
(that is the only use of this */
manifest_id_prefix[8]=0;
long long version = rhizome_manifest_get_ll(m, "version");
if (0||debug & DEBUG_RHIZOMESYNC) DEBUGF("manifest id=%s* version=%lld", manifest_id_prefix, version);
if (debug & DEBUG_RHIZOME_RX) DEBUGF("manifest id=%s* version=%lld", manifest_id_prefix, version);
/* Crude signature presence test */
for(i=m->manifest_all_bytes-1;i>0;i--)
@ -414,10 +414,10 @@ int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now)
/* Manifest is okay, so see if it is worth storing */
if (rhizome_manifest_version_cache_lookup(m)) {
/* We already have this version or newer */
if (debug&DEBUG_RHIZOMESYNC) DEBUG("We already have that manifest or newer.");
if (debug & DEBUG_RHIZOME_RX) DEBUG("We already have that manifest or newer.");
importManifest=0;
} else {
if (debug&DEBUG_RHIZOMESYNC) DEBUG("Not seen before.");
if (debug & DEBUG_RHIZOME_RX) DEBUG("Not seen before.");
importManifest=1;
}
}

View File

@ -821,6 +821,7 @@ const char *trimbuildpath(const char *s);
#define DEBUGF(F,...) LOGF(LOG_LEVEL_DEBUG, F, ##__VA_ARGS__)
#define DEBUG(X) DEBUGF("%s", (X))
#define DEBUGF_perror(F,...) DEBUGF(F ": %s [errno=%d]", ##__VA_ARGS__, strerror(errno), errno)
#define DEBUG_perror(X) DEBUGF("%s: %s [errno=%d]", (X), strerror(errno), errno)
#define D DEBUG("D")
@ -1101,7 +1102,7 @@ int overlay_saw_mdp_containing_frame(overlay_frame *f,long long now);
#define DEBUG_OVERLAYROUTEMONITOR (1 << 18)
#define DEBUG_QUEUES (1 << 19)
#define DEBUG_BROADCASTS (1 << 20)
#define DEBUG_RHIZOMESYNC (1 << 21)
#define DEBUG_RHIZOME_TX (1 << 21)
#define DEBUG_PACKETTX (1 << 22)
#define DEBUG_PACKETCONSTRUCTION (1 << 23)
#define DEBUG_MANIFESTS (1 << 24)

View File

@ -42,7 +42,7 @@ configure_servald_server() {
executeOk_servald config set log.show_pid on
executeOk_servald config set log.show_time on
executeOk_servald config set debug.rhizome on
executeOk_servald config set debug.rhizomesync on
executeOk_servald config set debug.rhizometx on
executeOk_servald config set debug.rhizomerx on
executeOk_servald config set mdp.wifi.tick_ms 100
executeOk_servald config set mdp.selfannounce.ticks_per_full_address 1