Added check for Unix specific headers and harmonize with Win32 build.
[pazpar2-moved-to-github.git] / src / http.c
index c23b63d..c68318a 100644 (file)
@@ -1,7 +1,5 @@
-/* $Id: http.c,v 1.42 2007-10-08 13:19:23 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,56 @@ 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
+
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 #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>
-#include <sys/uio.h>
+
 #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>
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
 #endif
 
-#include <netinet/in.h>
+#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 +133,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;
@@ -693,7 +697,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)
 {
@@ -710,7 +740,6 @@ static int http_proxy(struct http_request *rq)
         int sock;
         struct protoent *pe;
         int one = 1;
-        int flags;
 
         if (!(pe = getprotobyname("tcp"))) {
             abort();
@@ -723,18 +752,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;
@@ -824,7 +851,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);
@@ -874,7 +901,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");
@@ -915,25 +942,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)
 {
@@ -947,15 +955,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;
                 }
@@ -970,33 +982,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);
@@ -1009,7 +994,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");
@@ -1017,7 +1002,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;
@@ -1050,7 +1035,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);
@@ -1062,7 +1051,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);
 }
 
@@ -1108,7 +1101,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;
@@ -1117,10 +1109,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);
@@ -1141,7 +1130,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);
 
@@ -1199,7 +1188,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);