Split HTTP request/response handling -- halfway point to 'blocking' operations.
authorSebastian Hammer <quinn@indexdata.com>
Fri, 8 Dec 2006 21:40:58 +0000 (21:40 +0000)
committerSebastian Hammer <quinn@indexdata.com>
Fri, 8 Dec 2006 21:40:58 +0000 (21:40 +0000)
.gdb_history [deleted file]
http.c
http.h
http_command.c
http_command.h
pazpar2.c
reclists.c
termlists.c

diff --git a/.gdb_history b/.gdb_history
deleted file mode 100644 (file)
index 7ca6424..0000000
+++ /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 (file)
--- 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 <stdio.h>
@@ -13,6 +13,7 @@
 #include <fcntl.h>
 #include <netdb.h>
 #include <errno.h>
+#include <assert.h>
 
 #include <yaz/yaz-util.h>
 #include <yaz/comstack.h>
 #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 (file)
--- 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:
index 3b1e953..517ea10 100644 (file)
@@ -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 <stdio.h>
@@ -65,6 +65,7 @@ static void error(struct http_response *rs, char *code, char *msg, char *txt)
     strcpy(rs->code, code);
     sprintf(tmp, "<error code=\"general\">%s</error>", 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, "<init><status>OK</status><session>%d</session></init>", 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, "</termlist>");
     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, "</bytarget>");
     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, "</show>\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 = "<search><status>OK</status></search>";
+    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, "<error>%d</error>\n", stat.num_error);
     wrbuf_puts(c->wrbuf, "</stat>");
     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 = "<load><status>OK</status></load>";
-}
-#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;
 }
 
 /*
index 67f9adb..e127925 100644 (file)
@@ -3,6 +3,6 @@
 
 #include "http.h"
 
-struct http_response *http_command(struct http_request *r);
+void http_command(struct http_channel *c);
 
 #endif
index 08c5da6..d8d8756 100644 (file)
--- 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 <stdlib.h>
 #include <stdio.h>
@@ -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
index 330affe..579e34b 100644 (file)
@@ -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 <assert.h>
@@ -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
index f663a87..c9a9442 100644 (file)
@@ -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 <stdlib.h>
@@ -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))