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