Added SRU-GET and SRU-POST support for ZOOM C. Option "sru" specifies
authorAdam Dickmeiss <adam@indexdata.dk>
Wed, 1 Mar 2006 23:24:24 +0000 (23:24 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Wed, 1 Mar 2006 23:24:24 +0000 (23:24 +0000)
which mode to use; one of "post", "get" or "soap" (SRW, default).

NEWS
include/yaz/srw.h
include/yaz/zgdu.h
src/soap.c
src/srwutil.c
src/zgdu.c
src/zoom-c.c
src/zoom-p.h
zoom/zoomtst2.c

diff --git a/NEWS b/NEWS
index a2e8fff..f36d557 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,7 @@
 
+Added SRU-GET and SRU-POST support for ZOOM C. Option "sru" specifies
+which mode to use; one of "post", "get" or "soap" (SRW, default).
+
 Fixed bug in character set conversion yaz_iconv. Some three byte UTF-8
 sequences where not read correctly. Fix by Rustam Usmanov.
 
index 7e221f7..dc721a1 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: srw.h,v 1.24 2005-12-14 14:05:55 adam Exp $
+ * $Id: srw.h,v 1.25 2006-03-01 23:24:24 adam Exp $
  */
 /**
  * \file srw.h
@@ -220,6 +220,10 @@ YAZ_EXPORT void yaz_mk_srw_diagnostic(ODR o, Z_SRW_diagnostic *d,
                                       const char *uri, const char *message,
                                       const char *details);
 
+YAZ_EXPORT int yaz_sru_get_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
+                                  ODR encode, char *charset);
+YAZ_EXPORT int yaz_sru_post_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
+                                   ODR encode, char *charset);
 YAZ_END_CDECL
 
 #endif
index e7a97c0..daa9d4a 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: zgdu.h,v 1.5 2005-06-25 15:46:03 adam Exp $
+ * $Id: zgdu.h,v 1.6 2006-03-01 23:24:25 adam Exp $
  */
 
 /**
@@ -56,6 +56,10 @@ typedef struct {
 YAZ_EXPORT int z_GDU (ODR o, Z_GDU **p, int opt, const char *name);
 YAZ_EXPORT void z_HTTP_header_add(ODR o, Z_HTTP_Header **hp, const char *n,
                                   const char *v);
+YAZ_EXPORT void z_HTTP_header_add_content_type(ODR o, Z_HTTP_Header **hp,
+                                               const char *content_type,
+                                               const char *charset);
+
 YAZ_EXPORT const char *z_HTTP_header_lookup(Z_HTTP_Header *hp, const char *n);
 
 YAZ_EXPORT const char *z_HTTP_errmsg(int code);
index 5bbc9cc..45e86cb 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: soap.c,v 1.12 2005-08-22 20:34:21 adam Exp $
+ * $Id: soap.c,v 1.13 2006-03-01 23:24:25 adam Exp $
  */
 /**
  * \file soap.c
@@ -45,8 +45,45 @@ int z_soap_codec_enc_xsl(ODR o, Z_SOAP **pp,
             return z_soap_error(o, p, "SOAP-ENV:Client",
                                 "Bad XML Document", 0);
 
-        /* check that root node is Envelope */
         ptr = xmlDocGetRootElement(doc);
+        if (!ptr || !ptr->ns)
+        {
+            xmlFreeDoc(doc);
+            return z_soap_error(o, p, "SOAP-ENV:Client",
+                                "No Envelope element", 0);
+        }
+        /* check for SRU root node match */
+        
+        for (i = 0; handlers[i].ns; i++)
+            if (!xmlStrcmp(ptr->ns->href, BAD_CAST handlers[i].ns))
+                break;
+        if (handlers[i].ns)
+        {
+            void *handler_data = 0;
+            xmlNode p_top_tmp; /* pseudo parent node needed */
+
+            p_top_tmp.children = ptr;
+            ret = (*handlers[i].f)(o, &p_top_tmp, &handler_data,
+                                   handlers[i].client_data,
+                                   handlers[i].ns);
+            
+            if (ret || !handler_data)
+                z_soap_error(o, p, "SOAP-ENV:Client",
+                             "SOAP Handler returned error", 0);
+            else
+            {
+                p->which = Z_SOAP_generic;
+                p->u.generic = (Z_SOAP_Generic *)
+                    odr_malloc(o, sizeof(*p->u.generic));
+                p->u.generic->no = i;
+                p->u.generic->ns = handlers[i].ns;
+                p->u.generic->p = handler_data;
+            }
+            xmlFreeDoc(doc);
+            return ret;
+        }
+        /* OK: assume SOAP */
+
         if (!ptr || ptr->type != XML_ELEMENT_NODE ||
             xmlStrcmp(ptr->name, BAD_CAST "Envelope") || !ptr->ns)
         {
index 168d12b..e075dad 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: srwutil.c,v 1.35 2006-02-01 20:28:44 adam Exp $
+ * $Id: srwutil.c,v 1.36 2006-03-01 23:24:25 adam Exp $
  */
 /**
  * \file srwutil.c
@@ -24,6 +24,52 @@ static int hex_digit (int ch)
     return 0;
 }
 
+void encode_uri_char(char *dst, char ch)
+{
+    if (ch == ' ')
+        strcpy(dst, "+");
+    else if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
+        (ch >= '0' && ch <= '9'))
+    {
+        dst[0] = ch;
+        dst[1] = '\0';
+    }
+    else
+    {
+        dst[0] = '%';
+        sprintf(dst+1, "%02X", (unsigned char ) ch);
+    }
+}
+
+void yaz_array_to_uri(char **path, ODR o, char **name, char **value)
+{
+    size_t i, szp = 0, sz = 0;
+    for(i = 0; name[i]; i++)
+        sz += strlen(name[i]) + 3 + strlen(value[i]) * 3;
+    *path = odr_malloc(o, sz);
+    
+    for(i = 0; name[i]; i++)
+    {
+        size_t j, ilen;
+        if (i)
+            (*path)[szp++] = '&';
+        ilen = strlen(name[i]);
+        memcpy(*path+szp, name[i], ilen);
+        szp += ilen;
+        (*path)[szp++] = '=';
+        for (j = 0; value[i][j]; j++)
+        {
+            size_t vlen;
+            char vstr[5];
+            encode_uri_char(vstr, value[i][j]);
+            vlen = strlen(vstr);
+            memcpy(*path+szp, vstr, vlen);
+            szp += vlen;
+        }
+    }
+    (*path)[szp] = '\0';
+}
+
 int yaz_uri_array(const char *path, ODR o, char ***name, char ***val)
 {
     int no = 2;
@@ -32,7 +78,7 @@ int yaz_uri_array(const char *path, ODR o, char ***name, char ***val)
     if (*path == '?')
         path++;
     if (!*path)
-        return no;
+        return 0;
     cp = path;
     while ((cp = strchr(cp, '&')))
     {
@@ -872,6 +918,162 @@ int yaz_diag_srw_to_bib1(int code)
     return 1;
 }
 
+static void add_val_int(ODR o, char **name, char **value,  int *i,
+                        char *a_name, int *val)
+{
+    if (val)
+    {
+        name[*i] = a_name;
+        value[*i] = odr_malloc(o, 30);
+        sprintf(value[*i], "%d", *val);
+        (*i)++;
+    }
+}
+
+static void add_val_str(ODR o, char **name, char **value,  int *i,
+                        char *a_name, char *val)
+{
+    if (val)
+    {
+        name[*i] = a_name;
+        value[*i] = val;
+        (*i)++;
+    }
+}
+
+static int yaz_get_sru_parms(const Z_SRW_PDU *srw_pdu, ODR encode,
+                              char **name, char **value)
+{
+    int i = 0;
+    add_val_str(encode, name, value, &i, "version", srw_pdu->srw_version);
+    name[i] = "operation";
+    switch(srw_pdu->which)
+    {
+    case Z_SRW_searchRetrieve_request:
+        value[i++] = "searchRetrieve";
+        switch(srw_pdu->u.request->query_type)
+        {
+        case Z_SRW_query_type_cql:
+            add_val_str(encode, name, value, &i, "query",
+                        srw_pdu->u.request->query.cql);
+            break;
+        case Z_SRW_query_type_pqf:
+            add_val_str(encode, name, value, &i, "x-pquery",
+                        srw_pdu->u.request->query.pqf);
+            break;
+        case Z_SRW_query_type_xcql:
+            add_val_str(encode, name, value, &i, "x-cql",
+                        srw_pdu->u.request->query.xcql);
+            break;
+        }
+        switch(srw_pdu->u.request->sort_type)
+        {
+        case Z_SRW_sort_type_none:
+            break;
+        case Z_SRW_sort_type_sort:            
+            add_val_str(encode, name, value, &i, "sortKeys",
+                        srw_pdu->u.request->sort.sortKeys);
+            break;
+        }
+        add_val_int(encode, name, value, &i, "startRecord", 
+                    srw_pdu->u.request->startRecord);
+        add_val_int(encode, name, value, &i, "maximumRecords", 
+                    srw_pdu->u.request->maximumRecords);
+        add_val_str(encode, name, value, &i, "recordSchema",
+                    srw_pdu->u.request->recordSchema);
+        add_val_str(encode, name, value, &i, "recordPacking",
+                    srw_pdu->u.request->recordPacking);
+        add_val_str(encode, name, value, &i, "recordXPath",
+                    srw_pdu->u.request->recordXPath);
+        add_val_str(encode, name, value, &i, "stylesheet",
+                    srw_pdu->u.request->stylesheet);
+        add_val_int(encode, name, value, &i, "resultSetTTL", 
+                    srw_pdu->u.request->resultSetTTL);
+        break;
+    case Z_SRW_explain_request:
+        value[i++] = "explain";
+        add_val_str(encode, name, value, &i, "stylesheet",
+                    srw_pdu->u.explain_request->stylesheet);
+        break;
+    case Z_SRW_scan_request:
+        value[i++] = "scan";
+
+        switch(srw_pdu->u.scan_request->query_type)
+        {
+        case Z_SRW_query_type_cql:
+            add_val_str(encode, name, value, &i, "scanClause",
+                        srw_pdu->u.scan_request->scanClause.cql);
+            break;
+        case Z_SRW_query_type_pqf:
+            add_val_str(encode, name, value, &i, "x-pScanClause",
+                        srw_pdu->u.scan_request->scanClause.pqf);
+            break;
+        case Z_SRW_query_type_xcql:
+            add_val_str(encode, name, value, &i, "x-cqlScanClause",
+                        srw_pdu->u.scan_request->scanClause.xcql);
+            break;
+        }
+        add_val_int(encode, name, value, &i, "responsePosition", 
+                    srw_pdu->u.scan_request->responsePosition);
+        add_val_int(encode, name, value, &i, "maximumTerms", 
+                    srw_pdu->u.scan_request->maximumTerms);
+        add_val_str(encode, name, value, &i, "stylesheet",
+                    srw_pdu->u.scan_request->stylesheet);
+        break;
+    case Z_SRW_update_request:
+        value[i++] = "update";
+        break;
+    default:
+        return -1;
+    }
+    name[i++] = 0;
+    return 0;
+}
+
+int yaz_sru_get_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
+                       ODR encode, char *charset)
+{
+    char *name[30], *value[30]; /* definite upper limit for SRU params */
+    char *uri_args;
+    char *path;
+
+    if (yaz_get_sru_parms(srw_pdu, encode, name, value))
+        return -1;
+    yaz_array_to_uri(&uri_args, encode, name, value);
+
+    hreq->method = "GET";
+    
+    path = odr_malloc(encode, strlen(hreq->path) + strlen(uri_args) + 3);
+    sprintf(path, "%s?%s", hreq->path, uri_args);
+    hreq->path = path;
+
+    z_HTTP_header_add_content_type(encode, &hreq->headers,
+                                   "text/xml", charset);
+    return 0;
+}
+
+int yaz_sru_post_encode(Z_HTTP_Request *hreq, Z_SRW_PDU *srw_pdu,
+                        ODR encode, char *charset)
+{
+    char *name[30], *value[30]; /* definite upper limit for SRU params */
+    char *uri_args;
+
+    if (yaz_get_sru_parms(srw_pdu, encode, name, value))
+        return -1;
+
+    yaz_array_to_uri(&uri_args, encode, name, value);
+
+    hreq->method = "POST";
+    
+    hreq->content_buf = uri_args;
+    hreq->content_len = strlen(uri_args);
+
+    z_HTTP_header_add_content_type(encode, &hreq->headers,
+                                   "application/x-www-form-urlencoded",
+                                   charset);
+    return 0;
+}
+
 /*
  * Local variables:
  * c-basic-offset: 4
index 88c92a5..0dfdbaf 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: zgdu.c,v 1.13 2005-06-25 15:46:06 adam Exp $
+ * $Id: zgdu.c,v 1.14 2006-03-01 23:24:25 adam Exp $
  */
 
 /**
@@ -152,6 +152,22 @@ static int decode_headers_content(ODR o, int off, Z_HTTP_Header **headers,
     return 1;
 }
 
+void z_HTTP_header_add_content_type(ODR o, Z_HTTP_Header **hp,
+                                    const char *content_type,
+                                    const char *charset)
+{
+    const char *l = "Content-Type";
+    if (charset)
+    {
+        char *ctype = odr_malloc(o, strlen(content_type)+strlen(charset) + 15);
+        sprintf(ctype, "%s; charset=%s", content_type, charset);
+        z_HTTP_header_add(o, hp, l, ctype);
+    }
+    else
+        z_HTTP_header_add(o, hp, l, content_type);
+
+}
+
 void z_HTTP_header_add(ODR o, Z_HTTP_Header **hp, const char *n,
                        const char *v)
 {
index 6b90468..384ef76 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: zoom-c.c,v 1.63 2006-02-19 18:36:10 adam Exp $
+ * $Id: zoom-c.c,v 1.64 2006-03-01 23:24:25 adam Exp $
  */
 /**
  * \file zoom-c.c
@@ -54,7 +54,6 @@ static zoom_ret ZOOM_connection_send_init (ZOOM_connection c);
 static zoom_ret do_write_ex (ZOOM_connection c, char *buf_out, int len_out);
 static char *cql2pqf(ZOOM_connection c, const char *cql);
 
-
 static void initlog()
 {
     static int log_level_initialized = 0;
@@ -339,6 +338,19 @@ ZOOM_connection_new (const char *host, int portnum)
     return c;
 }
 
+static zoom_sru_mode get_sru_mode_from_string(const char *s)
+{
+    if (!s || !*s)
+        return zoom_sru_soap;
+    if (!yaz_matchstr(s, "soap"))
+        return zoom_sru_soap;
+    else if (!yaz_matchstr(s, "get"))
+        return zoom_sru_get;
+    else if (!yaz_matchstr(s, "post"))
+        return zoom_sru_post;
+    return zoom_sru_error;
+}
+
 ZOOM_API(void)
 ZOOM_connection_connect(ZOOM_connection c,
                         const char *host, int portnum)
@@ -388,6 +400,9 @@ ZOOM_connection_connect(ZOOM_connection c,
     else
         c->lang = 0;
 
+    val = ZOOM_options_get (c->options, "sru");
+    c->sru_mode = get_sru_mode_from_string(val);
+
     xfree (c->host_port);
     if (portnum)
     {
@@ -1129,7 +1144,7 @@ static zoom_ret ZOOM_connection_send_init (ZOOM_connection c)
         ZOOM_options_get(c->options, "implementationName"),
         odr_prepend(c->odr_out, "ZOOM-C", ireq->implementationName));
 
-    version = odr_strdup(c->odr_out, "$Revision: 1.63 $");
+    version = odr_strdup(c->odr_out, "$Revision: 1.64 $");
     if (strlen(version) > 10)   /* check for unexpanded CVS strings */
         version[strlen(version)-2] = '\0';
     ireq->implementationVersion = odr_prepend(c->odr_out,
@@ -1225,7 +1240,6 @@ static zoom_ret ZOOM_connection_send_init (ZOOM_connection c)
 #if HAVE_XML2
 static zoom_ret send_srw (ZOOM_connection c, Z_SRW_PDU *sr)
 {
-    char ctype[50];
     Z_SOAP_Handler h[2] = {
         {"http://www.loc.gov/zing/srw/", 0, (Z_SOAP_fun) yaz_srw_codec},
         {0, 0, 0}
@@ -1262,34 +1276,40 @@ static zoom_ret send_srw (ZOOM_connection c, Z_SRW_PDU *sr)
         }
     }
 
-    strcpy(ctype, "text/xml");
-    if (c->charset && strlen(c->charset) < 20)
+    if (c->sru_mode == zoom_sru_get)
+    {
+        yaz_sru_get_encode(gdu->u.HTTP_Request, sr, c->odr_out, c->charset);
+    }
+    else if (c->sru_mode == zoom_sru_post)
     {
-        strcat(ctype, "; charset=");
-        strcat(ctype, c->charset);
+        yaz_sru_post_encode(gdu->u.HTTP_Request, sr, c->odr_out, c->charset);
     }
-    z_HTTP_header_add(c->odr_out, &gdu->u.HTTP_Request->headers,
-                      "Content-Type", ctype);
-    z_HTTP_header_add(c->odr_out, &gdu->u.HTTP_Request->headers,
-                      "SOAPAction", "\"\"");
-    p->which = Z_SOAP_generic;
-    p->u.generic = (Z_SOAP_Generic *) odr_malloc(o, sizeof(*p->u.generic));
-    p->u.generic->no = 0;
-    p->u.generic->ns = 0;
-    p->u.generic->p = sr;
-    p->ns = "http://schemas.xmlsoap.org/soap/envelope/";
+    else if (c->sru_mode == zoom_sru_soap)
+    {
+        z_HTTP_header_add_content_type(c->odr_out,
+                                       &gdu->u.HTTP_Request->headers,
+                                       "text/xml", c->charset);
 
-    ret = z_soap_codec_enc(o, &p,
-                           &gdu->u.HTTP_Request->content_buf,
-                           &gdu->u.HTTP_Request->content_len, h,
-                           c->charset);
+        z_HTTP_header_add(c->odr_out, &gdu->u.HTTP_Request->headers,
+                          "SOAPAction", "\"\"");
+        p->which = Z_SOAP_generic;
+        p->u.generic = (Z_SOAP_Generic *) odr_malloc(o, sizeof(*p->u.generic));
+        p->u.generic->no = 0;
+        p->u.generic->ns = 0;
+        p->u.generic->p = sr;
+        p->ns = "http://schemas.xmlsoap.org/soap/envelope/";
+        
+        ret = z_soap_codec_enc(o, &p,
+                               &gdu->u.HTTP_Request->content_buf,
+                               &gdu->u.HTTP_Request->content_len, h,
+                               c->charset);
 
+    }
     if (!z_GDU(c->odr_out, &gdu, 0, 0))
         return zoom_complete;
     c->buf_out = odr_getbuf(c->odr_out, &c->len_out, 0);
-
     odr_destroy(o);
-
+        
     event = ZOOM_Event_create (ZOOM_EVENT_SEND_APDU);
     ZOOM_connection_put_event (c, event);
     odr_reset(c->odr_out);
index d445957..5213cfc 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: zoom-p.h,v 1.9 2005-10-17 12:25:39 mike Exp $
+ * $Id: zoom-p.h,v 1.10 2006-03-01 23:24:26 adam Exp $
  */
 /**
  * \file zoom-p.h
@@ -24,6 +24,14 @@ struct ZOOM_query_p {
     char *query_string;
 };
 
+typedef enum {
+    zoom_sru_error,
+    zoom_sru_soap,
+    zoom_sru_get,
+    zoom_sru_post,
+} zoom_sru_mode;
+    
+
 typedef struct ZOOM_task_p *ZOOM_task;
 
 #define STATE_IDLE 0
@@ -65,6 +73,7 @@ struct ZOOM_connection_p {
     ZOOM_resultset resultsets;
     ZOOM_Event m_queue_front;
     ZOOM_Event m_queue_back;
+    zoom_sru_mode sru_mode;
 };
 
 struct ZOOM_options_entry {
index f670802..40b197c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: zoomtst2.c,v 1.6 2005-06-25 15:46:08 adam Exp $
+ * $Id: zoomtst2.c,v 1.7 2006-03-01 23:24:26 adam Exp $
  *
  * Asynchronous single-target client performing search (no retrieval)
  */
@@ -27,6 +27,9 @@ int main(int argc, char **argv)
     /* create connection (don't connect yet) */
     z = ZOOM_connection_create(0);
 
+    /* option: set sru/get operation (only applicable if http: is used) */
+    ZOOM_connection_option_set (z, "sru", "post");
+
     /* option: set async operation */
     ZOOM_connection_option_set (z, "async", "1");