more work on zeerex explain filter, to be continued
[metaproxy-moved-to-github.git] / src / sru_util.cpp
1 /* $Id: sru_util.cpp,v 1.4 2007-01-05 12:26:50 marc Exp $
2    Copyright (c) 2005-2006, Index Data.
3
4    See the LICENSE file for details
5 */
6
7 #include "sru_util.hpp"
8 #include "util.hpp"
9
10 //#include <yaz/wrbuf.h>
11 //#include <yaz/querytowrbuf.h>
12
13 #include <iostream>
14 #include <string>
15
16 namespace mp = metaproxy_1;
17
18 // Doxygen doesn't like mp::gdu, so we use this instead
19 namespace mp_util = metaproxy_1::util;
20
21
22
23 bool mp_util::build_sru_debug_package(mp::Package &package)
24 {
25     Z_GDU *zgdu_req = package.request().get();
26     if  (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
27     {    
28         Z_HTTP_Request* http_req =  zgdu_req->u.HTTP_Request;
29         std::string content = mp_util::http_headers_debug(*http_req);
30         int http_code = 400;    
31         mp_util::http_response(package, content, http_code);
32         return true;
33     }
34     package.session().close();
35     return false;
36 }
37
38 void mp_util::get_sru_server_info(mp::Package &package, 
39                                    Z_SRW_explainRequest 
40                                    const *er_req) 
41 {
42
43     SRUServerInfo sruinfo;
44
45     // getting database info
46     std::string database("Default");
47     if (er_req && er_req->database)
48         database = er_req->database;
49
50     // getting host and port info
51     std::string host = package.origin().listen_host();
52     std::string port = mp_util::to_string(package.origin().listen_port());
53
54     // overwriting host and port info if set from HTTP Host header
55     Z_GDU *zgdu_req = package.request().get();
56     if  (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
57     {
58         Z_HTTP_Request* http_req =  zgdu_req->u.HTTP_Request;
59         if (http_req)
60         {
61             std::string http_host_address
62                 = mp_util::http_header_value(http_req->headers, "Host");
63
64             std::string::size_type i = http_host_address.rfind(":");
65             if (i != std::string::npos)
66             {
67                 host.assign(http_host_address, 0, i);
68                 port.assign(http_host_address, i + 1, std::string::npos);
69             }
70         }
71     }
72 }
73
74
75 bool mp_util::build_simple_explain(mp::Package &package, 
76                                    mp::odr &odr_en,
77                                    Z_SRW_PDU *sru_pdu_res,
78                                    Z_SRW_explainRequest 
79                                    const *er_req) 
80 {
81     // z3950'fy recordPacking
82     int record_packing = Z_SRW_recordPacking_XML;
83     if (er_req && er_req->recordPacking && 's' == *(er_req->recordPacking))
84         record_packing = Z_SRW_recordPacking_string;
85
86     // getting database info
87     std::string database("Default");
88     if (er_req && er_req->database)
89         database = er_req->database;
90
91     // getting host and port info
92     std::string host = package.origin().listen_host();
93     std::string port = mp_util::to_string(package.origin().listen_port());
94
95     // overwriting host and port info if set from HTTP Host header
96     Z_GDU *zgdu_req = package.request().get();
97     if  (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
98     {
99         Z_HTTP_Request* http_req =  zgdu_req->u.HTTP_Request;
100         if (http_req)
101         {
102             std::string http_host_address
103                 = mp_util::http_header_value(http_req->headers, "Host");
104
105             std::string::size_type i = http_host_address.rfind(":");
106             if (i != std::string::npos)
107             {
108                 host.assign(http_host_address, 0, i);
109                 port.assign(http_host_address, i + 1, std::string::npos);
110             }
111         }
112     }
113
114     // building SRU explain record
115     std::string explain_xml 
116         = mp_util::to_string(
117             "<explain  xmlns=\"http://explain.z3950.org/dtd/2.0/\">\n"
118             "  <serverInfo protocol='SRU'>\n"
119             "    <host>")
120         + host
121         + mp_util::to_string("</host>\n"
122             "    <port>")
123         + port
124         + mp_util::to_string("</port>\n"
125             "    <database>")
126         + database
127         + mp_util::to_string("</database>\n"
128             "  </serverInfo>\n"
129             "</explain>\n");
130     
131     
132     // preparing explain record insert
133     Z_SRW_explainResponse *sru_res = sru_pdu_res->u.explain_response;
134     
135     // inserting one and only explain record
136     
137     sru_res->record.recordPosition = odr_intdup(odr_en, 1);
138     sru_res->record.recordPacking = record_packing;
139     sru_res->record.recordSchema = "http://explain.z3950.org/dtd/2.0/";
140     sru_res->record.recordData_len = 1 + explain_xml.size();
141     sru_res->record.recordData_buf
142         = odr_strdupn(odr_en, (const char *)explain_xml.c_str(), 
143                       1 + explain_xml.size());
144
145     return true;
146 };
147
148
149 bool mp_util::build_sru_response(mp::Package &package, 
150                                              mp::odr &odr_en,
151                                              Z_SOAP *soap,
152                                              const Z_SRW_PDU *sru_pdu_res,
153                                              char *charset,
154                                              const char *stylesheet) 
155 {
156
157     // SRU request package translation to Z3950 package
158     //if (sru_pdu_res)
159     //    std::cout << *(const_cast<Z_SRW_PDU *>(sru_pdu_res)) << "\n";
160     //else
161     //    std::cout << "SRU empty\n";
162
163     
164     Z_GDU *zgdu_req = package.request().get();
165     if  (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
166     {    
167         Z_GDU *zgdu_res //= z_get_HTTP_Response(odr_en, 200);
168             = odr_en.create_HTTP_Response(package.session(), 
169                                           zgdu_req->u.HTTP_Request, 
170                                           200);
171
172         // adding HTTP response code and headers
173         Z_HTTP_Response * http_res = zgdu_res->u.HTTP_Response;
174         //http_res->code = http_code;
175         
176         std::string ctype("text/xml");
177         if (charset){
178             ctype += "; charset=";
179             ctype += charset;
180         }
181
182         z_HTTP_header_add(odr_en, 
183                           &http_res->headers, "Content-Type", ctype.c_str());
184
185          // packaging Z_SOAP into HTML response
186          static Z_SOAP_Handler soap_handlers[4] = {
187               {"http://www.loc.gov/zing/srw/", 0,
188                (Z_SOAP_fun) yaz_srw_codec},
189               {"http://www.loc.gov/zing/srw/v1.0/", 0,
190                (Z_SOAP_fun) yaz_srw_codec},
191               {"http://www.loc.gov/zing/srw/update/", 0,
192                (Z_SOAP_fun) yaz_ucp_codec},
193               {0, 0, 0}
194           };
195
196
197          // empty stylesheet means NO stylesheet
198          if (stylesheet && *stylesheet == '\0')
199              stylesheet = 0;
200          
201          // encoding SRU package
202          
203          soap->u.generic->p  = (void*) sru_pdu_res;         
204          //int ret = 
205          z_soap_codec_enc_xsl(odr_en, &soap, 
206                               &http_res->content_buf, &http_res->content_len,
207                               soap_handlers, charset, stylesheet);
208          
209
210          package.response() = zgdu_res;
211          return true;
212     }
213     package.session().close();
214     return false;
215 }
216
217
218
219  Z_SRW_PDU * mp_util::decode_sru_request(mp::Package &package,
220                                                      mp::odr &odr_de,
221                                                      mp::odr &odr_en,
222                                                      Z_SRW_PDU *sru_pdu_res,
223                                                      Z_SOAP *&soap,
224                                                      char *charset,
225                                                      char *stylesheet) 
226 {
227     Z_GDU *zgdu_req = package.request().get();
228     Z_SRW_PDU *sru_pdu_req = 0;
229
230     //assert((zgdu_req->which == Z_GDU_HTTP_Request));
231     
232     //ignoring all non HTTP_Request packages
233     if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request)){
234         return 0;
235     }
236     
237     Z_HTTP_Request* http_req =  zgdu_req->u.HTTP_Request;
238     if (! http_req)
239         return 0;
240
241     // checking if we got a SRU GET/POST/SOAP HTTP package
242     // closing connection if we did not ...
243     if (0 == yaz_sru_decode(http_req, &sru_pdu_req, &soap, 
244                             odr_de, &charset, 
245                             &(sru_pdu_res->u.response->diagnostics), 
246                             &(sru_pdu_res->u.response->num_diagnostics)))
247     {
248         if (sru_pdu_res->u.response->num_diagnostics)
249         {
250             //sru_pdu_res = sru_pdu_res_exp;
251             package.session().close();
252             return 0;
253         }
254         return sru_pdu_req;
255     }
256     else if (0 == yaz_srw_decode(http_req, &sru_pdu_req, &soap, 
257                                  odr_de, &charset))
258         return sru_pdu_req;
259     else 
260     {
261         //sru_pdu_res = sru_pdu_res_exp;
262         package.session().close();
263         return 0;
264     }
265     return 0;
266 }
267
268
269 bool 
270 mp_util::check_sru_query_exists(mp::Package &package, 
271                                 mp::odr &odr_en,
272                                 Z_SRW_PDU *sru_pdu_res, 
273                                 Z_SRW_searchRetrieveRequest const *sr_req)
274 {
275     if( (sr_req->query_type == Z_SRW_query_type_cql && !sr_req->query.cql) )
276     {
277         yaz_add_srw_diagnostic(odr_en,
278                                &(sru_pdu_res->u.response->diagnostics), 
279                                &(sru_pdu_res->u.response->num_diagnostics), 
280                                7, "query");
281         yaz_add_srw_diagnostic(odr_en,
282                                &(sru_pdu_res->u.response->diagnostics), 
283                                &(sru_pdu_res->u.response->num_diagnostics), 
284                                10, "CQL query is empty");
285         return false;
286     }
287     if( (sr_req->query_type == Z_SRW_query_type_xcql && !sr_req->query.xcql) )
288     {
289          yaz_add_srw_diagnostic(odr_en,
290                                &(sru_pdu_res->u.response->diagnostics), 
291                                &(sru_pdu_res->u.response->num_diagnostics), 
292                                10, "XCQL query is empty");
293          return false;
294    }
295     if( (sr_req->query_type == Z_SRW_query_type_pqf && !sr_req->query.pqf) )
296     {
297         yaz_add_srw_diagnostic(odr_en,
298                                &(sru_pdu_res->u.response->diagnostics), 
299                                &(sru_pdu_res->u.response->num_diagnostics), 
300                                10, "PQF query is empty");
301         return false;
302     }
303     return true;
304 };
305
306
307
308
309 Z_ElementSetNames * 
310 mp_util::build_esn_from_schema(mp::odr &odr_en, 
311                                const char *schema)
312 {
313   if (!schema)
314         return 0;
315   
316     Z_ElementSetNames *esn 
317         = (Z_ElementSetNames *) odr_malloc(odr_en, sizeof(Z_ElementSetNames));
318     esn->which = Z_ElementSetNames_generic;
319     esn->u.generic = odr_strdup(odr_en, schema);
320     return esn; 
321 }
322
323
324 std::ostream& std::operator<<(std::ostream& os, Z_SRW_PDU& srw_pdu) 
325 {
326     os << "SRU";
327     
328     switch(srw_pdu.which) {
329     case  Z_SRW_searchRetrieve_request:
330         os << " " << "searchRetrieveRequest";
331         {
332             Z_SRW_searchRetrieveRequest *sr = srw_pdu.u.request;
333             if (sr)
334             {
335                 if (sr->database)
336                     os << " " << (sr->database);
337                 else
338                     os << " -";
339                 if (sr->startRecord)
340                     os << " " << *(sr->startRecord);
341                 else
342                     os << " -";
343                 if (sr->maximumRecords)
344                     os << " " << *(sr->maximumRecords);
345                 else
346                     os << " -";
347                 if (sr->recordPacking)
348                     os << " " << (sr->recordPacking);
349                 else
350                     os << " -";
351
352                 if (sr->recordSchema)
353                     os << " " << (sr->recordSchema);
354                 else
355                     os << " -";
356                 
357                 switch (sr->query_type){
358                 case Z_SRW_query_type_cql:
359                     os << " CQL";
360                     if (sr->query.cql)
361                         os << " " << sr->query.cql;
362                     break;
363                 case Z_SRW_query_type_xcql:
364                     os << " XCQL";
365                     break;
366                 case Z_SRW_query_type_pqf:
367                     os << " PQF";
368                     if (sr->query.pqf)
369                         os << " " << sr->query.pqf;
370                     break;
371                 }
372             }
373         }
374         break;
375     case  Z_SRW_searchRetrieve_response:
376         os << " " << "searchRetrieveResponse";
377         {
378             Z_SRW_searchRetrieveResponse *sr = srw_pdu.u.response;
379             if (sr)
380             {
381                 if (! (sr->num_diagnostics))
382                 {
383                     os << " OK";
384                     if (sr->numberOfRecords)
385                         os << " " << *(sr->numberOfRecords);
386                     else
387                         os << " -";
388                     //if (sr->num_records)
389                     os << " " << (sr->num_records);
390                     //else
391                     //os << " -";
392                     if (sr->nextRecordPosition)
393                         os << " " << *(sr->nextRecordPosition);
394                     else
395                         os << " -";
396                 } 
397                 else
398                 {
399                     os << " DIAG";
400                     if (sr->diagnostics && sr->diagnostics->uri)
401                         os << " " << (sr->diagnostics->uri);
402                     else
403                         os << " -";
404                     if (sr->diagnostics && sr->diagnostics->message)
405                         os << " " << (sr->diagnostics->message);
406                     else
407                         os << " -";
408                     if (sr->diagnostics && sr->diagnostics->details)
409                         os << " " << (sr->diagnostics->details);
410                     else
411                         os << " -";
412                 }
413                 
414                     
415             }
416         }
417         break;
418     case  Z_SRW_explain_request:
419         os << " " << "explainRequest";
420         break;
421     case  Z_SRW_explain_response:
422         os << " " << "explainResponse";
423         break;
424     case  Z_SRW_scan_request:
425         os << " " << "scanRequest";
426         break;
427     case  Z_SRW_scan_response:
428         os << " " << "scanResponse";
429         break;
430     case  Z_SRW_update_request:
431         os << " " << "updateRequest";
432         break;
433     case  Z_SRW_update_response:
434         os << " " << "updateResponse";
435         break;
436     default: 
437         os << " " << "UNKNOWN";    
438     }
439
440     return os;    
441 }
442
443
444
445
446 // mp_util::SRU::SRU_protocol_type
447 // mp_util::SRU::protocol(const Z_HTTP_Request &http_req) const
448 // {
449 //     const std::string mime_urlencoded("application/x-www-form-urlencoded");
450 //     const std::string mime_text_xml("text/xml");
451 //     const std::string mime_soap_xml("application/soap+xml");
452
453 //     const std::string http_method(http_req.method);
454 //     const std::string http_type 
455 //         =  mp_util::http_header_value(http_req.headers, "Content-Type");
456
457 //     if (http_method == "GET")
458 //         return SRU_GET;
459
460 //     if (http_method == "POST"
461 //               && http_type  == mime_urlencoded)
462 //         return SRU_POST;
463     
464 //     if ( http_method == "POST"
465 //          && (http_type  == mime_text_xml
466 //              || http_type  == mime_soap_xml))
467 //         return SRU_SOAP;
468
469 //     return SRU_NONE;
470 // }
471
472 // std::string 
473 // mp_util::sru_protocol(const Z_HTTP_Request &http_req) const
474 // {
475 //     const std::string mime_urlencoded("application/x-www-form-urlencoded");
476 //     const std::string mime_text_xml("text/xml");
477 //     const std::string mime_soap_xml("application/soap+xml");
478
479 //     const std::string http_method(http_req.method);
480 //     const std::string http_type 
481 //         =  mp_util::http_header_value(http_req.headers, "Content-Type");
482
483 //     if (http_method == "GET")
484 //         return "SRU GET";
485
486 //     if (http_method == "POST"
487 //               && http_type  == mime_urlencoded)
488 //         return "SRU POST";
489     
490 //     if ( http_method == "POST"
491 //          && (http_type  == mime_text_xml
492 //              || http_type  == mime_soap_xml))
493 //         return "SRU SOAP";
494
495 //     return "HTTP";
496 // }
497
498 // std::string 
499 // mp_util::debug_http(const Z_HTTP_Request &http_req) const
500 // {
501 //     std::string message("<html>\n<body>\n<h1>"
502 //                         "Metaproxy SRUtoZ3950 filter"
503 //                         "</h1>\n");
504     
505 //     message += "<h3>HTTP Info</h3><br/>\n";
506 //     message += "<p>\n";
507 //     message += "<b>Method: </b> " + std::string(http_req.method) + "<br/>\n";
508 //     message += "<b>Version:</b> " + std::string(http_req.version) + "<br/>\n";
509 //     message += "<b>Path:   </b> " + std::string(http_req.path) + "<br/>\n";
510
511 //     message += "<b>Content-Type:</b>"
512 //         + mp_util::http_header_value(http_req.headers, "Content-Type")
513 //         + "<br/>\n";
514 //     message += "<b>Content-Length:</b>"
515 //         + mp_util::http_header_value(http_req.headers, "Content-Length")
516 //         + "<br/>\n";
517 //     message += "</p>\n";    
518     
519 //     message += "<h3>Headers</h3><br/>\n";
520 //     message += "<p>\n";    
521 //     Z_HTTP_Header* header = http_req.headers;
522 //     while (header){
523 //         message += "<b>Header: </b> <i>" 
524 //             + std::string(header->name) + ":</i> "
525 //             + std::string(header->value) + "<br/>\n";
526 //         header = header->next;
527 //     }
528 //     message += "</p>\n";    
529 //     message += "</body>\n</html>\n";
530 //     return message;
531 // }
532
533 // void mp_util::http_response(metaproxy_1::Package &package, 
534 //                                         const std::string &content, 
535 //                                         int http_code) const
536 // {
537
538 //     Z_GDU *zgdu_req = package.request().get(); 
539 //     Z_GDU *zgdu_res = 0; 
540 //     mp::odr odr;
541 //     zgdu_res 
542 //        = odr.create_HTTP_Response(package.session(), 
543 //                                   zgdu_req->u.HTTP_Request, 
544 //                                   http_code);
545         
546 //     zgdu_res->u.HTTP_Response->content_len = content.size();
547 //     zgdu_res->u.HTTP_Response->content_buf 
548 //         = (char*) odr_malloc(odr, zgdu_res->u.HTTP_Response->content_len);
549     
550 //     strncpy(zgdu_res->u.HTTP_Response->content_buf, 
551 //             content.c_str(),  zgdu_res->u.HTTP_Response->content_len);
552     
553 //     //z_HTTP_header_add(odr, &hres->headers,
554 //     //                  "Content-Type", content_type.c_str());
555 //     package.response() = zgdu_res;
556 // }
557
558 /*
559  * Local variables:
560  * c-basic-offset: 4
561  * indent-tabs-mode: nil
562  * c-file-style: "stroustrup"
563  * End:
564  * vim: shiftwidth=4 tabstop=8 expandtab
565  */