Pazpar2 compiles on Windows. But does not yet work
[pazpar2-moved-to-github.git] / src / http.c
index 9a142d7..b1d7b43 100644 (file)
@@ -1,7 +1,5 @@
-/* $Id: http.c,v 1.41 2007-10-02 12:11:14 adam Exp $
-   Copyright (c) 2006-2007, Index Data.
-
-This file is part of Pazpar2.
+/* This file is part of Pazpar2.
+   Copyright (C) 2006-2008 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
@@ -14,39 +12,59 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with Pazpar2; see the file LICENSE.  If not, write to the
-Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.
- */
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+*/
 
 #include <stdio.h>
+#ifdef WIN32
+#include <winsock.h>
+typedef int socklen_t;
+#endif
+
+#if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
+#endif
+
 #include <sys/types.h>
+#if HAVE_SYS_UIO_H
 #include <sys/uio.h>
+#endif
+
 #include <yaz/snprintf.h>
+#if HAVE_UNISTD_H
 #include <unistd.h>
+#endif
+
 #include <stdlib.h>
-#include <strings.h>
+#include <string.h>
 #include <ctype.h>
 #include <fcntl.h>
+#if HAVE_NETDB_H
 #include <netdb.h>
+#endif
+
 #include <errno.h>
 #include <assert.h>
 #include <string.h>
 
 #if HAVE_CONFIG_H
-#include <cconfig.h>
+#include <config.h>
 #endif
 
+#if HAVE_NETINET_IN_H
 #include <netinet/in.h>
+#endif
+
+#if HAVE_ARPA_INET_H
 #include <arpa/inet.h>
-#include <netdb.h>
+#endif
 
 #include <yaz/yaz-util.h>
 #include <yaz/comstack.h>
 #include <yaz/nmem.h>
 
-#include "cconfig.h"
 #include "util.h"
 #include "eventl.h"
 #include "pazpar2.h"
@@ -118,17 +136,6 @@ static void http_buf_destroy_queue(struct http_buf *b)
     }
 }
 
-#ifdef GAGA
-// Calculate length of chain
-static int http_buf_len(struct http_buf *b)
-{
-    int sum = 0;
-    for (; b; b = b->next)
-        sum += b->len;
-    return sum;
-}
-#endif
-
 static struct http_buf *http_buf_bybuf(char *b, int len)
 {
     struct http_buf *res = 0;
@@ -293,6 +300,7 @@ struct http_response *http_create_response(struct http_channel *c)
     r->channel = c;
     r->headers = 0;
     r->payload = 0;
+    r->content_type = "text/xml";
     return r;
 }
 
@@ -604,8 +612,8 @@ static struct http_buf *http_serialize_response(struct http_channel *c,
     {
         wrbuf_printf(c->wrbuf, "Content-Length: %d\r\n", r->payload ?
                 (int) strlen(r->payload) : 0);
-        wrbuf_printf(c->wrbuf, "Content-Type: text/xml\r\n");
-        if (1)
+        wrbuf_printf(c->wrbuf, "Content-Type: %s\r\n", r->content_type);
+        if (!strcmp(r->content_type, "text/xml"))
         {
             xmlDoc *doc = xmlParseMemory(r->payload, strlen(r->payload));
             if (doc)
@@ -692,7 +700,33 @@ struct http_header * http_header_append(struct http_channel *ch,
     return hp;
 }
 
-    
+   
+static int is_inprogress(void)
+{
+#ifdef WIN32
+    if (WSAGetLastError() != WSAEWOULDBLOCK)
+        return 1;
+#else
+    if (errno != EINPROGRESS)
+        return 1;
+#endif
+    return 0;
+} 
+
+static void enable_nonblock(int sock)
+{
+    int flags;
+#ifdef WIN32
+    flags = (flags & CS_FLAGS_BLOCKING) ? 0 : 1;
+    if (ioctlsocket(sock, FIONBIO, &flags) < 0)
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "ioctlsocket");
+#else
+    if ((flags = fcntl(sock, F_GETFL, 0)) < 0) 
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "fcntl");
+    if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0)
+        yaz_log(YLOG_FATAL|YLOG_ERRNO, "fcntl2");
+#endif
+}
 
 static int http_proxy(struct http_request *rq)
 {
@@ -709,7 +743,6 @@ static int http_proxy(struct http_request *rq)
         int sock;
         struct protoent *pe;
         int one = 1;
-        int flags;
 
         if (!(pe = getprotobyname("tcp"))) {
             abort();
@@ -722,18 +755,16 @@ static int http_proxy(struct http_request *rq)
         if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)
                         &one, sizeof(one)) < 0)
             abort();
-        if ((flags = fcntl(sock, F_GETFL, 0)) < 0) 
-            yaz_log(YLOG_FATAL|YLOG_ERRNO, "fcntl");
-        if (fcntl(sock, F_SETFL, flags | O_NONBLOCK) < 0)
-            yaz_log(YLOG_FATAL|YLOG_ERRNO, "fcntl2");
+        enable_nonblock(sock);
         if (connect(sock, (struct sockaddr *) proxy_addr, 
                     sizeof(*proxy_addr)) < 0)
-            if (errno != EINPROGRESS)
+        {
+            if (!is_inprogress()) 
             {
                 yaz_log(YLOG_WARN|YLOG_ERRNO, "Proxy connect");
                 return -1;
             }
-
+        }
         p = xmalloc(sizeof(struct http_proxy));
         p->oqueue = 0;
         p->channel = c;
@@ -823,7 +854,7 @@ static void http_io(IOCHAN i, int event)
 
         case EVENT_INPUT:
             htbuf = http_buf_create();
-            res = read(iochan_getfd(i), htbuf->buf, HTTP_BUF_SIZE -1);
+            res = recv(iochan_getfd(i), htbuf->buf, HTTP_BUF_SIZE -1, 0);
             if (res == -1 && errno == EAGAIN)
             {
                 http_buf_destroy(htbuf);
@@ -873,7 +904,7 @@ static void http_io(IOCHAN i, int event)
             if (hc->oqueue)
             {
                 struct http_buf *wb = hc->oqueue;
-                res = write(iochan_getfd(hc->iochan), wb->buf + wb->offset, wb->len);
+                res = send(iochan_getfd(hc->iochan), wb->buf + wb->offset, wb->len, 0);
                 if (res <= 0)
                 {
                     yaz_log(YLOG_WARN|YLOG_ERRNO, "write");
@@ -914,25 +945,6 @@ static void http_io(IOCHAN i, int event)
     }
 }
 
-#ifdef GAGA
-// If this hostname contains our proxy host as a prefix, replace with myurl
-static char *sub_hostname(struct http_channel *c, char *buf)
-{
-    char tmp[1024];
-    if (strlen(buf) > 1023)
-        return buf;
-    if (strncmp(buf, "http://", 7))
-        return buf;
-    if (!strncmp(buf + 7, proxy_url, strlen(proxy_url)))
-    {
-        strcpy(tmp, myurl);
-        strcat(tmp, buf + strlen(proxy_url) + 7);
-        return nmem_strdup(c->nmem, tmp);
-    }
-    return buf;
-}
-#endif
-
 // Handles I/O on a client connection to a backend web server (proxy mode)
 static void proxy_io(IOCHAN pi, int event)
 {
@@ -946,15 +958,19 @@ static void proxy_io(IOCHAN pi, int event)
 
         case EVENT_INPUT:
             htbuf = http_buf_create();
-            res = read(iochan_getfd(pi), htbuf->buf, HTTP_BUF_SIZE -1);
-            if (res == 0 || (res < 0 && errno != EINPROGRESS))
+            res = recv(iochan_getfd(pi), htbuf->buf, HTTP_BUF_SIZE -1, 0);
+            if (res == 0 || (res < 0 && !is_inprogress()))
             {
                 if (hc->oqueue)
                 {
                     yaz_log(YLOG_WARN, "Proxy read came up short");
                     // Close channel and alert client HTTP channel that we're gone
                     http_buf_destroy(htbuf);
+#ifdef WIN32
+                    closesocket(iochan_getfd(pi));
+#else
                     close(iochan_getfd(pi));
+#endif
                     iochan_destroy(pi);
                     pc->iochan = 0;
                 }
@@ -969,33 +985,6 @@ static void proxy_io(IOCHAN pi, int event)
                 htbuf->buf[res] = '\0';
                 htbuf->offset = 0;
                 htbuf->len = res;
-#ifdef GAGA
-                if (pc->first_response) // Check if this is a redirect
-                {
-                    int len;
-                    if ((len = package_check(htbuf->buf)))
-                    {
-                        struct http_response *res = http_parse_response_buf(hc, htbuf->buf, len);
-                        if (res)
-                        {
-                            const char *location = http_lookup_header(
-                                res->header, "Location");
-                            if (location)
-                            {
-                                // We found a location header. Rewrite it.
-                                struct http_buf *buf;
-                                h->value = sub_hostname(hc, location);
-                                buf = http_serialize_response(hc, res);
-                                yaz_log(YLOG_LOG, "Proxy rewrite");
-                                http_buf_enqueue(&hc->oqueue, buf);
-                                htbuf->offset = len;
-                                break;
-                            }
-                        }
-                    }
-                    pc->first_response = 0;
-                }
-#endif
                 // Write any remaining payload
                 if (htbuf->len - htbuf->offset > 0)
                     http_buf_enqueue(&hc->oqueue, htbuf);
@@ -1008,7 +997,7 @@ static void proxy_io(IOCHAN pi, int event)
                 iochan_clearflag(pi, EVENT_OUTPUT);
                 return;
             }
-            res = write(iochan_getfd(pi), htbuf->buf + htbuf->offset, htbuf->len);
+            res = send(iochan_getfd(pi), htbuf->buf + htbuf->offset, htbuf->len, 0);
             if (res <= 0)
             {
                 yaz_log(YLOG_WARN|YLOG_ERRNO, "write");
@@ -1016,7 +1005,7 @@ static void proxy_io(IOCHAN pi, int event)
                 return;
             }
             if (res == htbuf->len)
-            {
+            { 
                 struct http_buf *np = htbuf->next;
                 http_buf_destroy(htbuf);
                 pc->oqueue = np;
@@ -1049,7 +1038,11 @@ static void http_destroy(IOCHAN i)
     {
         if (s->proxy->iochan)
         {
+#ifdef WIN32
+            closesocket(iochan_getfd(s->proxy->iochan));
+#else
             close(iochan_getfd(s->proxy->iochan));
+#endif
             iochan_destroy(s->proxy->iochan);
         }
         http_buf_destroy_queue(s->proxy->oqueue);
@@ -1061,7 +1054,11 @@ static void http_destroy(IOCHAN i)
     http_destroy_observers(s);
     s->next = http_channel_freelist;
     http_channel_freelist = s;
+#ifdef WIN32
+    closesocket(iochan_getfd(i));
+#else
     close(iochan_getfd(i));
+#endif
     iochan_destroy(i);
 }
 
@@ -1107,7 +1104,6 @@ static void http_accept(IOCHAN i, int event)
     socklen_t len;
     int s;
     IOCHAN c;
-    int flags;
     struct http_channel *ch;
 
     len = sizeof addr;
@@ -1116,10 +1112,7 @@ static void http_accept(IOCHAN i, int event)
         yaz_log(YLOG_WARN|YLOG_ERRNO, "accept");
         return;
     }
-    if ((flags = fcntl(s, F_GETFL, 0)) < 0) 
-        yaz_log(YLOG_FATAL|YLOG_ERRNO, "fcntl");
-    if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0)
-        yaz_log(YLOG_FATAL|YLOG_ERRNO, "fcntl2");
+    enable_nonblock(s);
 
     yaz_log(YLOG_DEBUG, "New command connection");
     c = iochan_create(s, http_io, EVENT_INPUT | EVENT_EXCEPT);
@@ -1140,7 +1133,7 @@ void http_init(const char *addr)
     struct sockaddr_in myaddr;
     int one = 1;
     const char *pp;
-    int port;
+    short port;
 
     yaz_log(YLOG_LOG, "HTTP listener %s", addr);
 
@@ -1198,7 +1191,7 @@ void http_init(const char *addr)
 void http_set_proxyaddr(char *host, char *base_url)
 {
     char *p;
-    int port;
+    short port;
     struct hostent *he;
 
     strcpy(myurl, base_url);