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