2 * Copyright (c) 2002-2004, Index Data.
3 * See the file LICENSE for details.
5 * $Id: srwutil.c,v 1.17 2004-10-09 08:49:55 adam Exp $
9 #include <yaz/yaz-iconv.h>
11 static int hex_digit (int ch)
13 if (ch >= '0' && ch <= '9')
15 else if (ch >= 'a' && ch <= 'f')
17 else if (ch >= 'A' && ch <= 'F')
22 int yaz_uri_array(const char *path, ODR o, char ***name, char ***val)
31 while ((cp = strchr(cp, '&')))
36 *name = odr_malloc(o, no * sizeof(char**));
37 *val = odr_malloc(o, no * sizeof(char**));
39 for (no = 0; *path; no++)
41 const char *p1 = strchr(path, '=');
47 (*name)[no] = odr_malloc(o, (p1-path)+1);
48 memcpy((*name)[no], path, p1-path);
49 (*name)[no][p1-path] = '\0';
52 p1 = strchr(path, '&');
54 p1 = strlen(path) + path;
55 (*val)[no] = ret = odr_malloc(o, p1 - path + 1);
56 while (*path && *path != '&')
63 else if (*path == '%' && path[1] && path[2])
65 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
81 char *yaz_uri_val(const char *path, const char *name, ODR o)
83 size_t nlen = strlen(name);
89 const char *p1 = strchr(path, '=');
92 if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
98 p1 = strchr(path, '&');
100 p1 = strlen(path) + path;
101 ret = (char *) odr_malloc(o, p1 - path + 1);
102 while (*path && *path != '&')
109 else if (*path == '%' && path[1] && path[2])
111 ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
120 path = strchr(p1, '&');
127 void yaz_uri_val_int(const char *path, const char *name, ODR o, int **intp)
129 const char *v = yaz_uri_val(path, name, o);
131 *intp = odr_intdup(o, atoi(v));
134 void yaz_mk_std_diagnostic(ODR o, Z_SRW_diagnostic *d,
135 int code, const char *details)
137 d->uri = (char *) odr_malloc(o, 50);
138 sprintf(d->uri, "info:srw/diagnostic/1/%d", code);
141 d->details = odr_strdup(o, details);
146 void yaz_add_srw_diagnostic(ODR o, Z_SRW_diagnostic **d,
147 int *num, int code, const char *addinfo)
149 Z_SRW_diagnostic *d_new;
150 d_new = (Z_SRW_diagnostic *) odr_malloc (o, (*num + 1)* sizeof(**d));
152 memcpy (d_new, *d, *num *sizeof(**d));
155 yaz_mk_std_diagnostic(o, *d + *num, code, addinfo);
159 int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
160 Z_SOAP **soap_package, ODR decode, char **charset)
162 if (!strcmp(hreq->method, "POST"))
164 const char *content_type = z_HTTP_header_lookup(hreq->headers,
166 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
168 char *db = "Default";
169 const char *p0 = hreq->path, *p1;
171 const char *charset_p = 0;
173 static Z_SOAP_Handler soap_handlers[3] = {
175 {"http://www.loc.gov/zing/srw/", 0,
176 (Z_SOAP_fun) yaz_srw_codec},
177 {"http://www.loc.gov/zing/srw/v1.0/", 0,
178 (Z_SOAP_fun) yaz_srw_codec},
185 p1 = strchr(p0, '?');
187 p1 = p0 + strlen(p0);
190 db = (char*) odr_malloc(decode, p1 - p0 + 1);
191 memcpy (db, p0, p1 - p0);
195 if (charset && (charset_p = strstr(content_type, "; charset=")))
199 while (i < 20 && charset_p[i] &&
200 !strchr("; \n\r", charset_p[i]))
202 *charset = (char*) odr_malloc(decode, i+1);
203 memcpy(*charset, charset_p, i);
204 (*charset)[i] = '\0';
206 ret = z_soap_codec(decode, soap_package,
207 &hreq->content_buf, &hreq->content_len,
209 if (ret == 0 && (*soap_package)->which == Z_SOAP_generic)
211 *srw_pdu = (Z_SRW_PDU*) (*soap_package)->u.generic->p;
213 if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request &&
214 (*srw_pdu)->u.request->database == 0)
215 (*srw_pdu)->u.request->database = db;
217 if ((*srw_pdu)->which == Z_SRW_explain_request &&
218 (*srw_pdu)->u.explain_request->database == 0)
219 (*srw_pdu)->u.explain_request->database = db;
221 if ((*srw_pdu)->which == Z_SRW_scan_request &&
222 (*srw_pdu)->u.scan_request->database == 0)
223 (*srw_pdu)->u.scan_request->database = db;
233 int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
234 Z_SOAP **soap_package, ODR decode, char **charset,
235 Z_SRW_diagnostic **diag, int *num_diag)
238 static Z_SOAP_Handler soap_handlers[2] = {
239 {"http://www.loc.gov/zing/srw/", 0,
240 (Z_SOAP_fun) yaz_srw_codec},
244 if (!strcmp(hreq->method, "GET"))
246 char *db = "Default";
247 const char *p0 = hreq->path, *p1;
248 const char *operation = 0;
253 char *stylesheet = 0;
254 char *scanClause = 0;
255 char *recordXPath = 0;
256 char *recordSchema = 0;
257 char *recordPacking = "xml"; /* xml packing is default for SRU */
258 char *maximumRecords = 0;
259 char *startRecord = 0;
267 p1 = strchr(p0, '?');
269 p1 = p0 + strlen(p0);
272 db = (char*) odr_malloc(decode, p1 - p0 + 1);
273 memcpy (db, p0, p1 - p0);
276 yaz_uri_array(p1, decode, &uri_name, &uri_val);
281 for (i = 0; uri_name[i]; i++)
283 char *n = uri_name[i];
284 char *v = uri_val[i];
285 if (!strcmp(n, "query"))
287 else if (!strcmp(n, "x-pquery"))
289 else if (!strcmp(n, "operation"))
291 else if (!strcmp(n, "stylesheet"))
293 else if (!strcmp(n, "sortKeys"))
295 else if (!strcmp(n, "recordXPath"))
297 else if (!strcmp(n, "recordSchema"))
299 else if (!strcmp(n, "recordPacking"))
301 else if (!strcmp(n, "version"))
303 else if (!strcmp(n, "scanClause"))
305 else if (!strcmp(n, "maximumRecords"))
307 else if (!strcmp(n, "startRecord"))
310 yaz_add_srw_diagnostic(decode, diag, num_diag, 8, n);
316 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "version");
319 if (strcmp(version, "1.1"))
320 yaz_add_srw_diagnostic(decode, diag, num_diag, 5, "1.1");
324 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "operation");
325 operation = "explain";
327 if (!strcmp(operation, "searchRetrieve"))
329 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);
331 sr->srw_version = version;
335 sr->u.request->query_type = Z_SRW_query_type_cql;
336 sr->u.request->query.cql = query;
340 sr->u.request->query_type = Z_SRW_query_type_pqf;
341 sr->u.request->query.pqf = pQuery;
344 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "query");
348 sr->u.request->sort_type = Z_SRW_sort_type_sort;
349 sr->u.request->sort.sortKeys = sortKeys;
351 sr->u.request->recordXPath = recordXPath;
352 sr->u.request->recordSchema = recordSchema;
353 sr->u.request->recordPacking = recordPacking;
354 sr->u.request->stylesheet = stylesheet;
357 sr->u.request->maximumRecords =
358 odr_intdup(decode, atoi(maximumRecords));
360 sr->u.request->startRecord =
361 odr_intdup(decode, atoi(startRecord));
363 sr->u.request->database = db;
365 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
366 (*soap_package)->which = Z_SOAP_generic;
368 (*soap_package)->u.generic =
369 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
371 (*soap_package)->u.generic->p = sr;
372 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
373 (*soap_package)->u.generic->no = 0;
375 (*soap_package)->ns = "SRU";
379 else if (!strcmp(operation, "explain"))
381 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
383 sr->srw_version = version;
385 sr->u.explain_request->recordPacking = recordPacking;
386 sr->u.explain_request->database = db;
388 sr->u.explain_request->stylesheet = stylesheet;
390 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
391 (*soap_package)->which = Z_SOAP_generic;
393 (*soap_package)->u.generic =
394 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
396 (*soap_package)->u.generic->p = sr;
397 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
398 (*soap_package)->u.generic->no = 0;
400 (*soap_package)->ns = "SRU";
404 else if (!strcmp(operation, "scan"))
406 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_scan_request);
409 yaz_add_srw_diagnostic(decode, diag, num_diag, 7,
411 sr->srw_version = version;
413 sr->u.scan_request->scanClause = scanClause;
414 sr->u.scan_request->database = db;
415 sr->u.scan_request->stylesheet = stylesheet;
417 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
418 (*soap_package)->which = Z_SOAP_generic;
420 (*soap_package)->u.generic =
421 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
423 (*soap_package)->u.generic->p = sr;
424 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
425 (*soap_package)->u.generic->no = 0;
427 (*soap_package)->ns = "SRU";
433 /* unsupported operation ... */
434 /* Act as if we received a explain request and throw diagnostic. */
436 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
438 sr->srw_version = version;
440 sr->u.explain_request->recordPacking = recordPacking;
441 sr->u.explain_request->database = db;
443 sr->u.explain_request->stylesheet = stylesheet;
445 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
446 (*soap_package)->which = Z_SOAP_generic;
448 (*soap_package)->u.generic =
449 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
451 (*soap_package)->u.generic->p = sr;
452 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
453 (*soap_package)->u.generic->no = 0;
455 (*soap_package)->ns = "SRU";
457 yaz_add_srw_diagnostic(decode, diag, num_diag, 4, operation);
466 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
468 Z_SRW_PDU *sr = (Z_SRW_PDU *) odr_malloc(o, sizeof(*o));
470 sr->srw_version = odr_strdup(o, "1.1");
474 case Z_SRW_searchRetrieve_request:
475 sr->u.request = (Z_SRW_searchRetrieveRequest *)
476 odr_malloc(o, sizeof(*sr->u.request));
477 sr->u.request->query_type = Z_SRW_query_type_cql;
478 sr->u.request->query.cql = 0;
479 sr->u.request->sort_type = Z_SRW_sort_type_none;
480 sr->u.request->sort.none = 0;
481 sr->u.request->startRecord = 0;
482 sr->u.request->maximumRecords = 0;
483 sr->u.request->recordSchema = 0;
484 sr->u.request->recordPacking = 0;
485 sr->u.request->recordXPath = 0;
486 sr->u.request->database = 0;
487 sr->u.request->resultSetTTL = 0;
488 sr->u.request->stylesheet = 0;
490 case Z_SRW_searchRetrieve_response:
491 sr->u.response = (Z_SRW_searchRetrieveResponse *)
492 odr_malloc(o, sizeof(*sr->u.response));
493 sr->u.response->numberOfRecords = 0;
494 sr->u.response->resultSetId = 0;
495 sr->u.response->resultSetIdleTime = 0;
496 sr->u.response->records = 0;
497 sr->u.response->num_records = 0;
498 sr->u.response->diagnostics = 0;
499 sr->u.response->num_diagnostics = 0;
500 sr->u.response->nextRecordPosition = 0;
502 case Z_SRW_explain_request:
503 sr->u.explain_request = (Z_SRW_explainRequest *)
504 odr_malloc(o, sizeof(*sr->u.explain_request));
505 sr->u.explain_request->recordPacking = 0;
506 sr->u.explain_request->database = 0;
507 sr->u.explain_request->stylesheet = 0;
509 case Z_SRW_explain_response:
510 sr->u.explain_response = (Z_SRW_explainResponse *)
511 odr_malloc(o, sizeof(*sr->u.explain_response));
512 sr->u.explain_response->record.recordData_buf = 0;
513 sr->u.explain_response->record.recordData_len = 0;
514 sr->u.explain_response->record.recordSchema = 0;
515 sr->u.explain_response->record.recordPosition = 0;
516 sr->u.explain_response->record.recordPacking =
517 Z_SRW_recordPacking_string;
518 sr->u.explain_response->diagnostics = 0;
519 sr->u.explain_response->num_diagnostics = 0;
521 case Z_SRW_scan_request:
522 sr->u.scan_request = (Z_SRW_scanRequest *)
523 odr_malloc(o, sizeof(*sr->u.scan_request));
524 sr->u.scan_request->database = 0;
525 sr->u.scan_request->stylesheet = 0;
526 sr->u.scan_request->maximumTerms = 0;
527 sr->u.scan_request->responsePosition = 0;
528 sr->u.scan_request->scanClause = 0;
530 case Z_SRW_scan_response:
531 sr->u.scan_response = (Z_SRW_scanResponse *)
532 odr_malloc(o, sizeof(*sr->u.scan_response));
533 sr->u.scan_response->terms = 0;
534 sr->u.scan_response->num_terms = 0;
535 sr->u.scan_response->diagnostics = 0;
536 sr->u.scan_response->num_diagnostics = 0;
545 } yaz_srw_codes [] = {
546 {1, "Permanent system error"},
547 {2, "System temporarily unavailable"},
548 {3, "Authentication error"},
549 {4, "Unsupported operation"},
550 {5, "Unsupported version"},
551 {6, "Unsupported parameter value"},
552 {7, "Mandatory parameter not supplied"},
553 {8, "Unsupported parameter"},
554 /* Diagnostics Relating to CQL */
555 {10, "Query syntax error"},
556 {11, "Unsupported query type"},
557 {12, "Too many characters in query"},
558 {13, "Invalid or unsupported use of parentheses"},
559 {14, "Invalid or unsupported use of quotes"},
560 {15, "Unsupported context set"},
561 {16, "Unsupported index"},
562 {17, "Unsupported combination of index and context set"},
563 {18, "Unsupported combination of indexes"},
564 {19, "Unsupported relation"},
565 {20, "Unsupported relation modifier"},
566 {21, "Unsupported combination of relation modifers"},
567 {22, "Unsupported combination of relation and index"},
568 {23, "Too many characters in term"},
569 {24, "Unsupported combination of relation and term"},
570 {25, "Special characters not quoted in term"},
571 {26, "Non special character escaped in term"},
572 {27, "Empty term unsupported"},
573 {28, "Masking character not supported"},
574 {29, "Masked words too short"},
575 {30, "Too many masking characters in term"},
576 {31, "Anchoring character not supported"},
577 {32, "Anchoring character in unsupported position"},
578 {33, "Combination of proximity/adjacency and masking characters not supported"},
579 {34, "Combination of proximity/adjacency and anchoring characters not supported"},
580 {35, "Terms only exclusion stopwords"},
581 {36, "Term in invalid format for index or relation"},
582 {37, "Unsupported boolean operator"},
583 {38, "Too many boolean operators in query"},
584 {39, "Proximity not supported"},
585 {40, "Unsupported proximity relation"},
586 {41, "Unsupported proximity distance"},
587 {42, "Unsupported proximity unit"},
588 {43, "Unsupported proximity ordering"},
589 {44, "Unsupported combination of proximity modifiers"},
590 {45, "context set name (prefix) assigned to multiple identifiers"},
591 /* Diagnostics Relating to Result Sets */
592 {50, "Result sets not supported"},
593 {51, "Result set does not exist"},
594 {52, "Result set temporarily unavailable"},
595 {53, "Result sets only supported for retrieval"},
596 {54, "Retrieval may only occur from an existing result set"},
597 {55, "Combination of result sets with search terms not supported"},
598 {56, "Only combination of single result set with search terms supported"},
599 {57, "Result set created but no records available"},
600 {58, "Result set created with unpredictable partial results available"},
601 {59, "Result set created with valid partial results available"},
602 /* Diagnostics Relating to Records */
603 {60, "Result set no created: too many records retrieved"},
604 {61, "First record position out of range"},
605 {62, "Negative number of records requested"},
606 {63, "System error in retrieving records"},
607 {64, "Record temporarily unavailable"},
608 {65, "Record does not exist"},
609 {66, "Unknown schema for retrieval"},
610 {67, "Record not available in this schema"},
611 {68, "Not authorised to send record"},
612 {69, "Not authorised to send record in this schema"},
613 {70, "Record too large to send"},
614 {71, "Unsupported record packing"},
615 {72, "XPath retrieval unsupported"},
616 {73, "XPath expression contains unsupported feature"},
617 {74, "Unable to evaluate XPath expression"},
618 /* Diagnostics Relating to Sorting */
619 {80, "Sort not supported"},
620 {81, "Unsupported sort type"},
621 {82, "Unsupported sort sequence"},
622 {83, "Too many records to sort"},
623 {84, "Too many sort keys to sort"},
624 {85, "Duplicate sort keys"},
625 {86, "Cannot sort: incompatible record formats"},
626 {87, "Unsupported schema for sort"},
627 {88, "Unsupported path for sort"},
628 {89, "Path unsupported for schema"},
629 {90, "Unsupported direction value"},
630 {91, "Unsupported case value"},
631 {92, "Unsupported missing value action"},
632 /* Diagnostics Relating to Explain */
633 {100, "Explain not supported"},
634 {101, "Explain request type not supported (SOAP vs GET)"},
635 {102, "Explain record temporarily unavailable"},
636 /* Diagnostics Relating to Stylesheets */
637 {110, "Stylesheets not supported"},
638 {111, "Unsupported stylesheet"},
639 /* Diagnostics relating to Scan */
640 {120, "Response position out of range"},
644 const char *yaz_diag_srw_str (int code)
647 for (i = 0; yaz_srw_codes[i].code; i++)
648 if (yaz_srw_codes[i].code == code)
649 return yaz_srw_codes[i].msg;
655 static int srw_bib1_map[] = {
665 108, 10, /* Malformed query : Syntax error */
695 100, 1, /* bad map */
743 205, 1, /* bad map */
744 206, 1, /* bad map */
746 208, 1, /* bad map */
757 218, 1, /* bad map */
758 219, 1, /* bad map */
759 220, 1, /* bad map */
760 221, 1, /* bad map */
761 222, 1, /* bad map */
762 223, 1, /* bad map */
763 224, 1, /* bad map */
764 225, 1, /* bad map */
765 226, 1, /* bad map */
767 228, 1, /* bad map */
772 233, 1, /* bad map */
773 234, 1, /* bad map */
779 240, 1, /* bad map */
780 241, 1, /* bad map */
782 243, 1, /* bad map */
787 1001, 1, /* bad map */
788 1002, 1, /* bad map */
789 1003, 1, /* bad map */
790 1004, 1, /* bad map */
791 1005, 1, /* bad map */
792 1006, 1, /* bad map */
824 int yaz_diag_bib1_to_srw (int code)
826 const int *p = srw_bib1_map;
836 int yaz_diag_srw_to_bib1(int code)
838 const int *p = srw_bib1_map;