URI component encode/decode SRU database
authorAdam Dickmeiss <adam@indexdata.dk>
Mon, 23 Nov 2009 13:34:53 +0000 (14:34 +0100)
committerAdam Dickmeiss <adam@indexdata.dk>
Mon, 23 Nov 2009 13:35:35 +0000 (14:35 +0100)
Encoding of SRU database is performed by yaz_encode_sru_dbpath_odr or
yaz_encode_sru_dbpath_buf. Now used by yaz-client and the ZOOM API.
Decoding of SRU "path" database is performed by private function
yaz_decode_sru_dbpath_odr . This in turn is used by yaz_srw_decode
and yaz_sru_decode in server applications, GFS, yazproxy, metaproxy.

client/client.c
include/yaz/srw.h
src/srwutil.c
src/uri.c
src/zoom-c.c

index 824fe24..d1443ab 100644 (file)
@@ -1215,13 +1215,8 @@ static int send_srw(Z_SRW_PDU *sr)
     const char *charset = negotiationCharset;
     const char *host_port = cur_host;
     Z_GDU *gdu;
-    char *path = 0;
+    char *path = yaz_encode_sru_dbpath_odr(out, databaseNames[0]);
 
-    path = (char *) odr_malloc(out, 2+strlen(databaseNames[0]));
-    *path = '/';
-    strcpy(path+1, databaseNames[0]);
-
-    printf("path=%s\n", path);
     gdu = z_get_HTTP_Request_host_path(out, host_port, path);
 
     if (!yaz_matchstr(sru_method, "get"))
index 0741cb3..9c8c2c1 100644 (file)
@@ -250,6 +250,20 @@ YAZ_EXPORT int yaz_uri_to_array(const char *path, ODR o,
 YAZ_EXPORT void yaz_array_to_uri(char **path, ODR o,
                                  char **name, char **value);
 
+/** \brief encodes URI component
+    \param dst destination string (should be at least 3*strlen(uri)+1)
+    \param uri URI component C-string (source)
+*/
+YAZ_EXPORT void yaz_encode_uri_component(char *dst, const char *uri);
+
+/** \brief decodes URI component
+    \param dst destination string (should be at least strlen(uri)+1)
+    \param uri URI component buffer (source)
+    \param len number of bytes to decode from uri
+*/
+YAZ_EXPORT void yaz_decode_uri_component(char *dst, const char *uri,
+                                         size_t len);
+
 YAZ_EXPORT int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
                               Z_SOAP **soap_package, ODR decode, char **charset);
 YAZ_EXPORT int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
@@ -306,7 +320,23 @@ int sru_decode_surrogate_diagnostics(const char *buf, size_t len,
 YAZ_EXPORT
 void yaz_mk_sru_surrogate(ODR o, Z_SRW_record *record, int pos,
                           int code, const char *details);
-    
+
+/** \brief encode SRU database for HTTP path
+    \param out memory handle for resulting encoded database string
+    \param db source database
+    \returns encoded database path (includes leading /)
+*/
+YAZ_EXPORT
+char *yaz_encode_sru_dbpath_odr(ODR out, const char *db);
+
+/** \brief encode SRU database for HTTP path
+    \param dst destination buffer (should be at least strlen(db) +2 in size)
+    \param db source database
+   
+    The resulting database (dst) includes a leading /
+*/
+YAZ_EXPORT
+void yaz_encode_sru_dbpath_buf(char *dst, const char *db);
 
 YAZ_END_CDECL
 
index baac6a7..d011233 100644 (file)
@@ -8,10 +8,37 @@
  */
 
 #include <stdlib.h>
+#include <assert.h>
 #include <yaz/srw.h>
 #include <yaz/matchstr.h>
 #include <yaz/yaz-iconv.h>
 
+/** \brief decodes HTTP path (which should hold SRU database)
+    \param o memory for returned result
+    \param uri URI path (up to but not including ?)
+    \returns ODR allocated database
+*/
+static char *yaz_decode_sru_dbpath_odr(ODR n, const char *uri, size_t len)
+{
+    char *ret = odr_malloc(n, strlen(uri) + 1);
+    yaz_decode_uri_component(ret, uri, len);
+    return ret;
+}
+
+void yaz_encode_sru_dbpath_buf(char *dst, const char *db)
+{
+    assert(db);
+    *dst = '/';
+    yaz_encode_uri_component(dst+1, db);
+}
+
+char *yaz_encode_sru_dbpath_odr(ODR out, const char *db)
+{
+    char *dst = odr_malloc(out, 3 * strlen(db) + 2);
+    yaz_encode_sru_dbpath_buf(dst, db);
+    return dst;
+}
+
 #if YAZ_HAVE_XML2
 static int yaz_base64decode(const char *in, char *out)
 {
@@ -258,12 +285,7 @@ int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
             if (!p1)
                 p1 = p0 + strlen(p0);
             if (p1 != p0)
-            {
-                db = (char*) odr_malloc(decode, p1 - p0 + 1);
-                memcpy (db, p0, p1 - p0);
-                db[p1 - p0] = '\0';
-            }
-
+                db = yaz_decode_sru_dbpath_odr(decode, p0, p1 - p0);
             grab_charset(decode, content_type, charset);
 
             ret = z_soap_codec(decode, soap_package, 
@@ -386,11 +408,7 @@ int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
         if (!p1)
             p1 = p0 + strlen(p0);
         if (p1 != p0)
-        {
-            db = (char*) odr_malloc(decode, p1 - p0 + 1);
-            memcpy (db, p0, p1 - p0);
-            db[p1 - p0] = '\0';
-        }
+            db = yaz_decode_sru_dbpath_odr(decode, p0, p1 - p0);
         if (!strcmp(hreq->method, "POST"))
             p1 = hreq->content_buf;
         yaz_uri_to_array(p1, decode, &uri_name, &uri_val);
@@ -1305,7 +1323,6 @@ void yaz_encode_sru_extra(Z_SRW_PDU *sr, ODR odr, const char *extra_args)
 }
 
 
-
 /*
  * Local variables:
  * c-basic-offset: 4
index 326aaa2..ed1350a 100644 (file)
--- a/src/uri.c
+++ b/src/uri.c
@@ -20,10 +20,10 @@ static int hex_digit (int ch)
         return ch - 'a'+10;
     else if (ch >= 'A' && ch <= 'F')
         return ch - 'A'+10;
-    return 0;
+    return -1;
 }
 
-void encode_uri_char(char *dst, char ch)
+static void encode_uri_char(char *dst, char ch)
 {
     if (ch == ' ')
         strcpy(dst, "+");
@@ -41,6 +41,59 @@ void encode_uri_char(char *dst, char ch)
     }
 }
 
+void yaz_encode_uri_component(char *dst, const char *uri)
+{
+    for (; *uri; uri++)
+    {
+        encode_uri_char(dst, *uri);
+        dst += strlen(dst);
+    }
+    *dst = '\0';
+}
+
+static unsigned char decode_uri_char(const char *path, size_t *len)
+{
+    unsigned char ch;
+    if (*path == '+')
+    {
+        ch = ' ';
+        *len = 1;
+    }
+    else if (*path == '%' && *len >= 3)
+    {
+        int d1 = hex_digit(path[1]);
+        int d2 = hex_digit(path[2]);
+        if (d1 >= 0 && d2 >= 0)
+        {
+            ch = d1 * 16 + d2;
+            *len = 3;
+        }
+        else
+        {
+            ch = *path;
+            *len = 1;
+        }
+    }
+    else
+    {
+        ch = *path;
+        *len = 1;
+    }
+    return ch;
+}
+
+void yaz_decode_uri_component(char *dst, const char *uri, size_t len)
+{
+    while (len)
+    {
+        size_t sz = len;
+        *dst++ = decode_uri_char(uri, &sz);
+        uri += sz;
+        len = len - sz;
+    }
+    *dst = '\0';
+}
+
 void yaz_array_to_uri(char **path, ODR o, char **name, char **value)
 {
     size_t i, szp = 0, sz = 1;
@@ -50,22 +103,16 @@ void yaz_array_to_uri(char **path, ODR o, char **name, char **value)
     
     for(i = 0; name[i]; i++)
     {
-        size_t j, ilen;
+        size_t 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;
-        }
+
+        yaz_encode_uri_component(*path + szp, value[i]);
+        szp += strlen(*path + szp);
     }
     (*path)[szp] = '\0';
 }
@@ -107,18 +154,9 @@ int yaz_uri_to_array(const char *path, ODR o, char ***name, char ***val)
         (*val)[no] = ret = (char *) odr_malloc(o, p1 - path + 1);
         while (*path && *path != '&')
         {
-            if (*path == '+')
-            {
-                ret[i++] = ' ';
-                path++;
-            }
-            else if (*path == '%' && path[1] && path[2])
-            {
-                ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
-                path = path + 3;
-            }
-            else
-                ret[i++] = *path++;
+            size_t l = 3;
+            ret[i++] = decode_uri_char(path, &l);
+            path += l;
         }
         ret[i] = '\0';
 
@@ -153,18 +191,9 @@ char *yaz_uri_val(const char *path, const char *name, ODR o)
             ret = (char *) odr_malloc(o, p1 - path + 1);
             while (*path && *path != '&')
             {
-                if (*path == '+')
-                {
-                    ret[i++] = ' ';
-                    path++;
-                }
-                else if (*path == '%' && path[1] && path[2])
-                {
-                    ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
-                    path = path + 3;
-                }
-                else
-                    ret[i++] = *path++;
+                size_t l = 3;
+                ret[i++] = decode_uri_char(path, &l);
+                path += l;
             }
             ret[i] = '\0';
             return ret;
index dc1dc0c..a51bbb8 100644 (file)
@@ -1213,14 +1213,14 @@ static zoom_ret do_connect(ZOOM_connection c)
     if (c->cs && c->cs->protocol == PROTO_HTTP)
     {
 #if YAZ_HAVE_XML2
-        const char *path = 0;
+        const char *db = 0;
 
         c->proto = PROTO_HTTP;
-        cs_get_host_args(c->host_port, &path);
+        cs_get_host_args(c->host_port, &db);
         xfree(c->path);
-        c->path = (char*) xmalloc(strlen(path)+2);
-        c->path[0] = '/';
-        strcpy(c->path+1, path);
+
+        c->path = xmalloc(strlen(db) * 3 + 2);
+        yaz_encode_sru_dbpath_buf(c->path, db);
 #else
         set_ZOOM_error(c, ZOOM_ERROR_UNSUPPORTED_PROTOCOL, "SRW");
         do_close(c);
@@ -1445,11 +1445,7 @@ static zoom_ret send_srw(ZOOM_connection c, Z_SRW_PDU *sr)
     char *fdatabase = 0;
     
     if (database)
-    {
-        fdatabase = (char *) odr_malloc(c->odr_out, strlen(database)+2);
-        strcpy(fdatabase, "/");
-        strcat(fdatabase, database);
-    }
+        fdatabase = yaz_encode_sru_dbpath_odr(c->odr_out, database);
     gdu = z_get_HTTP_Request_host_path(c->odr_out, c->host_port,
                                        fdatabase ? fdatabase : c->path);