X-Git-Url: http://git.indexdata.com/?a=blobdiff_plain;f=src%2Fhttp.c;h=c9cca1df605fc30a52781880f91eea2bfefb4915;hb=9781a15c4874c98656c0ae8d3be9cacc75e19649;hp=1e73f7ce0ed03a1c6069bb0ce7f647c5174b794e;hpb=284649ed257354c2fcb2f2a6c78cf5fd7cf2283d;p=pazpar2-moved-to-github.git diff --git a/src/http.c b/src/http.c index 1e73f7c..c9cca1d 100644 --- a/src/http.c +++ b/src/http.c @@ -1,5 +1,5 @@ /* This file is part of Pazpar2. - Copyright (C) 2006-2010 Index Data + Copyright (C) 2006-2011 Index Data Pazpar2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -21,6 +21,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #endif +#if HAVE_SYS_TIME_H +#include +#endif + #include #ifdef WIN32 #include @@ -63,7 +67,8 @@ typedef int socklen_t; #include #include -#include "pazpar2.h" +#include "ppmutex.h" +#include "session.h" #include "http.h" #define MAX_HTTP_HEADER 4096 @@ -84,21 +89,21 @@ struct http_buf static void proxy_io(IOCHAN i, int event); -static struct http_channel *http_create(http_server_t http_server, - const char *addr, - struct conf_server *server); -static void http_destroy(IOCHAN i); +static struct http_channel *http_channel_create(http_server_t http_server, + const char *addr, + struct conf_server *server); +static void http_channel_destroy(IOCHAN i); static http_server_t http_server_create(void); static void http_server_incref(http_server_t hs); struct http_server { - struct http_buf *http_buf_freelist; - struct http_channel *http_channel_freelist; YAZ_MUTEX mutex; int listener_socket; int ref_count; + http_sessions_t http_sessions; struct sockaddr_in *proxy_addr; + FILE *record_file; }; struct http_channel_observer_s { @@ -121,17 +126,7 @@ const char *http_lookup_header(struct http_header *header, static struct http_buf *http_buf_create(http_server_t hs) { - struct http_buf *r = 0; - - yaz_mutex_enter(hs->mutex); - if (hs->http_buf_freelist) - { - r = hs->http_buf_freelist; - hs->http_buf_freelist = hs->http_buf_freelist->next; - } - yaz_mutex_leave(hs->mutex); - if (!r) - r = xmalloc(sizeof(struct http_buf)); + struct http_buf *r = xmalloc(sizeof(*r)); r->offset = 0; r->len = 0; r->next = 0; @@ -140,10 +135,7 @@ static struct http_buf *http_buf_create(http_server_t hs) static void http_buf_destroy(http_server_t hs, struct http_buf *b) { - yaz_mutex_enter(hs->mutex); - b->next = hs->http_buf_freelist; - hs->http_buf_freelist = b; - yaz_mutex_leave(hs->mutex); + xfree(b); } static void http_buf_destroy_queue(http_server_t hs, struct http_buf *b) @@ -796,9 +788,10 @@ static int http_proxy(struct http_request *rq) p->first_response = 1; c->proxy = p; // We will add EVENT_OUTPUT below - p->iochan = iochan_create(sock, proxy_io, EVENT_INPUT); + p->iochan = iochan_create(sock, proxy_io, EVENT_INPUT, "http_proxy"); iochan_setdata(p->iochan, p); - pazpar2_add_channel(p->iochan); + + iochan_add(ser->iochan_man, p->iochan); } // Do _not_ modify Host: header, just checking it's existence @@ -846,7 +839,7 @@ void http_send_response(struct http_channel *ch) if (!hb) { yaz_log(YLOG_WARN, "Failed to serialize HTTP response"); - http_destroy(ch->iochan); + http_channel_destroy(ch->iochan); } else { @@ -875,13 +868,13 @@ static void http_error(struct http_channel *hc, int no, const char *msg) static void http_io(IOCHAN i, int event) { struct http_channel *hc = iochan_getdata(i); - - switch (event) + while (event) { - int res, reqlen; - struct http_buf *htbuf; - - case EVENT_INPUT: + if (event == EVENT_INPUT) + { + int res, reqlen; + struct http_buf *htbuf; + htbuf = http_buf_create(hc->http_server); res = recv(iochan_getfd(i), htbuf->buf, HTTP_BUF_SIZE -1, 0); if (res == -1 && errno == EAGAIN) @@ -891,8 +884,19 @@ static void http_io(IOCHAN i, int event) } if (res <= 0) { +#if HAVE_SYS_TIME_H + if (hc->http_server->record_file) + { + struct timeval tv; + gettimeofday(&tv, 0); + fprintf(hc->http_server->record_file, "%lld %lld %lld 0\n", + (long long) tv.tv_sec, (long long) tv.tv_usec, + (long long) iochan_getfd(i)); + } +#endif http_buf_destroy(hc->http_server, htbuf); - http_destroy(i); + fflush(hc->http_server->record_file); + http_channel_destroy(i); return; } htbuf->buf[res] = '\0'; @@ -908,6 +912,22 @@ static void http_io(IOCHAN i, int event) return; // we have a complete HTTP request nmem_reset(hc->nmem); +#if HAVE_SYS_TIME_H + if (hc->http_server->record_file) + { + struct timeval tv; + int sz = 0; + struct http_buf *hb; + for (hb = hc->iqueue; hb; hb = hb->next) + sz += hb->len; + gettimeofday(&tv, 0); + fprintf(hc->http_server->record_file, "%lld %lld %lld %d\n", + (long long) tv.tv_sec, (long long) tv.tv_usec, + (long long) iochan_getfd(i), sz); + for (hb = hc->iqueue; hb; hb = hb->next) + fwrite(hb->buf, 1, hb->len, hc->http_server->record_file); + } + #endif if (!(hc->request = http_parse_request(hc, &hc->iqueue, reqlen))) { yaz_log(YLOG_WARN, "Failed to parse request"); @@ -930,16 +950,20 @@ static void http_io(IOCHAN i, int event) http_command(hc); } } - break; - case EVENT_OUTPUT: + } + else if (event == EVENT_OUTPUT) + { + event = 0; if (hc->oqueue) { struct http_buf *wb = hc->oqueue; - res = send(iochan_getfd(hc->iochan), wb->buf + wb->offset, wb->len, 0); + int res; + res = send(iochan_getfd(hc->iochan), + wb->buf + wb->offset, wb->len, 0); if (res <= 0) { yaz_log(YLOG_WARN|YLOG_ERRNO, "write"); - http_destroy(i); + http_channel_destroy(i); return; } if (res == wb->len) @@ -952,27 +976,30 @@ static void http_io(IOCHAN i, int event) wb->len -= res; wb->offset += res; } - if (!hc->oqueue) { + if (!hc->oqueue) + { if (!hc->keep_alive) { - http_destroy(i); + http_channel_destroy(i); return; } else { iochan_clearflag(i, EVENT_OUTPUT); if (hc->iqueue) - iochan_setevent(hc->iochan, EVENT_INPUT); + event = EVENT_INPUT; } } } - if (!hc->oqueue && hc->proxy && !hc->proxy->iochan) - http_destroy(i); // Server closed; we're done - break; - default: + http_channel_destroy(i); // Server closed; we're done + } + else + { yaz_log(YLOG_WARN, "Unexpected event on connection"); - http_destroy(i); + http_channel_destroy(i); + event = 0; + } } } @@ -1007,7 +1034,7 @@ static void proxy_io(IOCHAN pi, int event) } else { - http_destroy(hc->iochan); + http_channel_destroy(hc->iochan); return; } } @@ -1032,7 +1059,7 @@ static void proxy_io(IOCHAN pi, int event) if (res <= 0) { yaz_log(YLOG_WARN|YLOG_ERRNO, "write"); - http_destroy(hc->iochan); + http_channel_destroy(hc->iochan); return; } if (res == htbuf->len) @@ -1053,7 +1080,7 @@ static void proxy_io(IOCHAN pi, int event) break; default: yaz_log(YLOG_WARN, "Unexpected event on connection"); - http_destroy(hc->iochan); + http_channel_destroy(hc->iochan); } } @@ -1061,7 +1088,7 @@ static void http_fire_observers(struct http_channel *c); static void http_destroy_observers(struct http_channel *c); // Cleanup channel -static void http_destroy(IOCHAN i) +static void http_channel_destroy(IOCHAN i) { struct http_channel *s = iochan_getdata(i); http_server_t http_server; @@ -1087,11 +1114,6 @@ static void http_destroy(IOCHAN i) http_server = s->http_server; /* save it for destroy (decref) */ - yaz_mutex_enter(s->http_server->mutex); - s->next = s->http_server->http_channel_freelist; - s->http_server->http_channel_freelist = s; - yaz_mutex_leave(s->http_server->mutex); - http_server_destroy(http_server); #ifdef WIN32 @@ -1100,33 +1122,25 @@ static void http_destroy(IOCHAN i) close(iochan_getfd(i)); #endif iochan_destroy(i); + nmem_destroy(s->nmem); + wrbuf_destroy(s->wrbuf); + xfree(s); } -static struct http_channel *http_create(http_server_t hs, - const char *addr, - struct conf_server *server) +static struct http_channel *http_channel_create(http_server_t hs, + const char *addr, + struct conf_server *server) { struct http_channel *r; - yaz_mutex_enter(hs->mutex); - r = hs->http_channel_freelist; - if (r) - hs->http_channel_freelist = r->next; - yaz_mutex_leave(hs->mutex); + r = xmalloc(sizeof(struct http_channel)); + r->nmem = nmem_create(); + r->wrbuf = wrbuf_alloc(); - if (r) - { - nmem_reset(r->nmem); - wrbuf_rewind(r->wrbuf); - } - else - { - r = xmalloc(sizeof(struct http_channel)); - r->nmem = nmem_create(); - r->wrbuf = wrbuf_alloc(); - } http_server_incref(hs); r->http_server = hs; + r->http_sessions = hs->http_sessions; + assert(r->http_sessions); r->server = server; r->proxy = 0; r->iochan = 0; @@ -1166,17 +1180,18 @@ static void http_accept(IOCHAN i, int event) enable_nonblock(s); yaz_log(YLOG_DEBUG, "New command connection"); - c = iochan_create(s, http_io, EVENT_INPUT | EVENT_EXCEPT); + c = iochan_create(s, http_io, EVENT_INPUT | EVENT_EXCEPT, "http_session_socket"); - ch = http_create(server->http_server, inet_ntoa(addr.sin_addr), server); + ch = http_channel_create(server->http_server, inet_ntoa(addr.sin_addr), + server); ch->iochan = c; iochan_setdata(c, ch); - - pazpar2_add_channel(c); + iochan_add(server->iochan_man, c); } /* Create a http-channel listener, syntax [host:]port */ -int http_init(const char *addr, struct conf_server *server) +int http_init(const char *addr, struct conf_server *server, + const char *record_fname) { IOCHAN c; int l; @@ -1185,10 +1200,21 @@ int http_init(const char *addr, struct conf_server *server) int one = 1; const char *pp; short port; - http_server_t http_server; + FILE *record_file = 0; yaz_log(YLOG_LOG, "HTTP listener %s", addr); + + if (record_fname) + { + record_file = fopen(record_fname, "wb"); + if (!record_file) + { + yaz_log(YLOG_FATAL|YLOG_ERRNO, "fopen %s", record_fname); + return 1; + } + } + memset(&myaddr, 0, sizeof myaddr); myaddr.sin_family = AF_INET; pp = strchr(addr, ':'); @@ -1238,14 +1264,15 @@ int http_init(const char *addr, struct conf_server *server) return 1; } - http_server = http_server_create(); - server->http_server = http_server; + server->http_server = http_server_create(); - http_server->listener_socket = l; + server->http_server->record_file = record_file; + server->http_server->listener_socket = l; - c = iochan_create(l, http_accept, EVENT_INPUT | EVENT_EXCEPT); + c = iochan_create(l, http_accept, EVENT_INPUT | EVENT_EXCEPT, "http_server"); iochan_setdata(c, server); - pazpar2_add_channel(c); + + iochan_add(server->iochan_man, c); return 0; } @@ -1358,8 +1385,9 @@ http_server_t http_server_create(void) hs->mutex = 0; hs->proxy_addr = 0; hs->ref_count = 1; - hs->http_buf_freelist = 0; - hs->http_channel_freelist = 0; + hs->http_sessions = 0; + + hs->record_file = 0; return hs; } @@ -1369,33 +1397,17 @@ void http_server_destroy(http_server_t hs) { int r; - if (hs->mutex) - { - yaz_mutex_enter(hs->mutex); - r = --(hs->ref_count); - yaz_mutex_leave(hs->mutex); - } - else - r = --(hs->ref_count); - + yaz_mutex_enter(hs->mutex); /* OK: hs->mutex may be NULL */ + r = --(hs->ref_count); + yaz_mutex_leave(hs->mutex); + if (r == 0) { - struct http_buf *b = hs->http_buf_freelist; - struct http_channel *c = hs->http_channel_freelist; - while (b) - { - struct http_buf *b_next = b->next; - xfree(b); - b = b_next; - } - while (c) - { - struct http_channel *c_next = c->next; - xfree(c); - c = c_next; - } + http_sessions_destroy(hs->http_sessions); xfree(hs->proxy_addr); yaz_mutex_destroy(&hs->mutex); + if (hs->record_file) + fclose(hs->record_file); xfree(hs); } } @@ -1414,7 +1426,8 @@ void http_mutex_init(struct conf_server *server) assert(server); assert(server->http_server->mutex == 0); - yaz_mutex_create(&server->http_server->mutex); + pazpar2_mutex_create(&server->http_server->mutex, "http_server"); + server->http_server->http_sessions = http_sessions_create(); } /*