metaproxy  1.13.0
sru_util.cpp
Go to the documentation of this file.
1 /* This file is part of Metaproxy.
2  Copyright (C) Index Data
3 
4 Metaproxy is free software; you can redistribute it and/or modify it under
5 the terms of the GNU General Public License as published by the Free
6 Software Foundation; either version 2, or (at your option) any later
7 version.
8 
9 Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #include "sru_util.hpp"
20 #include <metaproxy/util.hpp>
21 
22 #include <iostream>
23 #include <string>
24 
25 namespace mp = metaproxy_1;
26 
27 // Doxygen doesn't like mp::gdu, so we use this instead
28 namespace mp_util = metaproxy_1::util;
29 
30 const std::string xmlns_explain("http://explain.z3950.org/dtd/2.0/");
31 
32 bool mp_util::build_sru_debug_package(mp::Package &package)
33 {
34  Z_GDU *zgdu_req = package.request().get();
35  if (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
36  {
37  Z_HTTP_Request* http_req = zgdu_req->u.HTTP_Request;
38  std::string content = mp_util::http_headers_debug(*http_req);
39  int http_code = 400;
40  mp_util::http_response(package, content, http_code);
41  return true;
42  }
43  package.session().close();
44  return false;
45 }
46 
48 {
49  mp_util::SRUServerInfo sruinfo;
50 
51  // getting host and port info
52  sruinfo.host = "localhost";
53  sruinfo.port = "80";
54 
55  // overwriting host and port info if set from HTTP Host header
56  Z_GDU *zgdu_req = package.request().get();
57  if (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
58  {
59  Z_HTTP_Request* http_req = zgdu_req->u.HTTP_Request;
60  if (http_req)
61  {
62  std::string http_path = http_req->path;
63 
64  // taking out GET parameters
65  std::string::size_type ipath = http_path.rfind("?");
66  if (ipath != std::string::npos)
67  http_path.assign(http_path, 0, ipath);
68 
69  // assign to database name
70  if (http_path.size() > 1)
71  sruinfo.database.assign(http_path, 1, std::string::npos);
72 
73  std::string http_host_address
74  = mp_util::http_header_value(http_req->headers, "Host");
75 
76  std::string::size_type iaddress = http_host_address.rfind(":");
77  if (iaddress != std::string::npos)
78  {
79  sruinfo.host.assign(http_host_address, 0, iaddress);
80  sruinfo.port.assign(http_host_address, iaddress + 1,
81  std::string::npos);
82  }
83  }
84  }
85 
86  //std::cout << "sruinfo.database " << sruinfo.database << "\n";
87  //std::cout << "sruinfo.host " << sruinfo.host << "\n";
88  //std::cout << "sruinfo.port " << sruinfo.port << "\n";
89 
90  return sruinfo;
91 }
92 
93 
95  metaproxy_1::odr &odr_en,
96  Z_SRW_PDU *sru_pdu_res,
97  SRUServerInfo sruinfo,
98  const xmlNode *explain,
99  Z_SRW_explainRequest const *er_req)
100 {
101 
102  // building SRU explain record
103  std::string explain_xml;
104 
105  if (explain == 0)
106  {
107  explain_xml
108  = mp_util::to_string(
109  "<explain xmlns=\"" + xmlns_explain + "\">\n"
110  " <serverInfo protocol='SRU'>\n"
111  " <host>")
112  + sruinfo.host
113  + mp_util::to_string("</host>\n"
114  " <port>")
115  + sruinfo.port
116  + mp_util::to_string("</port>\n"
117  " <database>")
118  + sruinfo.database
119  + mp_util::to_string("</database>\n"
120  " </serverInfo>\n"
121  "</explain>\n");
122  }
123  else
124  {
125  xmlNode *tmp = xmlCopyNode((xmlNode*) explain, 1);
126  xmlBufferPtr buf = xmlBufferCreate();
127  xmlNodeDump(buf, tmp->doc, tmp, 2, 1);
128  xmlFreeNode(tmp);
129 
130  explain_xml.assign((const char*)buf->content, 0, buf->use);
131  xmlBufferFree(buf);
132  }
133 
134 
135  // z3950'fy recordPacking
136  int record_packing = Z_SRW_recordPacking_XML;
137  if (er_req && er_req->recordPacking && 's' == *(er_req->recordPacking))
138  record_packing = Z_SRW_recordPacking_string;
139 
140  // preparing explain record insert
141  Z_SRW_explainResponse *sru_res = sru_pdu_res->u.explain_response;
142 
143  // inserting one and only explain record
144 
145  sru_res->record.recordPosition = odr_intdup(odr_en, 1);
146  sru_res->record.recordPacking = record_packing;
147  sru_res->record.recordSchema = (char *)xmlns_explain.c_str();
148  sru_res->record.recordData_len = 1 + explain_xml.size();
149  sru_res->record.recordData_buf
150  = odr_strdupn(odr_en, (const char *)explain_xml.c_str(),
151  1 + explain_xml.size());
152 
153  return true;
154 }
155 
156 
157 bool mp_util::build_sru_response(mp::Package &package,
158  mp::odr &odr_en,
159  Z_SOAP *soap,
160  const Z_SRW_PDU *sru_pdu_res,
161  char *charset,
162  const char *stylesheet)
163 {
164 
165  // SRU request package translation to Z3950 package
166  //if (sru_pdu_res)
167  // std::cout << *(const_cast<Z_SRW_PDU *>(sru_pdu_res)) << "\n";
168  //else
169  // std::cout << "SRU empty\n";
170 
171 
172  Z_GDU *zgdu_req = package.request().get();
173  if (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
174  {
175  Z_GDU *zgdu_res //= z_get_HTTP_Response(odr_en, 200);
176  = odr_en.create_HTTP_Response(package.session(),
177  zgdu_req->u.HTTP_Request,
178  200);
179 
180  // adding HTTP response code and headers
181  Z_HTTP_Response * http_res = zgdu_res->u.HTTP_Response;
182  //http_res->code = http_code;
183 
184  std::string ctype("text/xml");
185  if (charset)
186  {
187  ctype += "; charset=";
188  ctype += charset;
189  }
190 
191  z_HTTP_header_add(odr_en,
192  &http_res->headers, "Content-Type", ctype.c_str());
193 
194  // packaging Z_SOAP into HTML response
195  static Z_SOAP_Handler soap_handlers[4] = {
196  {(char *)YAZ_XMLNS_SRU_v1_1, 0, (Z_SOAP_fun) yaz_srw_codec},
197  {(char *)YAZ_XMLNS_SRU_v1_0, 0, (Z_SOAP_fun) yaz_srw_codec},
198  {(char *)YAZ_XMLNS_UPDATE_v0_9, 0, (Z_SOAP_fun) yaz_ucp_codec},
199  {0, 0, 0}
200  };
201 
202 
203  // empty stylesheet means NO stylesheet
204  if (stylesheet && *stylesheet == '\0')
205  stylesheet = 0;
206 
207  // encoding SRU package
208 
209  soap->u.generic->p = (void*) sru_pdu_res;
210  //int ret =
211  z_soap_codec_enc_xsl(odr_en, &soap,
212  &http_res->content_buf, &http_res->content_len,
213  soap_handlers, charset, stylesheet);
214 
215 
216  package.response() = zgdu_res;
217  return true;
218  }
219  package.session().close();
220  return false;
221 }
222 
223 
224 
225 Z_SRW_PDU * mp_util::decode_sru_request(mp::Package &package,
226  mp::odr &odr_de,
227  mp::odr &odr_en,
228  Z_SRW_diagnostic **diagnostic,
229  int *num_diagnostic,
230  Z_SOAP **soap,
231  char *charset)
232 {
233  Z_GDU *zgdu_req = package.request().get();
234  Z_SRW_PDU *sru_pdu_req = 0;
235 
236  //assert((zgdu_req->which == Z_GDU_HTTP_Request));
237 
238  //ignoring all non HTTP_Request packages
239  if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request))
240  {
241  return 0;
242  }
243 
244  Z_HTTP_Request* http_req = zgdu_req->u.HTTP_Request;
245  if (! http_req)
246  return 0;
247 
248  // checking if we got a SRU GET/POST/SOAP HTTP package
249  // closing connection if we did not ...
250  if (0 == yaz_sru_decode(http_req, &sru_pdu_req, soap,
251  odr_de, &charset,
252  diagnostic, num_diagnostic))
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)
276  {
277  yaz_add_srw_diagnostic(odr_en,
278  &(sru_pdu_res->u.response->diagnostics),
279  &(sru_pdu_res->u.response->num_diagnostics),
280  YAZ_SRW_MANDATORY_PARAMETER_NOT_SUPPLIED,
281  "query");
282  yaz_add_srw_diagnostic(odr_en,
283  &(sru_pdu_res->u.response->diagnostics),
284  &(sru_pdu_res->u.response->num_diagnostics),
285  YAZ_SRW_QUERY_SYNTAX_ERROR,
286  "CQL query is empty");
287  return false;
288  }
289  return true;
290 }
291 
292 
293 Z_ElementSetNames *
294 mp_util::build_esn_from_schema(mp::odr &odr_en, const char *schema)
295 {
296  if (!schema)
297  return 0;
298 
299  Z_ElementSetNames *esn
300  = (Z_ElementSetNames *) odr_malloc(odr_en, sizeof(Z_ElementSetNames));
301  esn->which = Z_ElementSetNames_generic;
302  esn->u.generic = odr_strdup(odr_en, schema);
303  return esn;
304 }
305 
306 
307 std::ostream& std::operator<<(std::ostream& os, Z_SRW_PDU& srw_pdu)
308 {
309  os << "SRU";
310 
311  switch (srw_pdu.which)
312  {
313  case Z_SRW_searchRetrieve_request:
314  os << " " << "searchRetrieveRequest";
315  {
316  Z_SRW_searchRetrieveRequest *sr = srw_pdu.u.request;
317  if (sr)
318  {
319  if (sr->database)
320  os << " " << (sr->database);
321  else
322  os << " -";
323  if (sr->startRecord)
324  os << " " << *(sr->startRecord);
325  else
326  os << " -";
327  if (sr->maximumRecords)
328  os << " " << *(sr->maximumRecords);
329  else
330  os << " -";
331  if (sr->recordPacking)
332  os << " " << (sr->recordPacking);
333  else
334  os << " -";
335 
336  if (sr->recordSchema)
337  os << " " << (sr->recordSchema);
338  else
339  os << " -";
340  os << " " << (sr->queryType ? sr->queryType : "cql")
341  << " " << sr->query;
342  }
343  }
344  break;
345  case Z_SRW_searchRetrieve_response:
346  os << " " << "searchRetrieveResponse";
347  {
348  Z_SRW_searchRetrieveResponse *sr = srw_pdu.u.response;
349  if (sr)
350  {
351  if (! (sr->num_diagnostics))
352  {
353  os << " OK";
354  if (sr->numberOfRecords)
355  os << " " << *(sr->numberOfRecords);
356  else
357  os << " -";
358  //if (sr->num_records)
359  os << " " << (sr->num_records);
360  //else
361  //os << " -";
362  if (sr->nextRecordPosition)
363  os << " " << *(sr->nextRecordPosition);
364  else
365  os << " -";
366  }
367  else
368  {
369  os << " DIAG";
370  if (sr->diagnostics && sr->diagnostics->uri)
371  os << " " << (sr->diagnostics->uri);
372  else
373  os << " -";
374  if (sr->diagnostics && sr->diagnostics->message)
375  os << " " << (sr->diagnostics->message);
376  else
377  os << " -";
378  if (sr->diagnostics && sr->diagnostics->details)
379  os << " " << (sr->diagnostics->details);
380  else
381  os << " -";
382  }
383 
384 
385  }
386  }
387  break;
388  case Z_SRW_explain_request:
389  os << " " << "explainRequest";
390  break;
391  case Z_SRW_explain_response:
392  os << " " << "explainResponse";
393  break;
394  case Z_SRW_scan_request:
395  os << " " << "scanRequest";
396  break;
397  case Z_SRW_scan_response:
398  os << " " << "scanResponse";
399  break;
400  case Z_SRW_update_request:
401  os << " " << "updateRequest";
402  break;
403  case Z_SRW_update_response:
404  os << " " << "updateResponse";
405  break;
406  default:
407  os << " " << "UNKNOWN";
408  }
409 
410  return os;
411 }
412 
413 /*
414  * Local variables:
415  * c-basic-offset: 4
416  * c-file-style: "Stroustrup"
417  * indent-tabs-mode: nil
418  * End:
419  * vim: shiftwidth=4 tabstop=8 expandtab
420  */
421 
SRUServerInfo get_sru_server_info(metaproxy_1::Package &package)
std::ostream & operator<<(std::ostream &os, Z_GDU &zgdu)
Definition: gduutil.cpp:33
Z_SRW_PDU * decode_sru_request(metaproxy_1::Package &package, metaproxy_1::odr &odr_de, metaproxy_1::odr &odr_en, Z_SRW_diagnostic **diagnostic, int *num_diagnostic, Z_SOAP **soap, char *charset)
const std::string xmlns_explain("http://explain.z3950.org/dtd/2.0/")
bool build_sru_debug_package(metaproxy_1::Package &package)
bool build_sru_response(metaproxy_1::Package &package, metaproxy_1::odr &odr_en, Z_SOAP *soap, const Z_SRW_PDU *sru_pdu_res, char *charset, const char *stylesheet)
bool build_sru_explain(metaproxy_1::Package &package, metaproxy_1::odr &odr_en, Z_SRW_PDU *sru_pdu_res, SRUServerInfo sruinfo, const xmlNode *explain=0, Z_SRW_explainRequest const *er_req=0)
Definition: sru_util.cpp:94
bool check_sru_query_exists(metaproxy_1::Package &package, metaproxy_1::odr &odr_en, Z_SRW_PDU *sru_pdu_res, Z_SRW_searchRetrieveRequest const *sr_req)
Z_ElementSetNames * build_esn_from_schema(metaproxy_1::odr &odr_en, const char *schema)