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