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