2 * Copyright (c) 2002-2004, Index Data.
3 * See the file LICENSE for details.
5 * $Id: srwutil.c,v 1.9 2004-01-09 19:54:05 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 = 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_add_srw_diagnostic(ODR o, Z_SRW_diagnostic **d,
135 int *num, int code, const char *addinfo)
137 Z_SRW_diagnostic *d_new;
138 d_new = (Z_SRW_diagnostic *) odr_malloc (o, (*num + 1)* sizeof(**d));
140 memcpy (d_new, *d, *num *sizeof(**d));
142 (*d + *num)->code = odr_intdup(o, code);
144 (*d + *num)->details = odr_strdup(o, addinfo);
146 (*d + *num)->details = 0;
150 int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
151 Z_SOAP **soap_package, ODR decode, char **charset)
153 if (!strcmp(hreq->method, "POST"))
155 const char *content_type = z_HTTP_header_lookup(hreq->headers,
157 if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
159 char *db = "Default";
160 const char *p0 = hreq->path, *p1;
162 const char *charset_p = 0;
164 static Z_SOAP_Handler soap_handlers[3] = {
166 {"http://www.loc.gov/zing/srw/", 0,
167 (Z_SOAP_fun) yaz_srw_codec},
168 {"http://www.loc.gov/zing/srw/v1.0/", 0,
169 (Z_SOAP_fun) yaz_srw_codec},
176 p1 = strchr(p0, '?');
178 p1 = p0 + strlen(p0);
181 db = (char*) odr_malloc(decode, p1 - p0 + 1);
182 memcpy (db, p0, p1 - p0);
186 if (charset && (charset_p = strstr(content_type, "; charset=")))
190 while (i < 20 && charset_p[i] &&
191 !strchr("; \n\r", charset_p[i]))
193 *charset = (char*) odr_malloc(decode, i+1);
194 memcpy(*charset, charset_p, i);
195 (*charset)[i] = '\0';
197 ret = z_soap_codec(decode, soap_package,
198 &hreq->content_buf, &hreq->content_len,
200 if (ret == 0 && (*soap_package)->which == Z_SOAP_generic)
202 *srw_pdu = (Z_SRW_PDU*) (*soap_package)->u.generic->p;
204 if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request &&
205 (*srw_pdu)->u.request->database == 0)
206 (*srw_pdu)->u.request->database = db;
208 if ((*srw_pdu)->which == Z_SRW_explain_request &&
209 (*srw_pdu)->u.explain_request->database == 0)
210 (*srw_pdu)->u.explain_request->database = db;
212 if ((*srw_pdu)->which == Z_SRW_scan_request &&
213 (*srw_pdu)->u.scan_request->database == 0)
214 (*srw_pdu)->u.scan_request->database = db;
224 int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
225 Z_SOAP **soap_package, ODR decode, char **charset,
226 Z_SRW_diagnostic **diag, int *num_diag)
229 static Z_SOAP_Handler soap_handlers[2] = {
230 {"http://www.loc.gov/zing/srw/", 0,
231 (Z_SOAP_fun) yaz_srw_codec},
235 if (!strcmp(hreq->method, "GET"))
237 char *db = "Default";
238 const char *p0 = hreq->path, *p1;
239 const char *operation = 0;
244 char *stylesheet = 0;
245 char *scanClause = 0;
246 char *recordXPath = 0;
247 char *recordSchema = 0;
248 char *recordPacking = "xml";
249 char *maximumRecords = 0;
250 char *startRecord = 0;
258 p1 = strchr(p0, '?');
260 p1 = p0 + strlen(p0);
263 db = (char*) odr_malloc(decode, p1 - p0 + 1);
264 memcpy (db, p0, p1 - p0);
267 yaz_uri_array(p1, decode, &uri_name, &uri_val);
272 for (i = 0; uri_name[i]; i++)
274 char *n = uri_name[i];
275 char *v = uri_val[i];
276 if (!strcmp(n, "query"))
278 else if (!strcmp(n, "x-pquery"))
280 else if (!strcmp(n, "operation"))
282 else if (!strcmp(n, "stylesheet"))
284 else if (!strcmp(n, "sortKeys"))
286 else if (!strcmp(n, "recordXPath"))
288 else if (!strcmp(n, "recordSchema"))
290 else if (!strcmp(n, "recordPacking"))
292 else if (!strcmp(n, "version"))
294 else if (!strcmp(n, "scanClause"))
296 else if (!strcmp(n, "maximumRecords"))
298 else if (!strcmp(n, "startRecord"))
301 yaz_add_srw_diagnostic(decode, diag, num_diag, 9, n);
305 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "version");
306 else if (version && strcmp(version, "1.1"))
307 yaz_add_srw_diagnostic(decode, diag, num_diag, 5, "1.1");
310 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "operation");
311 operation = "explain";
313 if (!strcmp(operation, "searchRetrieve"))
315 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);
317 sr->srw_version = version;
321 sr->u.request->query_type = Z_SRW_query_type_cql;
322 sr->u.request->query.cql = query;
326 sr->u.request->query_type = Z_SRW_query_type_pqf;
327 sr->u.request->query.pqf = pQuery;
330 yaz_add_srw_diagnostic(decode, diag, num_diag, 7, "query");
334 sr->u.request->sort_type = Z_SRW_sort_type_sort;
335 sr->u.request->sort.sortKeys = sortKeys;
337 sr->u.request->recordXPath = recordXPath;
338 sr->u.request->recordSchema = recordSchema;
339 sr->u.request->recordPacking = recordPacking;
340 sr->u.request->stylesheet = stylesheet;
343 sr->u.request->maximumRecords =
344 odr_intdup(decode, atoi(maximumRecords));
346 sr->u.request->startRecord =
347 odr_intdup(decode, atoi(startRecord));
349 sr->u.request->database = db;
351 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
352 (*soap_package)->which = Z_SOAP_generic;
354 (*soap_package)->u.generic =
355 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
357 (*soap_package)->u.generic->p = sr;
358 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
359 (*soap_package)->u.generic->no = 0;
361 (*soap_package)->ns = "SRU";
365 else if (!strcmp(operation, "explain"))
367 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
369 sr->srw_version = version;
371 sr->u.explain_request->recordPacking = recordPacking;
372 sr->u.explain_request->database = db;
374 sr->u.explain_request->stylesheet = stylesheet;
376 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
377 (*soap_package)->which = Z_SOAP_generic;
379 (*soap_package)->u.generic =
380 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
382 (*soap_package)->u.generic->p = sr;
383 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
384 (*soap_package)->u.generic->no = 0;
386 (*soap_package)->ns = "SRU";
390 else if (!strcmp(operation, "scan"))
392 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_scan_request);
395 yaz_add_srw_diagnostic(decode, diag, num_diag, 7,
397 sr->srw_version = version;
399 sr->u.scan_request->scanClause = scanClause;
400 sr->u.scan_request->database = db;
401 sr->u.scan_request->stylesheet = stylesheet;
403 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
404 (*soap_package)->which = Z_SOAP_generic;
406 (*soap_package)->u.generic =
407 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
409 (*soap_package)->u.generic->p = sr;
410 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
411 (*soap_package)->u.generic->no = 0;
413 (*soap_package)->ns = "SRU";
419 /* unsupported operation ... */
420 /* Act as if we received a explain request and throw diagnostic. */
422 Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
424 sr->srw_version = version;
426 sr->u.explain_request->recordPacking = recordPacking;
427 sr->u.explain_request->database = db;
429 sr->u.explain_request->stylesheet = stylesheet;
431 (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
432 (*soap_package)->which = Z_SOAP_generic;
434 (*soap_package)->u.generic =
435 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
437 (*soap_package)->u.generic->p = sr;
438 (*soap_package)->u.generic->ns = soap_handlers[0].ns;
439 (*soap_package)->u.generic->no = 0;
441 (*soap_package)->ns = "SRU";
443 yaz_add_srw_diagnostic(decode, diag, num_diag, 4, operation);
452 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
454 Z_SRW_PDU *sr = odr_malloc(o, sizeof(*o));
456 sr->srw_version = odr_strdup(o, "1.1");
460 case Z_SRW_searchRetrieve_request:
461 sr->u.request = (Z_SRW_searchRetrieveRequest *)
462 odr_malloc(o, sizeof(*sr->u.request));
463 sr->u.request->query_type = Z_SRW_query_type_cql;
464 sr->u.request->query.cql = 0;
465 sr->u.request->sort_type = Z_SRW_sort_type_none;
466 sr->u.request->sort.none = 0;
467 sr->u.request->startRecord = 0;
468 sr->u.request->maximumRecords = 0;
469 sr->u.request->recordSchema = 0;
470 sr->u.request->recordPacking = 0;
471 sr->u.request->recordXPath = 0;
472 sr->u.request->database = 0;
473 sr->u.request->resultSetTTL = 0;
474 sr->u.request->stylesheet = 0;
476 case Z_SRW_searchRetrieve_response:
477 sr->u.response = (Z_SRW_searchRetrieveResponse *)
478 odr_malloc(o, sizeof(*sr->u.response));
479 sr->u.response->numberOfRecords = 0;
480 sr->u.response->resultSetId = 0;
481 sr->u.response->resultSetIdleTime = 0;
482 sr->u.response->records = 0;
483 sr->u.response->num_records = 0;
484 sr->u.response->diagnostics = 0;
485 sr->u.response->num_diagnostics = 0;
486 sr->u.response->nextRecordPosition = 0;
488 case Z_SRW_explain_request:
489 sr->u.explain_request = (Z_SRW_explainRequest *)
490 odr_malloc(o, sizeof(*sr->u.explain_request));
491 sr->u.explain_request->recordPacking = 0;
492 sr->u.explain_request->database = 0;
493 sr->u.explain_request->stylesheet = 0;
495 case Z_SRW_explain_response:
496 sr->u.explain_response = (Z_SRW_explainResponse *)
497 odr_malloc(o, sizeof(*sr->u.explain_response));
498 sr->u.explain_response->record.recordData_buf = 0;
499 sr->u.explain_response->record.recordData_len = 0;
500 sr->u.explain_response->record.recordSchema = 0;
501 sr->u.explain_response->record.recordPosition = 0;
502 sr->u.explain_response->record.recordPacking =
503 Z_SRW_recordPacking_string;
504 sr->u.explain_response->diagnostics = 0;
505 sr->u.explain_response->num_diagnostics = 0;
507 case Z_SRW_scan_request:
508 sr->u.scan_request = (Z_SRW_scanRequest *)
509 odr_malloc(o, sizeof(*sr->u.scan_request));
510 sr->u.scan_request->database = 0;
511 sr->u.scan_request->stylesheet = 0;
512 sr->u.scan_request->maximumTerms = 0;
513 sr->u.scan_request->responsePosition = 0;
514 sr->u.scan_request->scanClause = 0;
516 case Z_SRW_scan_response:
517 sr->u.scan_response = (Z_SRW_scanResponse *)
518 odr_malloc(o, sizeof(*sr->u.scan_response));
519 sr->u.scan_response->terms = 0;
520 sr->u.scan_response->num_terms = 0;
521 sr->u.scan_response->diagnostics = 0;
522 sr->u.scan_response->num_diagnostics = 0;
531 } yaz_srw_codes [] = {
532 {1, "Permanent system error"},
533 {2, "System temporarily unavailable"},
534 {3, "Authentication error"},
535 {4, "Unsupported operation"},
536 {5, "Unsupported version"},
537 {6, "Unsupported parameter value"},
538 {7, "Mandatory parameter not supplied"},
539 {8, "Unknown database"},
540 {9, "Unknown parameter type"},
541 /* Diagnostics Relating to CQL */
542 {10, "Query syntax error"},
543 {11, "Unsupported query type"},
544 {12, "Too many characters in query"},
545 {13, "Invalid or unsupported use of parentheses"},
546 {14, "Invalid or unsupported use of quotes"},
547 {15, "Unsupported context context set"},
548 {16, "Unsupported index"},
549 {17, "Unsupported combination of index and context set"},
550 {18, "Unsupported combination of indexes"},
551 {19, "Unsupported relation"},
552 {20, "Unsupported relation modifier"},
553 {21, "Unsupported combination of relation modifers"},
554 {22, "Unsupported combination of relation and index"},
555 {23, "Too many characters in term"},
556 {24, "Unsupported combination of relation and term"},
557 {25, "Special characters not quoted in term"},
558 {26, "Non special character escaped in term"},
559 {27, "Empty term unsupported"},
560 {28, "Masking character not supported"},
561 {29, "Masked words too short"},
562 {30, "Too many masking characters in term"},
563 {31, "Anchoring character not supported"},
564 {32, "Anchoring character in unsupported position"},
565 {33, "Combination of proximity/adjacency and masking characters not supported"},
566 {34, "Combination of proximity/adjacency and anchoring characters not supported"},
567 {35, "Terms only exclusion stopwords"},
568 {36, "Term in invalid format for index or relation"},
569 {37, "Unsupported boolean operator"},
570 {38, "Too many boolean operators in query"},
571 {39, "Proximity not supported"},
572 {40, "Unsupported proximity relation"},
573 {41, "Unsupported proximity distance"},
574 {42, "Unsupported proximity unit"},
575 {43, "Unsupported proximity ordering"},
576 {44, "Unsupported combination of proximity modifiers"},
577 {45, "context set name (prefix) assigned to multiple identifiers"},
578 /* Diagnostics Relating to Result Sets */
579 {50, "Result sets not supported"},
580 {51, "Result set does not exist"},
581 {52, "Result set temporarily unavailable"},
582 {53, "Result sets only supported for retrieval"},
583 {54, "Retrieval may only occur from an existing result set"},
584 {55, "Combination of result sets with search terms not supported"},
585 {56, "Only combination of single result set with search terms supported"},
586 {57, "Result set created but no records available"},
587 {58, "Result set created with unpredictable partial results available"},
588 {59, "Result set created with valid partial results available"},
589 /* Diagnostics Relating to Records */
590 {60, "Result set no created: too many records retrieved"},
591 {61, "First record position out of range"},
592 {62, "Negative number of records requested"},
593 {63, "System error in retrieving records"},
594 {64, "Record temporarily unavailable"},
595 {65, "Record does not exist"},
596 {66, "Unknown schema for retrieval"},
597 {67, "Record not available in this schema"},
598 {68, "Not authorised to send record"},
599 {69, "Not authorised to send record in this schema"},
600 {70, "Record too large to send"},
601 {71, "Unsupported record packing"},
602 {72, "XPath retrieval unsupported"},
603 {73, "XPath expression contains unsupported feature"},
604 {74, "Unable to evaluate XPath expression"},
605 /* Diagnostics Relating to Sorting */
606 {80, "Sort not supported"},
607 {81, "Unsupported sort type"},
608 {82, "Unsupported sort sequence"},
609 {83, "Too many records to sort"},
610 {84, "Too many sort keys to sort"},
611 {85, "Duplicate sort keys"},
612 {86, "Cannot sort: incompatible record formats"},
613 {87, "Unsupported schema for sort"},
614 {88, "Unsupported path for sort"},
615 {89, "Path unsupported for schema"},
616 {90, "Unsupported direction value"},
617 {91, "Unsupported case value"},
618 {92, "Unsupported missing value action"},
619 /* Diagnostics Relating to Explain */
620 {100, "Explain not supported"},
621 {101, "Explain request type not supported (SOAP vs GET)"},
622 {102, "Explain record temporarily unavailable"},
623 /* Diagnostics Relating to Stylesheets */
624 {110, "Stylesheets not supported"},
625 {111, "Unsupported stylesheet"},
626 /* Diagnostics relating to Scan */
627 {120, "Response position out of range"},
631 const char *yaz_diag_srw_str (int code)
634 for (i = 0; yaz_srw_codes[i].code; i++)
635 if (yaz_srw_codes[i].code == code)
636 return yaz_srw_codes[i].msg;
642 static int srw_bib1_map[] = {
652 108, 10, /* Malformed query : Syntax error */
682 100, 1, /* bad map */
729 205, 1, /* bad map */
730 206, 1, /* bad map */
732 208, 1, /* bad map */
743 218, 1, /* bad map */
744 219, 1, /* bad map */
745 220, 1, /* bad map */
746 221, 1, /* bad map */
747 222, 1, /* bad map */
748 223, 1, /* bad map */
749 224, 1, /* bad map */
750 225, 1, /* bad map */
751 226, 1, /* bad map */
753 228, 1, /* bad map */
758 233, 1, /* bad map */
759 234, 1, /* bad map */
765 240, 1, /* bad map */
766 241, 1, /* bad map */
768 243, 1, /* bad map */
773 1001, 1, /* bad map */
774 1002, 1, /* bad map */
775 1003, 1, /* bad map */
776 1004, 1, /* bad map */
777 1005, 1, /* bad map */
778 1006, 1, /* bad map */
810 int yaz_diag_bib1_to_srw (int code)
812 const int *p = srw_bib1_map;
822 int yaz_diag_srw_to_bib1(int code)
824 const int *p = srw_bib1_map;