Added HTTP tunnel facility for COMSTACK, bug #1752.
authorAdam Dickmeiss <adam@indexdata.dk>
Sun, 7 Oct 2007 08:53:26 +0000 (08:53 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Sun, 7 Oct 2007 08:53:26 +0000 (08:53 +0000)
This is a facility that allows a Web proxy, such as squid, to tunnel
Z39.50 traffic. This facility is "transparent" to must applications
using YAZ. It's enabled by using pseudo transport connect: followed bý
the we proxy address, followed by command, then follwed by he regular
"virtual" addresss. For example,
connect:webproxy.com:3128,tcp:z3950.loc.gov:7090/voyager .

NEWS
include/yaz/comstack.h
include/yaz/tcpip.h
src/comstack.c
src/tcpip.c

diff --git a/NEWS b/NEWS
index 295d7f9..1bae7fd 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,11 @@
+Added HTTP tunnel facility for COMSTACK, bug #1752.
+This is a facility that allows a Web proxy, such as squid, to tunnel
+Z39.50 traffic. This facility is "transparent" to must applications
+using YAZ. It's enabled by using pseudo transport connect: followed bý
+the we proxy address, followed by command, then follwed by he regular
+"virtual" addresss. For example,
+connect:webproxy.com:3128,tcp:z3950.loc.gov:7090/voyager . 
+
 --- 3.0.14 2007/09/21
 
 Fixed bad memory reference in ZOOM_record - cuased by member not being
index 3307a91..bbfbe52 100644 (file)
@@ -24,7 +24,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/* $Id: comstack.h,v 1.28 2007-10-05 16:46:55 adam Exp $ */
+/* $Id: comstack.h,v 1.29 2007-10-07 08:53:26 adam Exp $ */
 
 /** 
  * \file comstack.h
@@ -126,16 +126,14 @@ YAZ_EXPORT const char *cs_errmsg(int n);
 YAZ_EXPORT COMSTACK cs_create_host(const char *type_and_host, 
                                    int blocking, void **vp);
 YAZ_EXPORT void cs_get_host_args(const char *type_and_host, const char **args);
+YAZ_EXPORT int cs_complete_auto_head(const unsigned char *buf, int len);
 YAZ_EXPORT int cs_complete_auto(const unsigned char *buf, int len);
 YAZ_EXPORT void *cs_get_ssl(COMSTACK cs);
 YAZ_EXPORT int cs_set_ssl_ctx(COMSTACK cs, void *ctx);
 YAZ_EXPORT int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname);
 YAZ_EXPORT int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len);
 YAZ_EXPORT void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes);
-YAZ_EXPORT int cs_complete_http(const char *buf, int len);
-YAZ_EXPORT int cs_parse_host(const char *uri, const char **host,
-                             CS_TYPE *t, enum oid_proto *proto);
-                                          
+
 /*
  * error management.
  */
index 0208450..8269d8c 100644 (file)
@@ -24,7 +24,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/* $Id: tcpip.h,v 1.12 2007-04-12 13:52:57 adam Exp $ */
+/* $Id: tcpip.h,v 1.13 2007-10-07 08:53:26 adam Exp $ */
 
 /**
  * \file tcpip.h
@@ -41,6 +41,8 @@ YAZ_BEGIN_CDECL
 YAZ_EXPORT int completeWAIS(const unsigned char *buf, int len);
 YAZ_EXPORT COMSTACK tcpip_type(int s, int flags, int protocol, void *vp);
 YAZ_EXPORT COMSTACK ssl_type(int s, int flags, int protocol, void *vp);
+YAZ_EXPORT COMSTACK yaz_tcpip_create(int s, int flags, int protocol,
+                                     const char *connect_host);
 
 YAZ_END_CDECL
 
index 6934ea6..62978da 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2007, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: comstack.c,v 1.19 2007-10-05 16:46:55 adam Exp $
+ * $Id: comstack.c,v 1.20 2007-10-07 08:53:26 adam Exp $
  */
 
 /** 
@@ -74,9 +74,24 @@ void cs_get_host_args(const char *type_and_host, const char **args)
     }
 }
 
-int cs_parse_host(const char *uri, const char **host,
-                  CS_TYPE *t, enum oid_proto *proto)
+static int cs_parse_host(const char *uri, const char **host,
+                         CS_TYPE *t, enum oid_proto *proto,
+                         char **connect_host)
 {
+    *connect_host = 0;
+    if (strncmp(uri, "connect:", 8) == 0)
+    {
+        const char *cp = strchr(uri, ',');
+        if (cp)
+        {
+            size_t len = cp - (uri + 8);
+            *connect_host = xmalloc(len+1);
+            memcpy(*connect_host, uri + 8, len);
+            (*connect_host)[len] = '\0';
+            uri = cp+1;
+        }
+    }
+
     if (strncmp (uri, "tcp:", 4) == 0)
     {
         *t = tcpip_type;
@@ -138,18 +153,27 @@ COMSTACK cs_create_host(const char *vhost, int blocking, void **vp)
     const char *host = 0;
     COMSTACK cs;
     CS_TYPE t;
+    char *connect_host = 0;
 
-    cs_parse_host(vhost, &host, &t, &proto);
+    cs_parse_host(vhost, &host, &t, &proto, &connect_host);
 
-    cs = cs_create(t, blocking, proto);
-    if (!cs)
-        return 0;
-
-    if (!(*vp = cs_straddr(cs, host)))
+    if (t == tcpip_type)
     {
-        cs_close (cs);
-        return 0;
-    }    
+        cs = yaz_tcpip_create(-1, blocking, proto, connect_host ? host : 0);
+    }
+    else
+    {
+        cs = cs_create(t, blocking, proto);
+    }
+    if (cs)
+    {
+        if (!(*vp = cs_straddr(cs, connect_host ? connect_host : host)))
+        {
+            cs_close (cs);
+            cs = 0;
+        }    
+    }
+    xfree(connect_host);
     return cs;
 }
 
@@ -178,7 +202,7 @@ static int skip_crlf(const char *buf, int len, int *i)
 
 #define CHUNK_DEBUG 0
 
-int cs_complete_http(const char *buf, int len)
+static int cs_complete_http(const char *buf, int len, int head_only)
 {
     /* deal with HTTP request/response */
     int i = 2, content_len = 0, chunked = 0;
@@ -188,7 +212,7 @@ int cs_complete_http(const char *buf, int len)
 
     /* if dealing with HTTP responses - then default
        content length is unlimited (socket close) */
-    if (!memcmp(buf, "HTTP/", 5))
+    if (!head_only && !memcmp(buf, "HTTP/", 5))
         content_len = -1; 
 
 #if 0
@@ -324,18 +348,29 @@ int cs_complete_http(const char *buf, int len)
     return 0;
 }
 
-int cs_complete_auto(const unsigned char *buf, int len)
+static int cs_complete_auto_x(const unsigned char *buf, int len, int head_only)
 {
     if (len > 5 && buf[0] >= 0x20 && buf[0] < 0x7f
                 && buf[1] >= 0x20 && buf[1] < 0x7f
                 && buf[2] >= 0x20 && buf[2] < 0x7f)
     {
-        int r = cs_complete_http((const char *) buf, len);
+        int r = cs_complete_http((const char *) buf, len, head_only);
         return r;
     }
     return completeBER(buf, len);
 }
 
+
+int cs_complete_auto(const unsigned char *buf, int len)
+{
+    return cs_complete_auto_x(buf, len, 0);
+}
+
+int cs_complete_auto_head(const unsigned char *buf, int len)
+{
+    return cs_complete_auto_x(buf, len, 1);
+}
+
 void cs_set_max_recv_bytes(COMSTACK cs, int max_recv_bytes)
 {
     cs->max_recv_bytes = max_recv_bytes;
index 8ffdfe8..b1f9fa9 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2007, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: tcpip.c,v 1.34 2007-01-19 10:28:42 adam Exp $
+ * $Id: tcpip.c,v 1.35 2007-10-07 08:53:26 adam Exp $
  */
 /**
  * \file tcpip.c
@@ -65,6 +65,8 @@
 static int tcpip_close(COMSTACK h);
 static int tcpip_put(COMSTACK h, char *buf, int size);
 static int tcpip_get(COMSTACK h, char **buf, int *bufsize);
+static int tcpip_put_connect(COMSTACK h, char *buf, int size);
+static int tcpip_get_connect(COMSTACK h, char **buf, int *bufsize);
 static int tcpip_connect(COMSTACK h, void *address);
 static int tcpip_more(COMSTACK h);
 static int tcpip_rcvconnect(COMSTACK h);
@@ -115,6 +117,10 @@ typedef struct tcpip_state
     SSL *ssl;
     char cert_fname[256];
 #endif
+    char *connect_request_buf;
+    int connect_request_len;
+    char *connect_response_buf;
+    int connect_response_len;
 } tcpip_state;
 
 #ifdef WIN32
@@ -201,12 +207,38 @@ COMSTACK tcpip_type(int s, int flags, int protocol, void *vp)
     else
         sp->complete = cs_complete_auto;
 
+    sp->connect_request_buf = 0;
+    sp->connect_request_len = 0;
+    sp->connect_response_buf = 0;
+    sp->connect_response_len = 0;
+
     p->timeout = COMSTACK_DEFAULT_TIMEOUT;
     TRC(fprintf(stderr, "Created new TCPIP comstack\n"));
 
     return p;
 }
 
+COMSTACK yaz_tcpip_create(int s, int flags, int protocol,
+                          const char *connect_host)
+{
+    COMSTACK p = tcpip_type(s, flags, protocol, 0);
+    if (!p)
+        return 0;
+    if (connect_host)
+    {
+        tcpip_state *sp = (tcpip_state *) p->cprivate;
+        sp->connect_request_buf = xmalloc(strlen(connect_host) + 30);
+        sprintf(sp->connect_request_buf, "CONNECT %s HTTP/1.0\r\n\r\n",
+                connect_host);
+        sp->connect_request_len = strlen(sp->connect_request_buf);
+        p->f_put = tcpip_put_connect;
+        p->f_get = tcpip_get_connect;
+        sp->complete = cs_complete_auto_head; /* only want HTTP header */
+    }
+    return p;
+}
+
+
 #if HAVE_OPENSSL_SSL_H
 
 COMSTACK ssl_type(int s, int flags, int protocol, void *vp)
@@ -792,6 +824,8 @@ COMSTACK tcpip_accept(COMSTACK h)
             state->ssl = SSL_new (state->ctx);
             SSL_set_fd (state->ssl, cnew->iofile);
         }
+        state->connect_request_buf = 0;
+        state->connect_response_buf = 0;
 #endif
         h = cnew;
     }
@@ -1208,6 +1242,8 @@ int tcpip_close(COMSTACK h)
     if (sp->ai)
         freeaddrinfo(sp->ai);
 #endif
+    xfree(sp->connect_request_buf);
+    xfree(sp->connect_response_buf);
     xfree(sp);
     xfree(h);
     return 0;
@@ -1375,6 +1411,38 @@ int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname)
 }
 #endif
 
+
+static int tcpip_put_connect(COMSTACK h, char *buf, int size)
+{
+    struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
+
+    int r = tcpip_put(h, state->connect_request_buf,
+                      state->connect_request_len);
+    if (r == 0)
+    {
+        /* it's sent */
+        h->f_put = tcpip_put; /* switch to normal tcpip put */
+        r = tcpip_put(h, buf, size);
+    }
+    return r;
+}
+
+static int tcpip_get_connect(COMSTACK h, char **buf, int *bufsize)
+{
+    struct tcpip_state *state = (struct tcpip_state *)h->cprivate;
+    int r;
+
+    r = tcpip_get(h, &state->connect_response_buf, 
+                  &state->connect_response_len);
+    if (r < 1)
+        return r;
+    /* got the connect response completely */
+    state->complete = cs_complete_auto; /* switch to normal tcpip get */
+    h->f_get = tcpip_get;
+    return tcpip_get(h, buf, bufsize);
+}
+
+
 /*
  * Local variables:
  * c-basic-offset: 4