From: Sebastian Hammer Date: Fri, 8 Dec 2006 21:40:58 +0000 (+0000) Subject: Split HTTP request/response handling -- halfway point to 'blocking' operations. X-Git-Tag: before.append.child~114 X-Git-Url: http://sru.miketaylor.org.uk/cgi-bin?a=commitdiff_plain;h=0b34234d576c19cdb90e009659754d4dc4353b14;p=pazpar2-moved-to-github.git Split HTTP request/response handling -- halfway point to 'blocking' operations. --- diff --git a/.gdb_history b/.gdb_history deleted file mode 100644 index 7ca6424..0000000 --- a/.gdb_history +++ /dev/null @@ -1,256 +0,0 @@ -list -break 54 -cont -print argv -print argc -cont -quit -break load_targets -run -c 2000 -finish -print channel_list -print *channel_list -print *channel_list->data -print *channel_list->next -next -break handler -cont -next -print *target -print *t -next -print res -print errno -print erddrno -print (int)errno -quit -run -c 2000 -run -c 2001 -run -run -c 2000 -break handler -cont -next -print res -next -cont -next -h -run -c 2001 -next -cont -next -cont -print channel_list -print *channel_list -print *channel_list->next -print *channel_list->next->next -run -c 2000 -next -cont -next -cont -next -print *a -print *a->u.initResponse -next -step -next -cont -delete 1 -cont -cont -run -c 2000 -bt -frame 4 -list -print *session -print *s -list -print *i -run -run -c 2001 -run -c 2000 -run -c 2001 -run -c 2000 -cont -quit -run -c 2000 -break handler -cont -cont -cont -cont -cont -next -print *p -next -print *p -next -next -print *p -next -print *p -next -cont -next -print *t -next -print *t -print *s -next -quit -break do_presentResponse -run -c 2002 -next -print *r -print *r->presentStatus -print *r->numberOfRecordsReturned -quit -break process_record -run -c 2001 -next -step -bt -finish -quit -run -c 2000 -run -c 2001 -run -c 2002 -print put - out -print pout - out -print out -print p -run -c 2000 -run -c 2001 -quit -run -c 2001 -bt -frame 1 -print *channel_list -print *channel_list->data -print *((struct target*)channel_list->data) -print *((struct target*)channel_list->data)->session -print *((struct target*)channel_list->data)->session->rechear[0] -print *((struct target*)channel_list->data)->session->recheap[0] -print *((struct target*)channel_list->data)->session->recheap[1] -print *((struct target*)channel_list->data)->session->recheap[2] -print *((struct target*)channel_list->data)->session->recheap[3] -print *((struct target*)channel_list->data)->session->recheap[4] -print *((struct target*)channel_list->data)->session->recheap[5] -cont -list -bt -frame 3 -print *s -run -c 2000 -bt -frame 1 -print *channel_list -print *((struct target*)channel_list->data) -print *((struct target*)channel_list->data)->target -print *((struct target*)channel_list->data)->session -print *((struct target*)channel_list->data)->session->recheap[0] -quit -run -c 2000 -run -c 2002 -bt -frame 2 -list -print *num -print *recs[0] -print *recs[1] -print *recs[2] -print *recs[3] -print *recs[4] -bt -frame rewind_recheap -frame 1 -list -print *S -print *s -bt -frame 2 -break -run -run -c 2000 -bt -list breakpoints -delete -frame 2 -break 865 -list -run -c 2001 -print *s -step -next -step -next -print *s -next -step -print parent -step -print *s -print p -print *s->recheap[0] -run -c 2000 -print *s -print *s->recheap[99] -step -print *s -print *s->recheap[93] -run -c 2001 -delete -cont -quit -list show -function show -help -list -quit -quit -list show -list cmd_show -break 99 -run -c 2000 -print *r -next -print r -print *rt -print *r -cont -print *r -print r -print *r->next -print *r->next_cluster -print *r->next_cluster->next_cluster -quit -quit -run -c 2000 -run -c 2001 -bt -frame 1 -print *r -quit -run -c 2000 -quit -run -c 2001 -run -c 2000 -list handler -break 622 -run -c 2000 -run -c 2001 -cont -cont -next -print len -cont -next -print len -cont -run -run -c 2000 -delete -cont -quit diff --git a/http.c b/http.c index c806c40..93f7707 100644 --- a/http.c +++ b/http.c @@ -1,5 +1,5 @@ /* - * $Id: http.c,v 1.4 2006-11-27 14:35:15 quinn Exp $ + * $Id: http.c,v 1.5 2006-12-08 21:40:58 quinn Exp $ */ #include @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -26,12 +27,15 @@ #include "http_command.h" static void proxy_io(IOCHAN i, int event); +static struct http_channel *http_create(void); +static void http_destroy(IOCHAN i); extern IOCHAN channel_list; static struct sockaddr_in *proxy_addr = 0; // If this is set, we proxy normal HTTP requests static char proxy_url[256] = ""; static struct http_buf *http_buf_freelist = 0; +static struct http_channel *http_channel_freelist = 0; static struct http_buf *http_buf_create() { @@ -108,6 +112,7 @@ static void http_buf_enqueue(struct http_buf **queue, struct http_buf *b) static struct http_buf *http_buf_bywrbuf(WRBUF wrbuf) { + // Heavens to Betsy (buf)! return http_buf_bybuf(wrbuf_buf(wrbuf), wrbuf_len(wrbuf)); } @@ -371,7 +376,7 @@ static struct http_buf *http_serialize_response(struct http_channel *c, wrbuf_printf(c->wrbuf, "HTTP/1.1 %s %s\r\n", r->code, r->msg); for (h = r->headers; h; h = h->next) wrbuf_printf(c->wrbuf, "%s: %s\r\n", h->name, h->value); - wrbuf_printf(c->wrbuf, "Content-length: %d\r\n", r->payload ? strlen(r->payload) : 0); + wrbuf_printf(c->wrbuf, "Content-length: %d\r\n", r->payload ? (int) strlen(r->payload) : 0); wrbuf_printf(c->wrbuf, "Content-type: text/xml\r\n"); wrbuf_puts(c->wrbuf, "\r\n"); @@ -412,30 +417,6 @@ static struct http_buf *http_serialize_request(struct http_request *r) } -// Cleanup -static void http_destroy(IOCHAN i) -{ - struct http_channel *s = iochan_getdata(i); - - if (s->proxy) - { - if (s->proxy->iochan) - { - close(iochan_getfd(s->proxy->iochan)); - iochan_destroy(s->proxy->iochan); - } - http_buf_destroy_queue(s->proxy->oqueue); - xfree(s->proxy); - } - http_buf_destroy_queue(s->iqueue); - http_buf_destroy_queue(s->oqueue); - nmem_destroy(s->nmem); - wrbuf_free(s->wrbuf, 1); - xfree(s); - close(iochan_getfd(i)); - iochan_destroy(i); -} - static int http_weshouldproxy(struct http_request *rq) { if (proxy_addr && !strstr(rq->path, "search.pz2")) @@ -506,11 +487,27 @@ static int http_proxy(struct http_request *rq) return 0; } +void http_send_response(struct http_channel *ch) +{ + struct http_response *rs = ch->response; + assert(rs); + struct http_buf *hb = http_serialize_response(ch, rs); + if (!hb) + { + yaz_log(YLOG_WARN, "Failed to serialize HTTP response"); + http_destroy(ch->iochan); + } + else + { + http_buf_enqueue(&ch->oqueue, hb); + iochan_setflag(ch->iochan, EVENT_OUTPUT); + ch->state = Http_Idle; + } +} + static void http_io(IOCHAN i, int event) { struct http_channel *hc = iochan_getdata(i); - struct http_request *request; - struct http_response *response; switch (event) { @@ -533,37 +530,29 @@ static void http_io(IOCHAN i, int event) http_buf_enqueue(&hc->iqueue, htbuf); } + if (hc->state == Http_Busy) + return; + if ((reqlen = request_check(hc->iqueue)) <= 2) return; nmem_reset(hc->nmem); - if (!(request = http_parse_request(hc, &hc->iqueue, reqlen))) + if (!(hc->request = http_parse_request(hc, &hc->iqueue, reqlen))) { yaz_log(YLOG_WARN, "Failed to parse request"); http_destroy(i); return; } - yaz_log(YLOG_LOG, "Request: %s %s v %s", request->method, request->path, - request->http_version); - if (http_weshouldproxy(request)) - http_proxy(request); + hc->response = 0; + yaz_log(YLOG_LOG, "Request: %s %s v %s", hc->request->method, + hc->request->path, hc->request->http_version); + if (http_weshouldproxy(hc->request)) + http_proxy(hc->request); else { - struct http_buf *hb; // Execute our business logic! - response = http_command(request); - if (!response) - { - http_destroy(i); - return; - } - if (!(hb = http_serialize_response(hc, response))) - { - http_destroy(i); - return; - } - http_buf_enqueue(&hc->oqueue, hb); - iochan_setflags(i, EVENT_OUTPUT); // Turns off input selecting + hc->state = Http_Busy; + http_command(hc); } if (hc->iqueue) { @@ -601,7 +590,11 @@ static void http_io(IOCHAN i, int event) return; } else - iochan_setflags(i, EVENT_INPUT); // Turns off output flag + { + iochan_clearflag(i, EVENT_OUTPUT); + if (hc->iqueue) + iochan_setevent(hc->iochan, EVENT_INPUT); + } } } @@ -688,6 +681,53 @@ static void proxy_io(IOCHAN pi, int event) } } +// Cleanup channel +static void http_destroy(IOCHAN i) +{ + struct http_channel *s = iochan_getdata(i); + + if (s->proxy) + { + if (s->proxy->iochan) + { + close(iochan_getfd(s->proxy->iochan)); + iochan_destroy(s->proxy->iochan); + } + http_buf_destroy_queue(s->proxy->oqueue); + xfree(s->proxy); + } + s->next = http_channel_freelist; + http_channel_freelist = s; + close(iochan_getfd(i)); + iochan_destroy(i); +} + +static struct http_channel *http_create(void) +{ + struct http_channel *r = http_channel_freelist; + + if (r) + { + http_channel_freelist = r->next; + nmem_reset(r->nmem); + wrbuf_rewind(r->wrbuf); + } + else + { + r = xmalloc(sizeof(struct http_channel)); + r->nmem = nmem_create(); + r->wrbuf = wrbuf_alloc(); + } + r->proxy = 0; + r->iochan = 0; + r->iqueue = r->oqueue = 0; + r->state = Http_Idle; + r->request = 0; + r->response = 0; + return r; +} + + /* Accept a new command connection */ static void http_accept(IOCHAN i, int event) { @@ -713,12 +753,8 @@ static void http_accept(IOCHAN i, int event) yaz_log(YLOG_LOG, "New command connection"); c = iochan_create(s, http_io, EVENT_INPUT | EVENT_EXCEPT); - ch = xmalloc(sizeof(*ch)); - ch->proxy = 0; - ch->nmem = nmem_create(); - ch->wrbuf = wrbuf_alloc(); + ch = http_create(); ch->iochan = c; - ch->iqueue = ch->oqueue = 0; iochan_setdata(c, ch); c->next = channel_list; diff --git a/http.h b/http.h index 907a19d..3fa3a3b 100644 --- a/http.h +++ b/http.h @@ -18,8 +18,16 @@ struct http_channel struct http_buf *oqueue; char version[10]; struct http_proxy *proxy; + enum + { + Http_Idle, + Http_Busy // Don't process new HTTP requests + } state; NMEM nmem; WRBUF wrbuf; + struct http_request *request; + struct http_response *response; + struct http_channel *next; // for freelist }; struct http_proxy // attached to iochan for proxy connection @@ -68,6 +76,7 @@ void http_addheader(struct http_response *r, const char *name, const char *value char *http_argbyname(struct http_request *r, char *name); char *http_headerbyname(struct http_request *r, char *name); struct http_response *http_create_response(struct http_channel *c); +void http_send_response(struct http_channel *c); /* * Local variables: diff --git a/http_command.c b/http_command.c index 3b1e953..517ea10 100644 --- a/http_command.c +++ b/http_command.c @@ -1,5 +1,5 @@ -/* - * $Id: http_command.c,v 1.6 2006-12-04 02:27:02 quinn Exp $ +/*_response(c, rs); + * $Id: http_command.c,v 1.7 2006-12-08 21:40:58 quinn Exp $ */ #include @@ -65,6 +65,7 @@ static void error(struct http_response *rs, char *code, char *msg, char *txt) strcpy(rs->code, code); sprintf(tmp, "%s", txt); rs->payload = nmem_strdup(c->nmem, tmp); + http_send_response(c); } int make_sessionid() @@ -100,30 +101,33 @@ static struct http_session *locate_session(struct http_request *rq, struct http_ return 0; } -static void cmd_exit(struct http_request *rq, struct http_response *rs) +static void cmd_exit(struct http_channel *c) { yaz_log(YLOG_WARN, "exit"); exit(0); } -static void cmd_init(struct http_request *rq, struct http_response *rs) +static void cmd_init(struct http_channel *c) { int sesid; char buf[1024]; struct http_session *s = http_session_create(); + struct http_response *rs = c->response; // FIXME create a pazpar2 session yaz_log(YLOG_DEBUG, "HTTP Session init"); sesid = make_sessionid(); s->session_id = sesid; sprintf(buf, "OK%d", sesid); - rs->payload = nmem_strdup(rq->channel->nmem, buf); + rs->payload = nmem_strdup(c->nmem, buf); + http_send_response(c); } -static void cmd_termlist(struct http_request *rq, struct http_response *rs) +static void cmd_termlist(struct http_channel *c) { + struct http_response *rs = c->response; + struct http_request *rq = c->request; struct http_session *s = locate_session(rq, rs); - struct http_channel *c = rq->channel; struct termlist_score **p; int len; int i; @@ -144,13 +148,15 @@ static void cmd_termlist(struct http_request *rq, struct http_response *rs) } wrbuf_puts(c->wrbuf, ""); rs->payload = nmem_strdup(rq->channel->nmem, wrbuf_buf(c->wrbuf)); + http_send_response(c); } -static void cmd_bytarget(struct http_request *rq, struct http_response *rs) +static void cmd_bytarget(struct http_channel *c) { + struct http_response *rs = c->response; + struct http_request *rq = c->request; struct http_session *s = locate_session(rq, rs); - struct http_channel *c = rq->channel; struct hitsbytarget *ht; int count, i; @@ -177,12 +183,14 @@ static void cmd_bytarget(struct http_request *rq, struct http_response *rs) wrbuf_puts(c->wrbuf, ""); rs->payload = nmem_strdup(c->nmem, wrbuf_buf(c->wrbuf)); + http_send_response(c); } -static void cmd_show(struct http_request *rq, struct http_response *rs) +static void cmd_show(struct http_channel *c) { + struct http_request *rq = c->request; + struct http_response *rs = c->response; struct http_session *s = locate_session(rq, rs); - struct http_channel *c = rq->channel; struct record **rl; char *start = http_argbyname(rq, "start"); char *num = http_argbyname(rq, "num"); @@ -225,10 +233,13 @@ static void cmd_show(struct http_request *rq, struct http_response *rs) wrbuf_puts(c->wrbuf, "\n"); rs->payload = nmem_strdup(c->nmem, wrbuf_buf(c->wrbuf)); + http_send_response(c); } -static void cmd_search(struct http_request *rq, struct http_response *rs) +static void cmd_search(struct http_channel *c) { + struct http_request *rq = c->request; + struct http_response *rs = c->response; struct http_session *s = locate_session(rq, rs); char *query = http_argbyname(rq, "query"); char *res; @@ -247,13 +258,15 @@ static void cmd_search(struct http_request *rq, struct http_response *rs) return; } rs->payload = "OK"; + http_send_response(c); } -static void cmd_stat(struct http_request *rq, struct http_response *rs) +static void cmd_stat(struct http_channel *c) { + struct http_request *rq = c->request; + struct http_response *rs = c->response; struct http_session *s = locate_session(rq, rs); - struct http_channel *c = rq->channel; struct statistics stat; if (!s) @@ -276,31 +289,13 @@ static void cmd_stat(struct http_request *rq, struct http_response *rs) wrbuf_printf(c->wrbuf, "%d\n", stat.num_error); wrbuf_puts(c->wrbuf, ""); rs->payload = nmem_strdup(c->nmem, wrbuf_buf(c->wrbuf)); + http_send_response(c); } -#ifdef GAGA -static void cmd_load(struct http_request *rq, struct http_response *rs) -{ - struct http_session *s = locate_session(rq, rs); - char *fn = http_argbyname(rq, "name"); - - if (!s) - return; - if (!fn) - { - error(rs, "417", "Must suppply name", 0); - return; - } - if (load_targets(s->psession, fn) < 0) - error(rs, "417", "Failed to find targets", "Possibly wrong filename"); - else - rs->payload = "OK"; -} -#endif struct { char *name; - void (*fun)(struct http_request *rq, struct http_response *rs); + void (*fun)(struct http_channel *c); } commands[] = { { "init", cmd_init }, { "stat", cmd_stat }, @@ -315,28 +310,28 @@ struct { {0,0} }; -struct http_response *http_command(struct http_request *rq) +void http_command(struct http_channel *c) { - char *command = http_argbyname(rq, "command"); - struct http_channel *c = rq->channel; + char *command = http_argbyname(c->request, "command"); struct http_response *rs = http_create_response(c); int i; + c->response = rs; if (!command) { error(rs, "417", "Must supply command", 0); - return rs; + return; } for (i = 0; commands[i].name; i++) if (!strcmp(commands[i].name, command)) { - (*commands[i].fun)(rq, rs); + (*commands[i].fun)(c); break; } if (!commands[i].name) error(rs, "417", "Unknown command", 0); - return rs; + return; } /* diff --git a/http_command.h b/http_command.h index 67f9adb..e127925 100644 --- a/http_command.h +++ b/http_command.h @@ -3,6 +3,6 @@ #include "http.h" -struct http_response *http_command(struct http_request *r); +void http_command(struct http_channel *c); #endif diff --git a/pazpar2.c b/pazpar2.c index 08c5da6..d8d8756 100644 --- a/pazpar2.c +++ b/pazpar2.c @@ -1,4 +1,4 @@ -/* $Id: pazpar2.c,v 1.10 2006-12-04 03:31:24 quinn Exp $ */; +/* $Id: pazpar2.c,v 1.11 2006-12-08 21:40:58 quinn Exp $ */; #include #include @@ -359,11 +359,11 @@ char *extract_title(struct session *s, const char *rec) } } wrbuf_putc(s->wrbuf, '\0'); - obuf = nmem_strdup(s->nmem, wrbuf_buf(s->wrbuf)); + obuf = (unsigned char*) nmem_strdup(s->nmem, wrbuf_buf(s->wrbuf)); for (p = obuf; *p; p++) if (*p == '&' || *p == '<' || *p > 122 || *p < ' ') *p = ' '; - return obuf; + return (char*) obuf; } // Extract 245 $a $b 100 $a diff --git a/reclists.c b/reclists.c index 330affe..579e34b 100644 --- a/reclists.c +++ b/reclists.c @@ -1,5 +1,5 @@ /* - * $Id: reclists.c,v 1.3 2006-11-27 14:35:15 quinn Exp $ + * $Id: reclists.c,v 1.4 2006-12-08 21:40:58 quinn Exp $ */ #include @@ -73,7 +73,7 @@ struct record *reclist_insert(struct reclist *l, struct record *record) struct reclist_bucket **p; struct record *head; - bucket = hash(record->merge_key) & l->hashmask; + bucket = hash((unsigned char*) record->merge_key) & l->hashmask; for (p = &l->hashtable[bucket]; *p; p = &(*p)->next) { // We found a matching record. Merge them diff --git a/termlists.c b/termlists.c index f663a87..c9a9442 100644 --- a/termlists.c +++ b/termlists.c @@ -1,5 +1,5 @@ /* - * $Id: termlists.c,v 1.2 2006-11-27 14:35:15 quinn Exp $ + * $Id: termlists.c,v 1.3 2006-12-08 21:40:58 quinn Exp $ */ #include @@ -119,7 +119,7 @@ void termlist_insert(struct termlist *tl, const char *term) unsigned int bucket; struct termlist_bucket **p; - bucket = hash(term) & tl->hashmask; + bucket = hash((unsigned char *)term) & tl->hashmask; for (p = &tl->hashtable[bucket]; *p; p = &(*p)->next) { if (!strcmp(term, (*p)->term.term))