2 * Copyright (c) 2002-2004, Index Data.
3 * See the file LICENSE for details.
5 * $Id: srwutil.c,v 1.16 2004-10-02 13:28:26 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);
314 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "version");
315 else if (version && strcmp(version, "1.1"))
316 yaz_add_srw_diagnostic(decode, diag, num_diag, 5, "1.1");
319 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "operation");
320 operation = "explain";
322 if (!strcmp(operation, "searchRetrieve"))
324 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);
326 sr->srw_version = version;
330 sr->u.request->query_type = Z_SRW_query_type_cql;
331 sr->u.request->query.cql = query;
335 sr->u.request->query_type = Z_SRW_query_type_pqf;
336 sr->u.request->query.pqf = pQuery;
339 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "query");
343 sr->u.request->sort_type = Z_SRW_sort_type_sort;
344 sr->u.request->sort.sortKeys = sortKeys;
346 sr->u.request->recordXPath = recordXPath;
347 sr->u.request->recordSchema = recordSchema;
348 sr->u.request->recordPacking = recordPacking;
349 sr->u.request->stylesheet = stylesheet;
352 sr->u.request->maximumRecords =
353 odr_intdup(decode, atoi(maximumRecords));
355 sr->u.request->startRecord =
356 odr_intdup(decode, atoi(startRecord));
358 sr->u.request->database = db;
360 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
361 (*soap_package)->which = Z_SOAP_generic;
363 (*soap_package)->u.generic =
364 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
366 (*soap_package)->u.generic->p = sr;
367 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
368 (*soap_package)->u.generic->no = 0;
370 (*soap_package)->ns = "SRU";
374 else if (!strcmp(operation, "explain"))
376 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
378 sr->srw_version = version;
380 sr->u.explain_request->recordPacking = recordPacking;
381 sr->u.explain_request->database = db;
383 sr->u.explain_request->stylesheet = stylesheet;
385 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
386 (*soap_package)->which = Z_SOAP_generic;
388 (*soap_package)->u.generic =
389 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
391 (*soap_package)->u.generic->p = sr;
392 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
393 (*soap_package)->u.generic->no = 0;
395 (*soap_package)->ns = "SRU";
399 else if (!strcmp(operation, "scan"))
401 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_scan_request);
404 yaz_add_srw_diagnostic(decode, diag, num_diag, 7,
406 sr->srw_version = version;
408 sr->u.scan_request->scanClause = scanClause;
409 sr->u.scan_request->database = db;
410 sr->u.scan_request->stylesheet = stylesheet;
412 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
413 (*soap_package)->which = Z_SOAP_generic;
415 (*soap_package)->u.generic =
416 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
418 (*soap_package)->u.generic->p = sr;
419 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
420 (*soap_package)->u.generic->no = 0;
422 (*soap_package)->ns = "SRU";
428 /* unsupported operation ... */
429 /* Act as if we received a explain request and throw diagnostic. */
431 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
433 sr->srw_version = version;
435 sr->u.explain_request->recordPacking = recordPacking;
436 sr->u.explain_request->database = db;
438 sr->u.explain_request->stylesheet = stylesheet;
440 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
441 (*soap_package)->which = Z_SOAP_generic;
443 (*soap_package)->u.generic =
444 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
446 (*soap_package)->u.generic->p = sr;
447 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
448 (*soap_package)->u.generic->no = 0;
450 (*soap_package)->ns = "SRU";
452 yaz_add_srw_diagnostic(decode, diag, num_diag, 4, operation);
461 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
463 Z_SRW_PDU *sr = (Z_SRW_PDU *) odr_malloc(o, sizeof(*o));
465 sr->srw_version = odr_strdup(o, "1.1");
469 case Z_SRW_searchRetrieve_request:
470 sr->u.request = (Z_SRW_searchRetrieveRequest *)
471 odr_malloc(o, sizeof(*sr->u.request));
472 sr->u.request->query_type = Z_SRW_query_type_cql;
473 sr->u.request->query.cql = 0;
474 sr->u.request->sort_type = Z_SRW_sort_type_none;
475 sr->u.request->sort.none = 0;
476 sr->u.request->startRecord = 0;
477 sr->u.request->maximumRecords = 0;
478 sr->u.request->recordSchema = 0;
479 sr->u.request->recordPacking = 0;
480 sr->u.request->recordXPath = 0;
481 sr->u.request->database = 0;
482 sr->u.request->resultSetTTL = 0;
483 sr->u.request->stylesheet = 0;
485 case Z_SRW_searchRetrieve_response:
486 sr->u.response = (Z_SRW_searchRetrieveResponse *)
487 odr_malloc(o, sizeof(*sr->u.response));
488 sr->u.response->numberOfRecords = 0;
489 sr->u.response->resultSetId = 0;
490 sr->u.response->resultSetIdleTime = 0;
491 sr->u.response->records = 0;
492 sr->u.response->num_records = 0;
493 sr->u.response->diagnostics = 0;
494 sr->u.response->num_diagnostics = 0;
495 sr->u.response->nextRecordPosition = 0;
497 case Z_SRW_explain_request:
498 sr->u.explain_request = (Z_SRW_explainRequest *)
499 odr_malloc(o, sizeof(*sr->u.explain_request));
500 sr->u.explain_request->recordPacking = 0;
501 sr->u.explain_request->database = 0;
502 sr->u.explain_request->stylesheet = 0;
504 case Z_SRW_explain_response:
505 sr->u.explain_response = (Z_SRW_explainResponse *)
506 odr_malloc(o, sizeof(*sr->u.explain_response));
507 sr->u.explain_response->record.recordData_buf = 0;
508 sr->u.explain_response->record.recordData_len = 0;
509 sr->u.explain_response->record.recordSchema = 0;
510 sr->u.explain_response->record.recordPosition = 0;
511 sr->u.explain_response->record.recordPacking =
512 Z_SRW_recordPacking_string;
513 sr->u.explain_response->diagnostics = 0;
514 sr->u.explain_response->num_diagnostics = 0;
516 case Z_SRW_scan_request:
517 sr->u.scan_request = (Z_SRW_scanRequest *)
518 odr_malloc(o, sizeof(*sr->u.scan_request));
519 sr->u.scan_request->database = 0;
520 sr->u.scan_request->stylesheet = 0;
521 sr->u.scan_request->maximumTerms = 0;
522 sr->u.scan_request->responsePosition = 0;
523 sr->u.scan_request->scanClause = 0;
525 case Z_SRW_scan_response:
526 sr->u.scan_response = (Z_SRW_scanResponse *)
527 odr_malloc(o, sizeof(*sr->u.scan_response));
528 sr->u.scan_response->terms = 0;
529 sr->u.scan_response->num_terms = 0;
530 sr->u.scan_response->diagnostics = 0;
531 sr->u.scan_response->num_diagnostics = 0;
540 } yaz_srw_codes [] = {
541 {1, "Permanent system error"},
542 {2, "System temporarily unavailable"},
543 {3, "Authentication error"},
544 {4, "Unsupported operation"},
545 {5, "Unsupported version"},
546 {6, "Unsupported parameter value"},
547 {7, "Mandatory parameter not supplied"},
548 {8, "Unsupported parameter"},
549 /* Diagnostics Relating to CQL */
550 {10, "Query syntax error"},
551 {11, "Unsupported query type"},
552 {12, "Too many characters in query"},
553 {13, "Invalid or unsupported use of parentheses"},
554 {14, "Invalid or unsupported use of quotes"},
555 {15, "Unsupported context set"},
556 {16, "Unsupported index"},
557 {17, "Unsupported combination of index and context set"},
558 {18, "Unsupported combination of indexes"},
559 {19, "Unsupported relation"},
560 {20, "Unsupported relation modifier"},
561 {21, "Unsupported combination of relation modifers"},
562 {22, "Unsupported combination of relation and index"},
563 {23, "Too many characters in term"},
564 {24, "Unsupported combination of relation and term"},
565 {25, "Special characters not quoted in term"},
566 {26, "Non special character escaped in term"},
567 {27, "Empty term unsupported"},
568 {28, "Masking character not supported"},
569 {29, "Masked words too short"},
570 {30, "Too many masking characters in term"},
571 {31, "Anchoring character not supported"},
572 {32, "Anchoring character in unsupported position"},
573 {33, "Combination of proximity/adjacency and masking characters not supported"},
574 {34, "Combination of proximity/adjacency and anchoring characters not supported"},
575 {35, "Terms only exclusion stopwords"},
576 {36, "Term in invalid format for index or relation"},
577 {37, "Unsupported boolean operator"},
578 {38, "Too many boolean operators in query"},
579 {39, "Proximity not supported"},
580 {40, "Unsupported proximity relation"},
581 {41, "Unsupported proximity distance"},
582 {42, "Unsupported proximity unit"},
583 {43, "Unsupported proximity ordering"},
584 {44, "Unsupported combination of proximity modifiers"},
585 {45, "context set name (prefix) assigned to multiple identifiers"},
586 /* Diagnostics Relating to Result Sets */
587 {50, "Result sets not supported"},
588 {51, "Result set does not exist"},
589 {52, "Result set temporarily unavailable"},
590 {53, "Result sets only supported for retrieval"},
591 {54, "Retrieval may only occur from an existing result set"},
592 {55, "Combination of result sets with search terms not supported"},
593 {56, "Only combination of single result set with search terms supported"},
594 {57, "Result set created but no records available"},
595 {58, "Result set created with unpredictable partial results available"},
596 {59, "Result set created with valid partial results available"},
597 /* Diagnostics Relating to Records */
598 {60, "Result set no created: too many records retrieved"},
599 {61, "First record position out of range"},
600 {62, "Negative number of records requested"},
601 {63, "System error in retrieving records"},
602 {64, "Record temporarily unavailable"},
603 {65, "Record does not exist"},
604 {66, "Unknown schema for retrieval"},
605 {67, "Record not available in this schema"},
606 {68, "Not authorised to send record"},
607 {69, "Not authorised to send record in this schema"},
608 {70, "Record too large to send"},
609 {71, "Unsupported record packing"},
610 {72, "XPath retrieval unsupported"},
611 {73, "XPath expression contains unsupported feature"},
612 {74, "Unable to evaluate XPath expression"},
613 /* Diagnostics Relating to Sorting */
614 {80, "Sort not supported"},
615 {81, "Unsupported sort type"},
616 {82, "Unsupported sort sequence"},
617 {83, "Too many records to sort"},
618 {84, "Too many sort keys to sort"},
619 {85, "Duplicate sort keys"},
620 {86, "Cannot sort: incompatible record formats"},
621 {87, "Unsupported schema for sort"},
622 {88, "Unsupported path for sort"},
623 {89, "Path unsupported for schema"},
624 {90, "Unsupported direction value"},
625 {91, "Unsupported case value"},
626 {92, "Unsupported missing value action"},
627 /* Diagnostics Relating to Explain */
628 {100, "Explain not supported"},
629 {101, "Explain request type not supported (SOAP vs GET)"},
630 {102, "Explain record temporarily unavailable"},
631 /* Diagnostics Relating to Stylesheets */
632 {110, "Stylesheets not supported"},
633 {111, "Unsupported stylesheet"},
634 /* Diagnostics relating to Scan */
635 {120, "Response position out of range"},
639 const char *yaz_diag_srw_str (int code)
642 for (i = 0; yaz_srw_codes[i].code; i++)
643 if (yaz_srw_codes[i].code == code)
644 return yaz_srw_codes[i].msg;
650 static int srw_bib1_map[] = {
660 108, 10, /* Malformed query : Syntax error */
690 100, 1, /* bad map */
738 205, 1, /* bad map */
739 206, 1, /* bad map */
741 208, 1, /* bad map */
752 218, 1, /* bad map */
753 219, 1, /* bad map */
754 220, 1, /* bad map */
755 221, 1, /* bad map */
756 222, 1, /* bad map */
757 223, 1, /* bad map */
758 224, 1, /* bad map */
759 225, 1, /* bad map */
760 226, 1, /* bad map */
762 228, 1, /* bad map */
767 233, 1, /* bad map */
768 234, 1, /* bad map */
774 240, 1, /* bad map */
775 241, 1, /* bad map */
777 243, 1, /* bad map */
782 1001, 1, /* bad map */
783 1002, 1, /* bad map */
784 1003, 1, /* bad map */
785 1004, 1, /* bad map */
786 1005, 1, /* bad map */
787 1006, 1, /* bad map */
819 int yaz_diag_bib1_to_srw (int code)
821 const int *p = srw_bib1_map;
831 int yaz_diag_srw_to_bib1(int code)
833 const int *p = srw_bib1_map;