From 54dc5b4629da5b10c2f3d4e3bdb7cb70c46669a5 Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Mon, 23 Nov 2009 14:34:53 +0100 Subject: [PATCH] URI component encode/decode SRU database 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 | 7 +--- include/yaz/srw.h | 32 ++++++++++++++++- src/srwutil.c | 41 +++++++++++++++------- src/uri.c | 101 ++++++++++++++++++++++++++++++++++------------------- src/zoom-c.c | 16 ++++----- 5 files changed, 132 insertions(+), 65 deletions(-) diff --git a/client/client.c b/client/client.c index 824fe24..d1443ab 100644 --- a/client/client.c +++ b/client/client.c @@ -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")) diff --git a/include/yaz/srw.h b/include/yaz/srw.h index 0741cb3..9c8c2c1 100644 --- a/include/yaz/srw.h +++ b/include/yaz/srw.h @@ -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 diff --git a/src/srwutil.c b/src/srwutil.c index baac6a7..d011233 100644 --- a/src/srwutil.c +++ b/src/srwutil.c @@ -8,10 +8,37 @@ */ #include +#include #include #include #include +/** \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 diff --git a/src/uri.c b/src/uri.c index 326aaa2..ed1350a 100644 --- 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; diff --git a/src/zoom-c.c b/src/zoom-c.c index dc1dc0c..a51bbb8 100644 --- a/src/zoom-c.c +++ b/src/zoom-c.c @@ -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); -- 1.7.10.4