which mode to use; one of "post", "get" or "soap" (SRW, default).
+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.
* 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
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
* 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 $
*/
/**
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);
* 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
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)
{
* 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
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;
if (*path == '?')
path++;
if (!*path)
- return no;
+ return 0;
cp = path;
while ((cp = strchr(cp, '&')))
{
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
* 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 $
*/
/**
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)
{
* 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
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;
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)
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)
{
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,
#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}
}
}
- 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);
* 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
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
ZOOM_resultset resultsets;
ZOOM_Event m_queue_front;
ZOOM_Event m_queue_back;
+ zoom_sru_mode sru_mode;
};
struct ZOOM_options_entry {
/*
- * $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)
*/
/* 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");