Tweak error mapping
[yaz-moved-to-github.git] / src / srwutil.c
1 /*
2  * Copyright (c) 2002-2003, Index Data.
3  * See the file LICENSE for details.
4  *
5  * $Id: srwutil.c,v 1.5 2004-01-06 11:20:15 adam Exp $
6  */
7
8 #include <yaz/srw.h>
9 #include <yaz/yaz-iconv.h>
10
11 static int hex_digit (int ch)
12 {
13     if (ch >= '0' && ch <= '9')
14         return ch - '0';
15     else if (ch >= 'a' && ch <= 'f')
16         return ch - 'a'+10;
17     else if (ch >= 'A' && ch <= 'F')
18         return ch - 'A'+10;
19     return 0;
20 }
21
22 char *yaz_uri_val(const char *path, const char *name, ODR o)
23 {
24     size_t nlen = strlen(name);
25     if (*path != '?')
26         return 0;
27     path++;
28     while (path && *path)
29     {
30         const char *p1 = strchr(path, '=');
31         if (!p1)
32             break;
33         if ((size_t)(p1 - path) == nlen && !memcmp(path, name, nlen))
34         {
35             size_t i = 0;
36             char *ret;
37             
38             path = p1 + 1;
39             p1 = strchr(path, '&');
40             if (!p1)
41                 p1 = strlen(path) + path;
42             ret = odr_malloc(o, p1 - path + 1);
43             while (*path && *path != '&')
44             {
45                 if (*path == '+')
46                 {
47                     ret[i++] = ' ';
48                     path++;
49                 }
50                 else if (*path == '%' && path[1] && path[2])
51                 {
52                     ret[i++] = hex_digit (path[1])*16 + hex_digit (path[2]);
53                     path = path + 3;
54                 }
55                 else
56                     ret[i++] = *path++;
57             }
58             ret[i] = '\0';
59             return ret;
60         }
61         path = strchr(p1, '&');
62         if (path)
63             path++;
64     }
65     return 0;
66 }
67
68 void yaz_uri_val_int(const char *path, const char *name, ODR o, int **intp)
69 {
70     const char *v = yaz_uri_val(path, name, o);
71     if (v)
72         *intp = odr_intdup(o, atoi(v));
73 }
74
75 int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
76                    Z_SOAP **soap_package, ODR decode, char **charset)
77 {
78     if (!strcmp(hreq->method, "POST"))
79     {
80         const char *content_type = z_HTTP_header_lookup(hreq->headers,
81                                                         "Content-Type");
82         if (content_type && !yaz_strcmp_del("text/xml", content_type, "; "))
83         {
84             char *db = "Default";
85             const char *p0 = hreq->path, *p1;
86             int ret = -1;
87             const char *charset_p = 0;
88             
89             static Z_SOAP_Handler soap_handlers[3] = {
90 #if HAVE_XML2
91                 {"http://www.loc.gov/zing/srw/", 0,
92                  (Z_SOAP_fun) yaz_srw_codec},
93                 {"http://www.loc.gov/zing/srw/v1.0/", 0,
94                  (Z_SOAP_fun) yaz_srw_codec},
95 #endif
96                 {0, 0, 0}
97             };
98             
99             if (*p0 == '/')
100                 p0++;
101             p1 = strchr(p0, '?');
102             if (!p1)
103                 p1 = p0 + strlen(p0);
104             if (p1 != p0)
105             {
106                 db = (char*) odr_malloc(decode, p1 - p0 + 1);
107                 memcpy (db, p0, p1 - p0);
108                 db[p1 - p0] = '\0';
109             }
110
111             if (charset && (charset_p = strstr(content_type, "; charset=")))
112             {
113                 int i = 0;
114                 charset_p += 10;
115                 while (i < 20 && charset_p[i] &&
116                        !strchr("; \n\r", charset_p[i]))
117                     i++;
118                 *charset = (char*) odr_malloc(decode, i+1);
119                 memcpy(*charset, charset_p, i);
120                 (*charset)[i] = '\0';
121             }
122             ret = z_soap_codec(decode, soap_package, 
123                                &hreq->content_buf, &hreq->content_len,
124                                soap_handlers);
125             if (ret == 0 && (*soap_package)->which == Z_SOAP_generic)
126             {
127                 *srw_pdu = (Z_SRW_PDU*) (*soap_package)->u.generic->p;
128                 
129                 if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request &&
130                     (*srw_pdu)->u.request->database == 0)
131                     (*srw_pdu)->u.request->database = db;
132
133                 if ((*srw_pdu)->which == Z_SRW_explain_request &&
134                     (*srw_pdu)->u.explain_request->database == 0)
135                     (*srw_pdu)->u.explain_request->database = db;
136
137                 if ((*srw_pdu)->which == Z_SRW_scan_request &&
138                     (*srw_pdu)->u.scan_request->database == 0)
139                     (*srw_pdu)->u.scan_request->database = db;
140
141                 return 0;
142             }
143             return 1;
144         }
145     }
146     return 2;
147 }
148
149 int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
150                    Z_SOAP **soap_package, ODR decode, char **charset)
151 {
152 #if HAVE_XML2
153     static Z_SOAP_Handler soap_handlers[2] = {
154         {"http://www.loc.gov/zing/srw/", 0,
155          (Z_SOAP_fun) yaz_srw_codec},
156         {0, 0, 0}
157     };
158 #endif
159     if (!strcmp(hreq->method, "GET"))
160     {
161         char *db = "Default";
162         const char *p0 = hreq->path, *p1;
163         const char *operation = 0;
164         char *query = 0;
165         char *pQuery = 0;
166         
167         if (charset)
168             *charset = 0;
169         if (*p0 == '/')
170             p0++;
171         p1 = strchr(p0, '?');
172         if (!p1)
173             p1 = p0 + strlen(p0);
174         if (p1 != p0)
175         {
176             db = (char*) odr_malloc(decode, p1 - p0 + 1);
177             memcpy (db, p0, p1 - p0);
178             db[p1 - p0] = '\0';
179         }
180 #if HAVE_XML2
181         query = yaz_uri_val(p1, "query", decode);
182         pQuery = yaz_uri_val(p1, "pQuery", decode);
183         operation = yaz_uri_val(p1, "operation", decode);
184         if (!operation)
185             operation = "explain";
186         if ((operation && !strcmp(operation, "searchRetrieve"))
187             || pQuery || query)
188         {
189             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);
190             char *sortKeys = yaz_uri_val(p1, "sortKeys", decode);
191             
192             *srw_pdu = sr;
193             if (query)
194             {
195                 sr->u.request->query_type = Z_SRW_query_type_cql;
196                 sr->u.request->query.cql = query;
197             }
198             if (pQuery)
199             {
200                 sr->u.request->query_type = Z_SRW_query_type_pqf;
201                 sr->u.request->query.pqf = pQuery;
202             }
203             if (sortKeys)
204             {
205                 sr->u.request->sort_type = Z_SRW_sort_type_sort;
206                 sr->u.request->sort.sortKeys = sortKeys;
207             }
208             sr->u.request->recordSchema = yaz_uri_val(p1, "recordSchema", decode);
209             sr->u.request->recordPacking = yaz_uri_val(p1, "recordPacking", decode);
210             if (!sr->u.request->recordPacking)
211                 sr->u.request->recordPacking = "xml";
212             yaz_uri_val_int(p1, "maximumRecords", decode, 
213                         &sr->u.request->maximumRecords);
214             yaz_uri_val_int(p1, "startRecord", decode,
215                         &sr->u.request->startRecord);
216
217             sr->u.request->database = db;
218
219             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
220             (*soap_package)->which = Z_SOAP_generic;
221             
222             (*soap_package)->u.generic =
223                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
224             
225             (*soap_package)->u.generic->p = sr;
226             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
227             (*soap_package)->u.generic->no = 0;
228             
229             (*soap_package)->ns = "SRU";
230
231             return 0;
232         }
233         else if (p1 && !strcmp(operation, "explain"))
234         {
235             Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);
236
237             *srw_pdu = sr;
238             sr->u.explain_request->recordPacking =
239                 yaz_uri_val(p1, "recordPacking", decode);
240             if (!sr->u.explain_request->recordPacking)
241                 sr->u.explain_request->recordPacking = "xml";
242             sr->u.explain_request->database = db;
243
244             (*soap_package) = odr_malloc(decode, sizeof(**soap_package));
245             (*soap_package)->which = Z_SOAP_generic;
246             
247             (*soap_package)->u.generic =
248                 odr_malloc(decode, sizeof(*(*soap_package)->u.generic));
249             
250             (*soap_package)->u.generic->p = sr;
251             (*soap_package)->u.generic->ns = soap_handlers[0].ns;
252             (*soap_package)->u.generic->no = 0;
253             
254             (*soap_package)->ns = "SRU";
255
256             return 0;
257         }
258 #endif
259         return 1;
260     }
261     return 2;
262 }
263
264 Z_SRW_PDU *yaz_srw_get(ODR o, int which)
265 {
266     Z_SRW_PDU *sr = odr_malloc(o, sizeof(*o));
267
268     sr->srw_version = odr_strdup(o, "1.1");
269     sr->which = which;
270     switch(which)
271     {
272     case Z_SRW_searchRetrieve_request:
273         sr->u.request = (Z_SRW_searchRetrieveRequest *)
274             odr_malloc(o, sizeof(*sr->u.request));
275         sr->u.request->query_type = Z_SRW_query_type_cql;
276         sr->u.request->query.cql = 0;
277         sr->u.request->sort_type = Z_SRW_sort_type_none;
278         sr->u.request->sort.none = 0;
279         sr->u.request->startRecord = 0;
280         sr->u.request->maximumRecords = 0;
281         sr->u.request->recordSchema = 0;
282         sr->u.request->recordPacking = 0;
283         sr->u.request->recordXPath = 0;
284         sr->u.request->database = 0;
285         sr->u.request->resultSetTTL = 0;
286         sr->u.request->stylesheet = 0;
287         break;
288     case Z_SRW_searchRetrieve_response:
289         sr->u.response = (Z_SRW_searchRetrieveResponse *)
290             odr_malloc(o, sizeof(*sr->u.response));
291         sr->u.response->numberOfRecords = 0;
292         sr->u.response->resultSetId = 0;
293         sr->u.response->resultSetIdleTime = 0;
294         sr->u.response->records = 0;
295         sr->u.response->num_records = 0;
296         sr->u.response->diagnostics = 0;
297         sr->u.response->num_diagnostics = 0;
298         sr->u.response->nextRecordPosition = 0;
299         break;
300     case Z_SRW_explain_request:
301         sr->u.explain_request = (Z_SRW_explainRequest *)
302             odr_malloc(o, sizeof(*sr->u.explain_request));
303         sr->u.explain_request->recordPacking = 0;
304         sr->u.explain_request->database = 0;
305         break;
306     case Z_SRW_explain_response:
307         sr->u.explain_response = (Z_SRW_explainResponse *)
308             odr_malloc(o, sizeof(*sr->u.explain_response));
309         sr->u.explain_response->record.recordData_buf = 0;
310         sr->u.explain_response->record.recordData_len = 0;
311         sr->u.explain_response->record.recordSchema = 0;
312         sr->u.explain_response->record.recordPosition = 0;
313         sr->u.explain_response->record.recordPacking =
314             Z_SRW_recordPacking_string;
315         sr->u.explain_response->diagnostics = 0;
316         sr->u.explain_response->num_diagnostics = 0;
317     }
318     return sr;
319 }
320
321
322 static struct {
323     int code;
324     const char *msg;
325 } yaz_srw_codes [] = {
326 {1, "Permanent system error"}, 
327 {2, "System temporarily unavailable"}, 
328 {3, "Authentication error"}, 
329 /* Diagnostics Relating to CQL */
330 {10, "Query syntax error"}, 
331 {11, "Unsupported query type"}, 
332 {12, "Too many characters in query"}, 
333 {13, "Unbalanced or illegal use of parentheses"}, 
334 {14, "Unbalanced or illegal use of quotes"}, 
335 {15, "Illegal or unsupported context set"}, 
336 {16, "Illegal or unsupported index"}, 
337 {17, "Illegal or unsupported combination of index and context set"}, 
338 {18, "Illegal or unsupported combination of indexes"}, 
339 {19, "Illegal or unsupported relation"}, 
340 {20, "Illegal or unsupported relation modifier"}, 
341 {21, "Illegal or unsupported combination of relation modifers"}, 
342 {22, "Illegal or unsupported combination of relation and index"}, 
343 {23, "Too many characters in term"}, 
344 {24, "Illegal combination of relation and term"}, 
345 {25, "Special characters not quoted in term"}, 
346 {26, "Non special character escaped in term"}, 
347 {27, "Empty term unsupported"}, 
348 {28, "Masking character not supported"}, 
349 {29, "Masked words too short"}, 
350 {30, "Too many masking characters in term"}, 
351 {31, "Anchoring character not supported"}, 
352 {32, "Anchoring character in illegal or unsupported position"}, 
353 {33, "Combination of proximity/adjacency and masking characters not supported"}, 
354 {34, "Combination of proximity/adjacency and anchoring characters not supported"}, 
355 {35, "Terms only exclusion (stop) words"}, 
356 {36, "Term in invalid format for index or relation"}, 
357 {37, "Illegal or unsupported boolean operator"}, 
358 {38, "Too many boolean operators in query"}, 
359 {39, "Proximity not supported"}, 
360 {40, "Illegal or unsupported proximity relation"}, 
361 {41, "Illegal or unsupported proximity distance"}, 
362 {42, "Illegal or unsupported proximity unit"}, 
363 {43, "Illegal or unsupported proximity ordering"}, 
364 {44, "Illegal or unsupported combination of proximity modifiers"}, 
365 {45, "context set name (prefix) assigned to multiple identifiers"}, 
366 /* Diagnostics Relating to Result Sets */
367 {50, "Result sets not supported"}, 
368 {51, "Result set does not exist"}, 
369 {52, "Result set temporarily unavailable"}, 
370 {53, "Result sets only supported for retrieval"}, 
371 {54, "Retrieval may only occur from an existing result set"}, 
372 {55, "Combination of result sets with search terms not supported"}, 
373 {56, "Only combination of single result set with search terms supported"}, 
374 {57, "Result set created but no records available"}, 
375 {58, "Result set created with unpredictable partial results available"}, 
376 {59, "Result set created with valid partial results available"}, 
377 /* Diagnostics Relating to Records */
378 {60, "Too many records retrieved"}, 
379 {61, "First record position out of range"}, 
380 {62, "Negative number of records requested"}, 
381 {63, "System error in retrieving records"}, 
382 {64, "Record temporarily unavailable"}, 
383 {65, "Record does not exist"}, 
384 {66, "Unknown schema for retrieval"}, 
385 {67, "Record not available in this schema"}, 
386 {68, "Not authorised to send record"}, 
387 {69, "Not authorised to send record in this schema"}, 
388 {70, "Record too large to send"}, 
389 /* Diagnostics Relating to Sorting */
390 {80, "Sort not supported"}, 
391 {81, "Unsupported sort type (sortKeys vs xSortKeys)"}, 
392 {82, "Illegal or unsupported sort sequence"}, 
393 {83, "Too many records"}, 
394 {84, "Too many sort keys"}, 
395 {85, "Duplicate sort keys"}, 
396 {86, "Incompatible record formats"}, 
397 {87, "Unsupported schema for sort"}, 
398 {88, "Unsupported tag path for sort"}, 
399 {89, "Tag path illegal or unsupported for schema"}, 
400 {90, "Illegal or unsupported direction value"}, 
401 {91, "Illegal or unsupported case value"}, 
402 {92, "Illegal or unsupported missing value action"}, 
403 /* Diagnostics Relating to Explain */
404 {100, "Explain not supported"}, 
405 {101, "Explain request type not supported (SOAP vs GET)"}, 
406 {102, "Explain record temporarily unavailable"},
407 {0, 0}
408 };
409
410 const char *yaz_diag_srw_str (int code)
411 {
412     int i;
413     for (i = 0; yaz_srw_codes[i].code; i++)
414         if (yaz_srw_codes[i].code == code)
415             return yaz_srw_codes[i].msg;
416     return 0;
417 }
418
419
420 /* bib1:srw */
421 static int srw_bib1_map[] = {
422     1, 1,
423     2, 2,
424     3, 11,
425     4, 35,
426     5, 12,
427     6, 38,
428     7, 30,
429     8, 32,
430     9, 29,
431     108, 10,  /* Malformed query : Syntax error */
432     10, 10,
433     11, 12,
434     11, 23,
435     12, 60,
436     13, 61,
437     13, 62,
438     14, 63,
439     14, 64,
440     14, 65,
441     15, 68,
442     15, 69,
443     16, 70,
444     17, 70,
445     18, 50,
446     19, 55,
447     20, 56, 
448     21, 52,
449     22, 50,
450     23, 3,
451     24, 66,
452     25, 66,
453     26, 66,
454     27, 51,
455     28, 52,
456     29, 52,
457     30, 51,
458     31, 57,
459     32, 58,
460     33, 59,
461     100, 1, /* bad map */
462     101, 3,
463     102, 3,
464     103, 3,
465     104, 3,
466     105, 3, 
467     106, 66,
468     107, 11,
469     108, 10,
470     108, 13,
471     108, 14,
472     108, 25,
473     108, 26,
474     108, 27,
475     108, 45,
476         
477     109, 1,
478     110, 37,
479     111, 1,
480     112, 58,
481     113, 10,
482     114, 16,
483     115, 16,
484     116, 16,
485     117, 19,
486     118, 22,
487     119, 32,
488     119, 31,
489     120, 28,
490     121, 15,
491     122, 32,
492     123, 22,
493     123, 17,
494     123, 18,
495     124, 24,
496     125, 36,
497     126, 36, 
498     127, 36,
499     128, 51,
500     129, 39,
501     130, 43,
502     131, 40,
503     132, 42,
504     201, 44,
505     201, 33,
506     201, 34,
507     202, 41,
508     203, 43,
509     205, 1,  /* bad map */
510     206, 1,  /* bad map */
511     207, 89,
512     208, 1,  /* bad map */
513     209, 80,
514     210, 80,
515     210, 81,
516     211, 84,
517     212, 85,
518     213, 92,
519     214, 90,
520     215, 91,
521     216, 92,
522     217, 63,
523     218, 1,  /* bad map */
524     219, 1,  /* bad map */
525     220, 1,  /* bad map */
526     221, 1,  /* bad map */
527     222, 1,  /* bad map */
528     223, 1,  /* bad map */
529     224, 1,  /* bad map */
530     225, 1,  /* bad map */
531     226, 1,  /* bad map */
532     227, 66,
533     228, 1,  /* bad map */
534     229, 36,
535     230, 83,
536     231, 89,
537     232, 1,
538     233, 1, /* bad map */
539     234, 1, /* bad map */
540     235, 2,
541     236, 3, 
542     237, 82,
543     238, 67,
544     239, 66,
545     240, 1, /* bad map */
546     241, 1, /* bad map */
547     242, 70,
548     243, 1, /* bad map */
549     244, 66,
550     245, 10,
551     246, 10,
552     247, 10,
553     1001, 1, /* bad map */
554     1002, 1, /* bad map */
555     1003, 1, /* bad map */
556     1004, 1, /* bad map */
557     1005, 1, /* bad map */
558     1006, 1, /* bad map */
559     1007, 100,
560     1008, 1, 
561     1009, 1,
562     1010, 3,
563     1011, 3,
564     1012, 3,
565     1013, 3,
566     1014, 3,
567     1015, 3,
568     1015, 3,
569     1016, 3,
570     1017, 3,
571     1018, 2,
572     1019, 2,
573     1020, 2,
574     1021, 3,
575     1022, 3,
576     1023, 3,
577     1024, 16,
578     1025, 3,
579     1026, 64,
580     1027, 1,
581     1028, 65,
582     1029, 1,
583     1040, 1,
584     /* 1041-1065 */
585     1066, 66,
586     1066, 67,
587     0
588 };
589
590 int yaz_diag_bib1_to_srw (int code)
591 {
592     const int *p = srw_bib1_map;
593     while (*p)
594     {
595         if (code == p[0])
596             return p[1];
597         p += 2;
598     }
599     return 1;
600 }
601
602 int yaz_diag_srw_to_bib1(int code)
603 {
604     const int *p = srw_bib1_map;
605     while (*p)
606     {
607         if (code == p[1])
608             return p[0];
609         p += 2;
610     }
611     return 1;
612 }
613