Updated source file headers with new year and no CVS Id.
[pazpar2-moved-to-github.git] / src / http.c
1 /* This file is part of Pazpar2.
2    Copyright (C) 2006-2008 Index Data
3
4 Pazpar2 is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8
9 Pazpar2 is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
18 */
19
20 #include <stdio.h>
21 #include <sys/socket.h>
22 #include <sys/types.h>
23 #include <sys/uio.h>
24 #include <yaz/snprintf.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <strings.h>
28 #include <ctype.h>
29 #include <fcntl.h>
30 #include <netdb.h>
31 #include <errno.h>
32 #include <assert.h>
33 #include <string.h>
34
35 #if HAVE_CONFIG_H
36 #include <cconfig.h>
37 #endif
38
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <netdb.h>
42
43 #include <yaz/yaz-util.h>
44 #include <yaz/comstack.h>
45 #include <yaz/nmem.h>
46
47 #include "cconfig.h"
48 #include "util.h"
49 #include "eventl.h"
50 #include "pazpar2.h"
51 #include "http.h"
52 #include "http_command.h"
53
54 #define MAX_HTTP_HEADER 4096
55
56 static void proxy_io(IOCHAN i, int event);
57 static struct http_channel *http_create(const char *addr);
58 static void http_destroy(IOCHAN i);
59
60 // If this is set, we proxy normal HTTP requests
61 static struct sockaddr_in *proxy_addr = 0; 
62 static char proxy_url[256] = "";
63 static char myurl[256] = "";
64 static struct http_buf *http_buf_freelist = 0;
65 static struct http_channel *http_channel_freelist = 0;
66
67 struct http_channel_observer_s {
68     void *data;
69     void *data2;
70     http_channel_destroy_t destroy;
71     struct http_channel_observer_s *next;
72     struct http_channel *chan;
73 };
74
75
76 static const char *http_lookup_header(struct http_header *header,
77                                       const char *name)
78 {
79     for (; header; header = header->next)
80         if (!strcasecmp(name, header->name))
81             return header->value;
82     return 0;
83 }
84
85 static struct http_buf *http_buf_create()
86 {
87     struct http_buf *r;
88
89     if (http_buf_freelist)
90     {
91         r = http_buf_freelist;
92         http_buf_freelist = http_buf_freelist->next;
93     }
94     else
95         r = xmalloc(sizeof(struct http_buf));
96     r->offset = 0;
97     r->len = 0;
98     r->next = 0;
99     return r;
100 }
101
102 static void http_buf_destroy(struct http_buf *b)
103 {
104     b->next = http_buf_freelist;
105     http_buf_freelist = b;
106 }
107
108 static void http_buf_destroy_queue(struct http_buf *b)
109 {
110     struct http_buf *p;
111     while (b)
112     {
113         p = b->next;
114         http_buf_destroy(b);
115         b = p;
116     }
117 }
118
119 #ifdef GAGA
120 // Calculate length of chain
121 static int http_buf_len(struct http_buf *b)
122 {
123     int sum = 0;
124     for (; b; b = b->next)
125         sum += b->len;
126     return sum;
127 }
128 #endif
129
130 static struct http_buf *http_buf_bybuf(char *b, int len)
131 {
132     struct http_buf *res = 0;
133     struct http_buf **p = &res;
134
135     while (len)
136     {
137         int tocopy = len;
138         if (tocopy > HTTP_BUF_SIZE)
139             tocopy = HTTP_BUF_SIZE;
140         *p = http_buf_create();
141         memcpy((*p)->buf, b, tocopy);
142         (*p)->len = tocopy;
143         len -= tocopy;
144         b += tocopy;
145         p = &(*p)->next;
146     }
147     return res;
148 }
149
150 // Add a (chain of) buffers to the end of an existing queue.
151 static void http_buf_enqueue(struct http_buf **queue, struct http_buf *b)
152 {
153     while (*queue)
154         queue = &(*queue)->next;
155     *queue = b;
156 }
157
158 static struct http_buf *http_buf_bywrbuf(WRBUF wrbuf)
159 {
160     // Heavens to Betsy (buf)!
161     return http_buf_bybuf(wrbuf_buf(wrbuf), wrbuf_len(wrbuf));
162 }
163
164 // Non-destructively collapse chain of buffers into a string (max *len)
165 // Return
166 static void http_buf_peek(struct http_buf *b, char *buf, int len)
167 {
168     int rd = 0;
169     while (b && rd < len)
170     {
171         int toread = len - rd;
172         if (toread > b->len)
173             toread = b->len;
174         memcpy(buf + rd, b->buf + b->offset, toread);
175         rd += toread;
176         b = b->next;
177     }
178     buf[rd] = '\0';
179 }
180
181 static int http_buf_size(struct http_buf *b)
182 {
183     int sz = 0;
184     for (; b; b = b->next)
185         sz += b->len;
186     return sz;
187 }
188
189 // Ddestructively munch up to len  from head of queue.
190 static int http_buf_read(struct http_buf **b, char *buf, int len)
191 {
192     int rd = 0;
193     while ((*b) && rd < len)
194     {
195         int toread = len - rd;
196         if (toread > (*b)->len)
197             toread = (*b)->len;
198         memcpy(buf + rd, (*b)->buf + (*b)->offset, toread);
199         rd += toread;
200         if (toread < (*b)->len)
201         {
202             (*b)->len -= toread;
203             (*b)->offset += toread;
204             break;
205         }
206         else
207         {
208             struct http_buf *n = (*b)->next;
209             http_buf_destroy(*b);
210             *b = n;
211         }
212     }
213     buf[rd] = '\0';
214     return rd;
215 }
216
217 // Buffers may overlap.
218 static void urldecode(char *i, char *o)
219 {
220     while (*i)
221     {
222         if (*i == '+')
223         {
224             *(o++) = ' ';
225             i++;
226         }
227         else if (*i == '%')
228         {
229             i++;
230             sscanf(i, "%2hhx", o);
231             i += 2;
232             o++;
233         }
234         else
235             *(o++) = *(i++);
236     }
237     *o = '\0';
238 }
239
240 // Warning: Buffers may not overlap
241 void urlencode(const char *i, char *o)
242 {
243     while (*i)
244     {
245         if (strchr(" /:", *i))
246         {
247             sprintf(o, "%%%.2X", (int) *i);
248             o += 3;
249         }
250         else
251             *(o++) = *i;
252         i++;
253     }
254     *o = '\0';
255 }
256
257 void http_addheader(struct http_response *r, const char *name, const char *value)
258 {
259     struct http_channel *c = r->channel;
260     struct http_header *h = nmem_malloc(c->nmem, sizeof *h);
261     h->name = nmem_strdup(c->nmem, name);
262     h->value = nmem_strdup(c->nmem, value);
263     h->next = r->headers;
264     r->headers = h;
265 }
266
267 char *http_argbyname(struct http_request *r, char *name)
268 {
269     struct http_argument *p;
270     if (!name)
271         return 0;
272     for (p = r->arguments; p; p = p->next)
273         if (!strcmp(p->name, name))
274             return p->value;
275     return 0;
276 }
277
278 char *http_headerbyname(struct http_header *h, char *name)
279 {
280     for (; h; h = h->next)
281         if (!strcmp(h->name, name))
282             return h->value;
283     return 0;
284 }
285
286 struct http_response *http_create_response(struct http_channel *c)
287 {
288     struct http_response *r = nmem_malloc(c->nmem, sizeof(*r));
289     strcpy(r->code, "200");
290     r->msg = "OK";
291     r->channel = c;
292     r->headers = 0;
293     r->payload = 0;
294     r->content_type = "text/xml";
295     return r;
296 }
297
298
299 static const char *next_crlf(const char *cp, size_t *skipped)
300 {
301     const char *next_cp = strchr(cp, '\n');
302     if (next_cp)
303     {
304         if (next_cp > cp && next_cp[-1] == '\r')
305             *skipped = next_cp - cp - 1;
306         else
307             *skipped = next_cp - cp;
308         next_cp++;
309     }
310     return next_cp;
311 }
312
313 // Check if buf contains a package (minus payload)
314 static int package_check(const char *buf, int sz)
315 {
316     int content_len = 0;
317     int len = 0;
318
319     while (*buf)
320     {
321         size_t skipped = 0;
322         const char *b = next_crlf(buf, &skipped);
323
324         if (!b)
325         {
326             // we did not find CRLF.. See if buffer is too large..
327             if (sz >= MAX_HTTP_HEADER-1)
328                 return MAX_HTTP_HEADER-1; // yes. Return that (will fail later)
329             break;
330         }
331         len += (b - buf);
332         if (skipped == 0)
333         {
334             // CRLF CRLF , i.e. end of header
335             if (len + content_len <= sz)
336                 return len + content_len;
337             break;
338         }
339         buf = b;
340         // following first skip of \r\n so that we don't consider Method
341         if (!strncasecmp(buf, "Content-Length:", 15))
342         {
343             const char *cp = buf+15;
344             while (*cp == ' ')
345                 cp++;
346             content_len = 0;
347             while (*cp && isdigit(*cp))
348                 content_len = content_len*10 + (*cp++ - '0');
349             if (content_len < 0) /* prevent negative offsets */
350                 content_len = 0;
351         }
352     }
353     return 0;     // incomplete request
354 }
355
356 // Check if we have a request. Return 0 or length
357 static int request_check(struct http_buf *queue)
358 {
359     char tmp[MAX_HTTP_HEADER];
360
361     // only peek at the header..
362     http_buf_peek(queue, tmp, MAX_HTTP_HEADER-1);
363     // still we only return non-zero if the complete request is received..
364     return package_check(tmp, http_buf_size(queue));
365 }
366
367 struct http_response *http_parse_response_buf(struct http_channel *c, const char *buf, int len)
368 {
369     char tmp[MAX_HTTP_HEADER];
370     struct http_response *r = http_create_response(c);
371     char *p, *p2;
372     struct http_header **hp = &r->headers;
373
374     if (len >= MAX_HTTP_HEADER)
375         return 0;
376     memcpy(tmp, buf, len);
377     for (p = tmp; *p && *p != ' '; p++) // Skip HTTP version
378         ;
379     p++;
380     // Response code
381     for (p2 = p; *p2 && *p2 != ' ' && p2 - p < 3; p2++)
382         r->code[p2 - p] = *p2;
383     if (!(p = strstr(tmp, "\r\n")))
384         return 0;
385     p += 2;
386     while (*p)
387     {
388         if (!(p2 = strstr(p, "\r\n")))
389             return 0;
390         if (p == p2) // End of headers
391             break;
392         else
393         {
394             struct http_header *h = *hp = nmem_malloc(c->nmem, sizeof(*h));
395             char *value = strchr(p, ':');
396             if (!value)
397                 return 0;
398             *(value++) = '\0';
399             h->name = nmem_strdup(c->nmem, p);
400             while (isspace(*value))
401                 value++;
402             if (value >= p2)  // Empty header;
403             {
404                 h->value = "";
405                 p = p2 + 2;
406                 continue;
407             }
408             *p2 = '\0';
409             h->value = nmem_strdup(c->nmem, value);
410             h->next = 0;
411             hp = &h->next;
412             p = p2 + 2;
413         }
414     }
415     return r;
416 }
417
418 static int http_parse_arguments(struct http_request *r, NMEM nmem,
419                                 const char *args)
420 {
421     const char *p2 = args;
422
423     while (*p2)
424     {
425         struct http_argument *a;
426         const char *equal = strchr(p2, '=');
427         const char *eoa = strchr(p2, '&');
428         if (!equal)
429         {
430             yaz_log(YLOG_WARN, "Expected '=' in argument");
431             return -1;
432         }
433         if (!eoa)
434             eoa = equal + strlen(equal); // last argument
435         else if (equal > eoa)
436         {
437             yaz_log(YLOG_WARN, "Missing '&' in argument");
438             return -1;
439         }
440         a = nmem_malloc(nmem, sizeof(struct http_argument));
441         a->name = nmem_strdupn(nmem, p2, equal - p2);
442         a->value = nmem_strdupn(nmem, equal+1, eoa - equal - 1);
443         urldecode(a->name, a->name);
444         urldecode(a->value, a->value);
445         a->next = r->arguments;
446         r->arguments = a;
447         p2 = eoa;
448         while (*p2 == '&')
449             p2++;
450     }
451     return 0;
452 }
453
454 struct http_request *http_parse_request(struct http_channel *c,
455                                         struct http_buf **queue,
456                                         int len)
457 {
458     struct http_request *r = nmem_malloc(c->nmem, sizeof(*r));
459     char *p, *p2;
460     char *start = nmem_malloc(c->nmem, len+1);
461     char *buf = start;
462
463     if (http_buf_read(queue, buf, len) < len)
464     {
465         yaz_log(YLOG_WARN, "http_buf_read < len (%d)", len);
466         return 0;
467     }
468     r->search = "";
469     r->channel = c;
470     r->arguments = 0;
471     r->headers = 0;
472     r->content_buf = 0;
473     r->content_len = 0;
474     // Parse first line
475     for (p = buf, p2 = r->method; *p && *p != ' ' && p - buf < 19; p++)
476         *(p2++) = *p;
477     if (*p != ' ')
478     {
479         yaz_log(YLOG_WARN, "Unexpected HTTP method in request");
480         return 0;
481     }
482     *p2 = '\0';
483
484     if (!(buf = strchr(buf, ' ')))
485     {
486         yaz_log(YLOG_WARN, "Missing Request-URI in HTTP request");
487         return 0;
488     }
489     buf++;
490     if (!(p = strchr(buf, ' ')))
491     {
492         yaz_log(YLOG_WARN, "HTTP Request-URI not terminated (too long?)");
493         return 0;
494     }
495     *(p++) = '\0';
496     if ((p2 = strchr(buf, '?'))) // Do we have arguments?
497         *(p2++) = '\0';
498     r->path = nmem_strdup(c->nmem, buf);
499     if (p2)
500     {
501         r->search = nmem_strdup(c->nmem, p2);
502         // Parse Arguments
503         http_parse_arguments(r, c->nmem, p2);
504     }
505     buf = p;
506
507     if (strncmp(buf, "HTTP/", 5))
508         strcpy(r->http_version, "1.0");
509     else
510     {
511         size_t skipped;
512         buf += 5; // strlen("HTTP/")
513
514         p = (char*) next_crlf(buf, &skipped);
515         if (!p || skipped < 3 || skipped > 5)
516             return 0;
517
518         memcpy(r->http_version, buf, skipped);
519         r->http_version[skipped] = '\0';
520         buf = p;
521     }
522     strcpy(c->version, r->http_version);
523
524     r->headers = 0;
525     while (*buf)
526     {
527         size_t skipped;
528
529         p = (char *) next_crlf(buf, &skipped);
530         if (!p)
531         {
532             return 0;
533         }
534         else if (skipped == 0)
535         {
536             buf = p;
537             break;
538         }
539         else
540         {
541             char *cp;
542             char *n_v = nmem_malloc(c->nmem, skipped+1);
543             struct http_header *h = nmem_malloc(c->nmem, sizeof(*h));
544
545             memcpy(n_v, buf, skipped);
546             n_v[skipped] = '\0';
547
548             if (!(cp = strchr(n_v, ':')))
549                 return 0;
550             h->name = nmem_strdupn(c->nmem, n_v, cp - n_v);
551             cp++;
552             while (isspace(*cp))
553                 cp++;
554             h->value = nmem_strdup(c->nmem, cp);
555             h->next = r->headers;
556             r->headers = h;
557             buf = p;
558         }
559     }
560
561     // determine if we do keep alive
562     if (!strcmp(c->version, "1.0"))
563     {
564         const char *v = http_lookup_header(r->headers, "Connection");
565         if (v && !strcmp(v, "Keep-Alive"))
566             c->keep_alive = 1;
567         else
568             c->keep_alive = 0;
569     }
570     else
571     {
572         const char *v = http_lookup_header(r->headers, "Connection");
573         if (v && !strcmp(v, "close"))
574             c->keep_alive = 0;
575         else
576             c->keep_alive = 1;
577     }
578     if (buf < start + len)
579     {
580         const char *content_type = http_lookup_header(r->headers,
581                                                       "Content-Type");
582         r->content_len = start + len - buf;
583         r->content_buf = buf;
584
585         if (!strcmp(content_type, "application/x-www-form-urlencoded"))
586         {
587             http_parse_arguments(r, c->nmem, r->content_buf);
588         }
589     }
590     return r;
591 }
592
593 static struct http_buf *http_serialize_response(struct http_channel *c,
594         struct http_response *r)
595 {
596     struct http_header *h;
597
598     wrbuf_rewind(c->wrbuf);
599     wrbuf_printf(c->wrbuf, "HTTP/%s %s %s\r\n", c->version, r->code, r->msg);
600     for (h = r->headers; h; h = h->next)
601         wrbuf_printf(c->wrbuf, "%s: %s\r\n", h->name, h->value);
602     if (r->payload)
603     {
604         wrbuf_printf(c->wrbuf, "Content-Length: %d\r\n", r->payload ?
605                 (int) strlen(r->payload) : 0);
606         wrbuf_printf(c->wrbuf, "Content-Type: %s\r\n", r->content_type);
607         if (!strcmp(r->content_type, "text/xml"))
608         {
609             xmlDoc *doc = xmlParseMemory(r->payload, strlen(r->payload));
610             if (doc)
611             {
612                 xmlFreeDoc(doc);
613             }
614             else
615             {
616                 yaz_log(YLOG_WARN, "Sending non-wellformed "
617                         "response (bug #1162");
618                 yaz_log(YLOG_WARN, "payload: %s", r->payload);
619             }
620         }
621     }
622     wrbuf_puts(c->wrbuf, "\r\n");
623
624     if (r->payload)
625         wrbuf_puts(c->wrbuf, r->payload);
626
627     return http_buf_bywrbuf(c->wrbuf);
628 }
629
630 // Serialize a HTTP request
631 static struct http_buf *http_serialize_request(struct http_request *r)
632 {
633     struct http_channel *c = r->channel;
634     struct http_header *h;
635
636     wrbuf_rewind(c->wrbuf);
637     wrbuf_printf(c->wrbuf, "%s %s%s%s", r->method, r->path,
638                  *r->search ? "?" : "", r->search);
639
640     wrbuf_printf(c->wrbuf, " HTTP/%s\r\n", r->http_version);
641
642     for (h = r->headers; h; h = h->next)
643         wrbuf_printf(c->wrbuf, "%s: %s\r\n", h->name, h->value);
644
645     wrbuf_puts(c->wrbuf, "\r\n");
646
647     if (r->content_buf)
648         wrbuf_write(c->wrbuf, r->content_buf, r->content_len);
649
650 #if 0
651     yaz_log(YLOG_LOG, "WRITING TO PROXY:\n%s\n----",
652             wrbuf_cstr(c->wrbuf));
653 #endif
654     return http_buf_bywrbuf(c->wrbuf);
655 }
656
657
658 static int http_weshouldproxy(struct http_request *rq)
659 {
660     if (proxy_addr && !strstr(rq->path, "search.pz2"))
661         return 1;
662     return 0;
663 }
664
665
666 struct http_header * http_header_append(struct http_channel *ch, 
667                                         struct http_header * hp, 
668                                         const char *name, 
669                                         const char *value)
670 {
671     struct http_header *hpnew = 0; 
672
673     if (!hp | !ch)
674         return 0;
675
676     while (hp && hp->next)
677         hp = hp->next;
678
679     if(name && strlen(name)&& value && strlen(value)){
680         hpnew = nmem_malloc(ch->nmem, sizeof *hpnew);
681         hpnew->name = nmem_strdup(ch->nmem, name);
682         hpnew->value = nmem_strdup(ch->nmem, value);
683         
684         hpnew->next = 0;
685         hp->next = hpnew;
686         hp = hp->next;
687         
688         return hpnew;
689     }
690
691     return hp;
692 }
693
694     
695
696 static int http_proxy(struct http_request *rq)
697 {
698     struct http_channel *c = rq->channel;
699     struct http_proxy *p = c->proxy;
700     struct http_header *hp;
701     struct http_buf *requestbuf;
702     char server_via[128] = "";
703     char server_port[16] = "";
704     struct conf_server *ser = global_parameters.server;
705
706     if (!p) // This is a new connection. Create a proxy channel
707     {
708         int sock;
709         struct protoent *pe;
710         int one = 1;
711         int flags;
712
713         if (!(pe = getprotobyname("tcp"))) {
714             abort();
715         }
716         if ((sock = socket(PF_INET, SOCK_STREAM, pe->p_proto)) < 0)
717         {
718             yaz_log(YLOG_WARN|YLOG_ERRNO, "socket");
719             return -1;
720         }
721         if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)
722                         &one, sizeof(one)) < 0)
723             abort();
724         if ((flags = fcntl(sock, F_GETFL, 0)) < 0) 
725             yaz_log(YLOG_FATAL|YLOG_ERRNO, "fcntl");
726         if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0)
727             yaz_log(YLOG_FATAL|YLOG_ERRNO, "fcntl2");
728         if (connect(sock, (struct sockaddr *) proxy_addr, 
729                     sizeof(*proxy_addr)) < 0)
730             if (errno != EINPROGRESS)
731             {
732                 yaz_log(YLOG_WARN|YLOG_ERRNO, "Proxy connect");
733                 return -1;
734             }
735
736         p = xmalloc(sizeof(struct http_proxy));
737         p->oqueue = 0;
738         p->channel = c;
739         p->first_response = 1;
740         c->proxy = p;
741         // We will add EVENT_OUTPUT below
742         p->iochan = iochan_create(sock, proxy_io, EVENT_INPUT);
743         iochan_setdata(p->iochan, p);
744         pazpar2_add_channel(p->iochan);
745     }
746
747     // Do _not_ modify Host: header, just checking it's existence
748
749     if (!http_lookup_header(rq->headers, "Host"))
750     {
751         yaz_log(YLOG_WARN, "Failed to find Host header in proxy");
752         return -1;
753     }
754     
755     // Add new header about paraz2 version, host, remote client address, etc.
756     {
757         hp = rq->headers;
758         hp = http_header_append(c, hp, 
759                                 "X-Pazpar2-Version", PACKAGE_VERSION);
760         hp = http_header_append(c, hp, 
761                                 "X-Pazpar2-Server-Host", ser->host);
762         sprintf(server_port, "%d",  ser->port);
763         hp = http_header_append(c, hp, 
764                                 "X-Pazpar2-Server-Port", server_port);
765         sprintf(server_via,  "1.1 %s:%s (%s/%s)",  
766                 ser->host, server_port, PACKAGE_NAME, PACKAGE_VERSION);
767         hp = http_header_append(c, hp, "Via" , server_via);
768         hp = http_header_append(c, hp, "X-Forwarded-For", c->addr);
769     }
770     
771     requestbuf = http_serialize_request(rq);
772
773     http_buf_enqueue(&p->oqueue, requestbuf);
774     iochan_setflag(p->iochan, EVENT_OUTPUT);
775     return 0;
776 }
777
778 void http_send_response(struct http_channel *ch)
779 {
780     struct http_response *rs = ch->response;
781     struct http_buf *hb;
782
783     assert(rs);
784     hb = http_serialize_response(ch, rs);
785     if (!hb)
786     {
787         yaz_log(YLOG_WARN, "Failed to serialize HTTP response");
788         http_destroy(ch->iochan);
789     }
790     else
791     {
792         http_buf_enqueue(&ch->oqueue, hb);
793         iochan_setflag(ch->iochan, EVENT_OUTPUT);
794         ch->state = Http_Idle;
795     }
796 }
797
798 static void http_error(struct http_channel *hc, int no, const char *msg)
799 {
800     struct http_response *rs = http_create_response(hc);
801
802     hc->response = rs;
803     hc->keep_alive = 0;  // not keeping this HTTP session alive
804
805     sprintf(rs->code, "%d", no);
806
807     rs->msg = nmem_strdup(hc->nmem, msg);
808     rs->payload = nmem_malloc(hc->nmem, 100);
809     yaz_snprintf(rs->payload, 99, "<error>HTTP Error %d: %s</error>\n",
810                  no, msg);
811     http_send_response(hc);
812 }
813
814 static void http_io(IOCHAN i, int event)
815 {
816     struct http_channel *hc = iochan_getdata(i);
817
818     switch (event)
819     {
820         int res, reqlen;
821         struct http_buf *htbuf;
822
823         case EVENT_INPUT:
824             htbuf = http_buf_create();
825             res = read(iochan_getfd(i), htbuf->buf, HTTP_BUF_SIZE -1);
826             if (res == -1 && errno == EAGAIN)
827             {
828                 http_buf_destroy(htbuf);
829                 return;
830             }
831             if (res <= 0)
832             {
833                 http_buf_destroy(htbuf);
834                 http_destroy(i);
835                 return;
836             }
837             htbuf->buf[res] = '\0';
838             htbuf->len = res;
839             http_buf_enqueue(&hc->iqueue, htbuf);
840
841             while (1)
842             {
843                 if (hc->state == Http_Busy)
844                     return;
845                 reqlen = request_check(hc->iqueue);
846                 if (reqlen <= 2)
847                     return;
848                 // we have a complete HTTP request
849                 nmem_reset(hc->nmem);
850                 if (!(hc->request = http_parse_request(hc, &hc->iqueue, reqlen)))
851                 {
852                     yaz_log(YLOG_WARN, "Failed to parse request");
853                     http_error(hc, 400, "Bad Request");
854                     return;
855                 }
856                 hc->response = 0;
857                 yaz_log(YLOG_LOG, "Request: %s %s%s%s", hc->request->method,
858                         hc->request->path,
859                         *hc->request->search ? "?" : "",
860                         hc->request->search);
861                 if (http_weshouldproxy(hc->request))
862                     http_proxy(hc->request);
863                 else
864                 {
865                     // Execute our business logic!
866                     hc->state = Http_Busy;
867                     http_command(hc);
868                 }
869             }
870             break;
871         case EVENT_OUTPUT:
872             if (hc->oqueue)
873             {
874                 struct http_buf *wb = hc->oqueue;
875                 res = write(iochan_getfd(hc->iochan), wb->buf + wb->offset, wb->len);
876                 if (res <= 0)
877                 {
878                     yaz_log(YLOG_WARN|YLOG_ERRNO, "write");
879                     http_destroy(i);
880                     return;
881                 }
882                 if (res == wb->len)
883                 {
884                     hc->oqueue = hc->oqueue->next;
885                     http_buf_destroy(wb);
886                 }
887                 else
888                 {
889                     wb->len -= res;
890                     wb->offset += res;
891                 }
892                 if (!hc->oqueue) {
893                     if (!hc->keep_alive)
894                     {
895                         http_destroy(i);
896                         return;
897                     }
898                     else
899                     {
900                         iochan_clearflag(i, EVENT_OUTPUT);
901                         if (hc->iqueue)
902                             iochan_setevent(hc->iochan, EVENT_INPUT);
903                     }
904                 }
905             }
906
907             if (!hc->oqueue && hc->proxy && !hc->proxy->iochan) 
908                 http_destroy(i); // Server closed; we're done
909             break;
910         default:
911             yaz_log(YLOG_WARN, "Unexpected event on connection");
912             http_destroy(i);
913     }
914 }
915
916 #ifdef GAGA
917 // If this hostname contains our proxy host as a prefix, replace with myurl
918 static char *sub_hostname(struct http_channel *c, char *buf)
919 {
920     char tmp[1024];
921     if (strlen(buf) > 1023)
922         return buf;
923     if (strncmp(buf, "http://", 7))
924         return buf;
925     if (!strncmp(buf + 7, proxy_url, strlen(proxy_url)))
926     {
927         strcpy(tmp, myurl);
928         strcat(tmp, buf + strlen(proxy_url) + 7);
929         return nmem_strdup(c->nmem, tmp);
930     }
931     return buf;
932 }
933 #endif
934
935 // Handles I/O on a client connection to a backend web server (proxy mode)
936 static void proxy_io(IOCHAN pi, int event)
937 {
938     struct http_proxy *pc = iochan_getdata(pi);
939     struct http_channel *hc = pc->channel;
940
941     switch (event)
942     {
943         int res;
944         struct http_buf *htbuf;
945
946         case EVENT_INPUT:
947             htbuf = http_buf_create();
948             res = read(iochan_getfd(pi), htbuf->buf, HTTP_BUF_SIZE -1);
949             if (res == 0 || (res < 0 && errno != EINPROGRESS))
950             {
951                 if (hc->oqueue)
952                 {
953                     yaz_log(YLOG_WARN, "Proxy read came up short");
954                     // Close channel and alert client HTTP channel that we're gone
955                     http_buf_destroy(htbuf);
956                     close(iochan_getfd(pi));
957                     iochan_destroy(pi);
958                     pc->iochan = 0;
959                 }
960                 else
961                 {
962                     http_destroy(hc->iochan);
963                     return;
964                 }
965             }
966             else
967             {
968                 htbuf->buf[res] = '\0';
969                 htbuf->offset = 0;
970                 htbuf->len = res;
971 #ifdef GAGA
972                 if (pc->first_response) // Check if this is a redirect
973                 {
974                     int len;
975                     if ((len = package_check(htbuf->buf)))
976                     {
977                         struct http_response *res = http_parse_response_buf(hc, htbuf->buf, len);
978                         if (res)
979                         {
980                             const char *location = http_lookup_header(
981                                 res->header, "Location");
982                             if (location)
983                             {
984                                 // We found a location header. Rewrite it.
985                                 struct http_buf *buf;
986                                 h->value = sub_hostname(hc, location);
987                                 buf = http_serialize_response(hc, res);
988                                 yaz_log(YLOG_LOG, "Proxy rewrite");
989                                 http_buf_enqueue(&hc->oqueue, buf);
990                                 htbuf->offset = len;
991                                 break;
992                             }
993                         }
994                     }
995                     pc->first_response = 0;
996                 }
997 #endif
998                 // Write any remaining payload
999                 if (htbuf->len - htbuf->offset > 0)
1000                     http_buf_enqueue(&hc->oqueue, htbuf);
1001             }
1002             iochan_setflag(hc->iochan, EVENT_OUTPUT);
1003             break;
1004         case EVENT_OUTPUT:
1005             if (!(htbuf = pc->oqueue))
1006             {
1007                 iochan_clearflag(pi, EVENT_OUTPUT);
1008                 return;
1009             }
1010             res = write(iochan_getfd(pi), htbuf->buf + htbuf->offset, htbuf->len);
1011             if (res <= 0)
1012             {
1013                 yaz_log(YLOG_WARN|YLOG_ERRNO, "write");
1014                 http_destroy(hc->iochan);
1015                 return;
1016             }
1017             if (res == htbuf->len)
1018             {
1019                 struct http_buf *np = htbuf->next;
1020                 http_buf_destroy(htbuf);
1021                 pc->oqueue = np;
1022             }
1023             else
1024             {
1025                 htbuf->len -= res;
1026                 htbuf->offset += res;
1027             }
1028
1029             if (!pc->oqueue) {
1030                 iochan_setflags(pi, EVENT_INPUT); // Turns off output flag
1031             }
1032             break;
1033         default:
1034             yaz_log(YLOG_WARN, "Unexpected event on connection");
1035             http_destroy(hc->iochan);
1036     }
1037 }
1038
1039 static void http_fire_observers(struct http_channel *c);
1040 static void http_destroy_observers(struct http_channel *c);
1041
1042 // Cleanup channel
1043 static void http_destroy(IOCHAN i)
1044 {
1045     struct http_channel *s = iochan_getdata(i);
1046
1047     if (s->proxy)
1048     {
1049         if (s->proxy->iochan)
1050         {
1051             close(iochan_getfd(s->proxy->iochan));
1052             iochan_destroy(s->proxy->iochan);
1053         }
1054         http_buf_destroy_queue(s->proxy->oqueue);
1055         xfree(s->proxy);
1056     }
1057     http_buf_destroy_queue(s->iqueue);
1058     http_buf_destroy_queue(s->oqueue);
1059     http_fire_observers(s);
1060     http_destroy_observers(s);
1061     s->next = http_channel_freelist;
1062     http_channel_freelist = s;
1063     close(iochan_getfd(i));
1064     iochan_destroy(i);
1065 }
1066
1067 static struct http_channel *http_create(const char *addr)
1068 {
1069     struct http_channel *r = http_channel_freelist;
1070
1071     if (r)
1072     {
1073         http_channel_freelist = r->next;
1074         nmem_reset(r->nmem);
1075         wrbuf_rewind(r->wrbuf);
1076     }
1077     else
1078     {
1079         r = xmalloc(sizeof(struct http_channel));
1080         r->nmem = nmem_create();
1081         r->wrbuf = wrbuf_alloc();
1082     }
1083     r->proxy = 0;
1084     r->iochan = 0;
1085     r->iqueue = r->oqueue = 0;
1086     r->state = Http_Idle;
1087     r->keep_alive = 0;
1088     r->request = 0;
1089     r->response = 0;
1090     if (!addr)
1091     {
1092         yaz_log(YLOG_WARN, "Invalid HTTP forward address");
1093         exit(1);
1094     }
1095     strcpy(r->addr, addr);
1096     r->observers = 0;
1097     return r;
1098 }
1099
1100
1101 /* Accept a new command connection */
1102 static void http_accept(IOCHAN i, int event)
1103 {
1104     struct sockaddr_in addr;
1105     int fd = iochan_getfd(i);
1106     socklen_t len;
1107     int s;
1108     IOCHAN c;
1109     int flags;
1110     struct http_channel *ch;
1111
1112     len = sizeof addr;
1113     if ((s = accept(fd, (struct sockaddr *) &addr, &len)) < 0)
1114     {
1115         yaz_log(YLOG_WARN|YLOG_ERRNO, "accept");
1116         return;
1117     }
1118     if ((flags = fcntl(s, F_GETFL, 0)) < 0) 
1119         yaz_log(YLOG_FATAL|YLOG_ERRNO, "fcntl");
1120     if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0)
1121         yaz_log(YLOG_FATAL|YLOG_ERRNO, "fcntl2");
1122
1123     yaz_log(YLOG_DEBUG, "New command connection");
1124     c = iochan_create(s, http_io, EVENT_INPUT | EVENT_EXCEPT);
1125     
1126     ch = http_create(inet_ntoa(addr.sin_addr));
1127     ch->iochan = c;
1128     iochan_setdata(c, ch);
1129
1130     pazpar2_add_channel(c);
1131 }
1132
1133 /* Create a http-channel listener, syntax [host:]port */
1134 void http_init(const char *addr)
1135 {
1136     IOCHAN c;
1137     int l;
1138     struct protoent *p;
1139     struct sockaddr_in myaddr;
1140     int one = 1;
1141     const char *pp;
1142     int port;
1143
1144     yaz_log(YLOG_LOG, "HTTP listener %s", addr);
1145
1146     memset(&myaddr, 0, sizeof myaddr);
1147     myaddr.sin_family = AF_INET;
1148     pp = strchr(addr, ':');
1149     if (pp)
1150     {
1151         int len = pp - addr;
1152         char hostname[128];
1153         struct hostent *he;
1154
1155         strncpy(hostname, addr, len);
1156         hostname[len] = '\0';
1157         if (!(he = gethostbyname(hostname))){
1158             yaz_log(YLOG_FATAL, "Unable to resolve '%s'", hostname);
1159             exit(1);
1160         }
1161         
1162         memcpy(&myaddr.sin_addr.s_addr, he->h_addr_list[0], he->h_length);
1163         port = atoi(pp + 1);
1164     }
1165     else
1166     {
1167         port = atoi(addr);
1168         myaddr.sin_addr.s_addr = INADDR_ANY;
1169     }
1170
1171     myaddr.sin_port = htons(port);
1172
1173     if (!(p = getprotobyname("tcp"))) {
1174         abort();
1175     }
1176     if ((l = socket(PF_INET, SOCK_STREAM, p->p_proto)) < 0)
1177         yaz_log(YLOG_FATAL|YLOG_ERRNO, "socket");
1178     if (setsockopt(l, SOL_SOCKET, SO_REUSEADDR, (char*)
1179                     &one, sizeof(one)) < 0)
1180         abort();
1181
1182     if (bind(l, (struct sockaddr *) &myaddr, sizeof myaddr) < 0) 
1183     {
1184         yaz_log(YLOG_FATAL|YLOG_ERRNO, "bind");
1185         exit(1);
1186     }
1187     if (listen(l, SOMAXCONN) < 0) 
1188     {
1189         yaz_log(YLOG_FATAL|YLOG_ERRNO, "listen");
1190         exit(1);
1191     }
1192
1193     c = iochan_create(l, http_accept, EVENT_INPUT | EVENT_EXCEPT);
1194     pazpar2_add_channel(c);
1195 }
1196
1197 void http_set_proxyaddr(char *host, char *base_url)
1198 {
1199     char *p;
1200     int port;
1201     struct hostent *he;
1202
1203     strcpy(myurl, base_url);
1204     strcpy(proxy_url, host);
1205     p = strchr(host, ':');
1206     yaz_log(YLOG_DEBUG, "Proxying for %s", host);
1207     yaz_log(YLOG_LOG, "HTTP backend  %s", proxy_url);
1208     if (p) {
1209         port = atoi(p + 1);
1210         *p = '\0';
1211     }
1212     else
1213         port = 80;
1214     if (!(he = gethostbyname(host))) 
1215     {
1216         fprintf(stderr, "Failed to lookup '%s'\n", host);
1217         exit(1);
1218     }
1219     proxy_addr = xmalloc(sizeof(struct sockaddr_in));
1220     proxy_addr->sin_family = he->h_addrtype;
1221     memcpy(&proxy_addr->sin_addr.s_addr, he->h_addr_list[0], he->h_length);
1222     proxy_addr->sin_port = htons(port);
1223 }
1224
1225 static void http_fire_observers(struct http_channel *c)
1226 {
1227     http_channel_observer_t p = c->observers;
1228     while (p)
1229     {
1230         p->destroy(p->data, c, p->data2);
1231         p = p->next;
1232     }
1233 }
1234
1235 static void http_destroy_observers(struct http_channel *c)
1236 {
1237     while (c->observers)
1238     {
1239         http_channel_observer_t obs = c->observers;
1240         c->observers = obs->next;
1241         xfree(obs);
1242     }
1243 }
1244
1245 http_channel_observer_t http_add_observer(struct http_channel *c, void *data,
1246                                           http_channel_destroy_t des)
1247 {
1248     http_channel_observer_t obs = xmalloc(sizeof(*obs));
1249     obs->chan = c;
1250     obs->data = data;
1251     obs->data2 = 0;
1252     obs->destroy= des;
1253     obs->next = c->observers;
1254     c->observers = obs;
1255     return obs;
1256 }
1257
1258 void http_remove_observer(http_channel_observer_t obs)
1259 {
1260     struct http_channel *c = obs->chan;
1261     http_channel_observer_t found, *p = &c->observers;
1262     while (*p != obs)
1263         p = &(*p)->next;
1264     found = *p;
1265     assert(found);
1266     *p = (*p)->next;
1267     xfree(found);
1268 }
1269
1270 struct http_channel *http_channel_observer_chan(http_channel_observer_t obs)
1271 {
1272     return obs->chan;
1273 }
1274
1275 void http_observer_set_data2(http_channel_observer_t obs, void *data2)
1276 {
1277     obs->data2 = data2;
1278 }
1279
1280
1281 /*
1282  * Local variables:
1283  * c-basic-offset: 4
1284  * indent-tabs-mode: nil
1285  * End:
1286  * vim: shiftwidth=4 tabstop=8 expandtab
1287  */