1 /* $Id: filter_sru_to_z3950.cpp,v 1.7 2006-09-15 14:18:25 marc Exp $
2 Copyright (c) 2005-2006, Index Data.
4 See the LICENSE file for details
11 #include "gduutil.hpp"
12 #include "filter_sru_to_z3950.hpp"
16 #include <yaz/pquery.h>
18 #include <boost/thread/mutex.hpp>
25 namespace mp = metaproxy_1;
26 namespace yf = mp::filter;
32 std::string to_string(const T& t)
41 std::string http_header_value(const Z_HTTP_Header* header,
42 const std::string name)
44 while (header && header->name
45 && std::string(header->name) != name)
46 header = header->next;
48 if (header && header->name && std::string(header->name) == name
50 return std::string(header->value);
59 namespace metaproxy_1 {
61 class SRUtoZ3950::Rep {
62 //friend class SRUtoZ3950;
64 void configure(const xmlNode *xmlnode);
65 void process(metaproxy_1::Package &package) const;
67 std::string sru_protocol(const Z_HTTP_Request &http_req) const;
68 std::string debug_http(const Z_HTTP_Request &http_req) const;
69 void http_response(mp::Package &package,
70 const std::string &content,
71 int http_code = 200) const;
72 bool build_sru_debug_package(mp::Package &package) const;
73 bool z3950_build_query(mp::odr &odr_en, Z_Query *z_query,
74 const std::string &query,
75 int query_type) const;
76 bool z3950_init_request(mp::Package &package,
78 &database = "Default") const;
79 bool z3950_close_request(mp::Package &package) const;
80 bool z3950_search_request(mp::Package &package,
82 const std::string &database,
83 const std::string &query,
84 int query_type) const;
85 bool z3950_present_request(mp::Package &package) const;
86 bool z3950_scan_request(mp::Package &package) const;
91 yf::SRUtoZ3950::SRUtoZ3950() : m_p(new Rep)
95 yf::SRUtoZ3950::~SRUtoZ3950()
96 { // must have a destructor because of boost::scoped_ptr
99 void yf::SRUtoZ3950::configure(const xmlNode *xmlnode)
101 m_p->configure(xmlnode);
104 void yf::SRUtoZ3950::process(mp::Package &package) const
106 m_p->process(package);
109 void yf::SRUtoZ3950::Rep::configure(const xmlNode *xmlnode)
113 void yf::SRUtoZ3950::Rep::process(mp::Package &package) const
115 Z_GDU *zgdu_req = package.request().get();
117 // ignoring all non HTTP_Request packages
118 if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request)){
123 // only working on HTTP_Request packages now
126 // TODO: Z3950 response parsing and translation to SRU package
127 Z_HTTP_Request* http_req = zgdu_req->u.HTTP_Request;
129 unsigned int search_hits = 0;
131 if (z3950_init_request(package))
133 ok = z3950_search_request(package, search_hits, "Default",
134 "dc.title=bacillus", Z_SRW_query_type_cql);
135 if (ok && search_hits)
136 ok = z3950_present_request(package);
137 //z3950_scan_request(package,"Default",
138 // "dc:title=bacillus", Z_SRW_query_type_cql);
139 z3950_close_request(package);
142 build_sru_debug_package(package);
152 // SRU request package checking
155 //Z_GDU *zgdu_res = 0;
156 Z_SRW_PDU *sru_pdu_req = 0;
157 //Z_SRW_PDU *sru_pdu_res = 0;
158 //Z_APDU *z3950_apdu_req = 0;
159 //Z_APDU *z3950_apdu_res = 0;
162 Z_SOAP *soap_req = 0;
164 Z_SRW_diagnostic *diag = 0;
166 //mp::odr odr_de(ODR_DECODE);
168 if (0 == yaz_sru_decode(http_req, &sru_pdu_req, &soap_req,
169 odr(ODR_DECODE), &charset, &diag, &num_diags))
171 std::cout << "SRU GET/POST \n";
173 else if (0 == yaz_srw_decode(http_req, &sru_pdu_req, &soap_req,
174 odr(ODR_DECODE), &charset))
176 std::cout << "SRU SOAP \n";
180 std::cout << "SRU DECODING ERROR - SHOULD NEVER HAPPEN\n";
181 package.session().close();
187 std::cout << "SRU DIAGNOSTICS " << num_diags << "\n";
188 // TODO: make nice diagnostic return package
189 //Z_SRW_PDU *srw_pdu_res =
190 // yaz_srw_get(odr(ODR_ENCODE),
191 // Z_SRW_searchRetrieve_response);
192 // Z_SRW_searchRetrieveResponse *srw_res = srw_pdu_res->u.response;
194 // srw_res->diagnostics = diagnostic;
195 // srw_res->num_diagnostics = num_diagnostic;
196 // send_srw_response(srw_pdu_res);
199 // package.session().close();
204 // SRU request package translation to Z3950 package
207 if (sru_pdu_req && sru_pdu_req->which == Z_SRW_searchRetrieve_request)
209 //Z_SRW_searchRetrieveRequest *srw_req = sru_pdu_req->u.request;
211 // recordXPath unsupported.
212 //if (srw_req->recordXPath)
213 // yaz_add_srw_diagnostic(odr_decode(),
214 // &diag, &num_diags, 72, 0);
216 // if (srw_req->sort_type != Z_SRW_sort_type_none)
217 // yaz_add_srw_diagnostic(odr_decode(),
218 // &diag, &num_diags, 80, 0);
222 std::cout << "SRU OPERATION NOT SUPPORTED \n";
223 // TODO: make nice diagnostic return package
224 // package.session().close();
230 bool yf::SRUtoZ3950::Rep::build_sru_debug_package(mp::Package &package) const
232 Z_GDU *zgdu_req = package.request().get();
233 if (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
235 Z_HTTP_Request* http_req = zgdu_req->u.HTTP_Request;
236 std::string content = debug_http(*http_req);
238 http_response(package, content, http_code);
246 yf::SRUtoZ3950::Rep::z3950_init_request(mp::Package &package,
247 const std::string &database) const
249 // prepare Z3950 package
251 //Package z3950_package(s, package.origin());
252 Package z3950_package(package.session(), package.origin());
253 z3950_package.copy_filter(package);
255 // set initRequest APDU
256 mp::odr odr_en(ODR_ENCODE);
257 Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_initRequest);
258 Z_InitRequest *init_req = apdu->u.initRequest;
259 //TODO: add user name in apdu
260 //TODO: add user passwd in apdu
261 //init_req->idAuthentication = org_init->idAuthentication;
262 //init_req->implementationId = "IDxyz";
263 //init_req->implementationName = "NAMExyz";
264 //init_req->implementationVersion = "VERSIONxyz";
266 ODR_MASK_SET(init_req->options, Z_Options_search);
267 ODR_MASK_SET(init_req->options, Z_Options_present);
268 ODR_MASK_SET(init_req->options, Z_Options_namedResultSets);
269 ODR_MASK_SET(init_req->options, Z_Options_scan);
271 ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_1);
272 ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_2);
273 ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_3);
275 z3950_package.request() = apdu;
277 // send Z3950 package
278 // std::cout << "z3950_init_request " << *apdu <<"\n";
279 z3950_package.move();
281 // dead Z3950 backend detection
282 if (z3950_package.session().is_closed()){
283 package.session().close();
287 // check successful initResponse
288 Z_GDU *z3950_gdu = z3950_package.response().get();
290 if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950
291 && z3950_gdu->u.z3950->which == Z_APDU_initResponse)
298 yf::SRUtoZ3950::Rep::z3950_close_request(mp::Package &package) const
300 // prepare Z3950 package
301 Package z3950_package(package.session(), package.origin());
302 z3950_package.copy_filter(package);
303 z3950_package.session().close();
306 //mp::odr odr_en(ODR_ENCODE);
307 //Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_close);
308 //z3950_package.request() = apdu;
310 z3950_package.move();
312 // check successful close response
313 //Z_GDU *z3950_gdu = z3950_package.response().get();
314 //if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950
315 // && z3950_gdu->u.z3950->which == Z_APDU_close)
318 if (z3950_package.session().is_closed()){
319 //package.session().close();
326 yf::SRUtoZ3950::Rep::z3950_search_request(mp::Package &package,
328 const std::string &database,
329 const std::string &query,
330 int query_type) const
332 Package z3950_package(package.session(), package.origin());
333 z3950_package.copy_filter(package);
334 mp::odr odr_en(ODR_ENCODE);
335 Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_searchRequest);
337 //TODO: add stuff in apdu
338 Z_SearchRequest *z_searchRequest = apdu->u.searchRequest;
339 z_searchRequest->num_databaseNames = 1;
340 z_searchRequest->databaseNames = (char**)
341 odr_malloc(odr_en, sizeof(char *));
342 z_searchRequest->databaseNames[0] = odr_strdup(odr_en, database.c_str());
344 // TODO query repackaging
345 Z_Query *z_query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query));
346 z_searchRequest->query = z_query;
349 if (!z3950_build_query(odr_en, z_query, query, query_type))
351 //send_to_srw_client_error(7, "query");
355 z3950_package.request() = apdu;
356 //std::cout << "z3950_search_request " << *apdu << "\n";
358 z3950_package.move();
359 //TODO: check success condition
360 Z_GDU *z3950_gdu = z3950_package.response().get();
361 //std::cout << "z3950_search_request " << *z3950_gdu << "\n";
363 if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950
364 && z3950_gdu->u.z3950->which == Z_APDU_searchResponse
365 && z3950_gdu->u.z3950->u.searchResponse->searchStatus)
367 hits = *(z3950_gdu->u.z3950->u.searchResponse->resultCount);
375 yf::SRUtoZ3950::Rep::z3950_present_request(mp::Package &package) const
377 Package z3950_package(package.session(), package.origin());
378 z3950_package.copy_filter(package);
379 mp::odr odr_en(ODR_ENCODE);
380 Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_presentRequest);
381 //TODO: add stuff in apdu
382 z3950_package.request() = apdu;
384 //std::cout << "z3950_present_request " << *apdu << "\n";
385 z3950_package.move();
387 //TODO: check success condition
388 Z_GDU *z3950_gdu = z3950_package.response().get();
389 if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950
390 && z3950_gdu->u.z3950->which == Z_APDU_presentResponse)
391 //&& z3950_gdu->u.z3950->u.presenthResponse->searchStatus)
393 std::cout << "z3950_present_request OK\n";
401 yf::SRUtoZ3950::Rep::z3950_scan_request(mp::Package &package) const
403 Package z3950_package(package.session(), package.origin());
404 z3950_package.copy_filter(package);
405 mp::odr odr_en(ODR_ENCODE);
406 Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_scanRequest);
407 //TODO: add stuff in apdu
408 z3950_package.request() = apdu;
410 std::cout << "z3950_scan_request " << *apdu << "\n";
411 z3950_package.move();
412 //TODO: check success condition
417 bool yf::SRUtoZ3950::Rep::z3950_build_query(mp::odr &odr_en, Z_Query *z_query,
418 const std::string &query,
419 int query_type) const
421 if (query_type == Z_SRW_query_type_cql)
423 Z_External *ext = (Z_External *)
424 odr_malloc(odr_en, sizeof(*ext));
425 ext->direct_reference =
426 odr_getoidbystr(odr_en, "1.2.840.10003.16.2");
427 ext->indirect_reference = 0;
429 ext->which = Z_External_CQL;
430 //ext->u.cql = srw_req->query.cql;
431 ext->u.cql = const_cast<char *>(query.c_str());
433 z_query->which = Z_Query_type_104;
434 z_query->u.type_104 = ext;
438 if (query_type == Z_SRW_query_type_pqf)
440 Z_RPNQuery *RPNquery;
441 YAZ_PQF_Parser pqf_parser;
443 pqf_parser = yaz_pqf_create ();
445 RPNquery = yaz_pqf_parse (pqf_parser, odr_en, query.c_str());
446 //srw_req->query.pqf);
449 // const char *pqf_msg;
451 // int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
453 // yaz_log(YLOG_LOG, "%*s^\n", ioff+4, "");
454 // yaz_log(YLOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
456 // send_to_srw_client_error(10, 0);
459 z_query->which = Z_Query_type_1;
460 z_query->u.type_1 = RPNquery;
462 yaz_pqf_destroy (pqf_parser);
470 yf::SRUtoZ3950::Rep::sru_protocol(const Z_HTTP_Request &http_req) const
472 const std::string mime_urlencoded("application/x-www-form-urlencoded");
473 const std::string mime_text_xml("text/xml");
474 const std::string mime_soap_xml("application/soap+xml");
476 const std::string http_method(http_req.method);
477 const std::string http_type
478 = http_header_value(http_req.headers, "Content-Type");
480 if (http_method == "GET")
483 if (http_method == "POST"
484 && http_type == mime_urlencoded)
487 if ( http_method == "POST"
488 && (http_type == mime_text_xml
489 || http_type == mime_soap_xml))
496 yf::SRUtoZ3950::Rep::debug_http(const Z_HTTP_Request &http_req) const
498 std::string message("<html>\n<body>\n<h1>"
499 "Metaproxy SRUtoZ3950 filter"
502 message += "<h3>HTTP Info</h3><br/>\n";
504 message += "<b>Method: </b> " + std::string(http_req.method) + "<br/>\n";
505 message += "<b>Version:</b> " + std::string(http_req.version) + "<br/>\n";
506 message += "<b>Path: </b> " + std::string(http_req.path) + "<br/>\n";
508 message += "<b>Content-Type:</b>"
509 + http_header_value(http_req.headers, "Content-Type")
511 message += "<b>Content-Length:</b>"
512 + http_header_value(http_req.headers, "Content-Length")
516 message += "<h3>Headers</h3><br/>\n";
518 Z_HTTP_Header* header = http_req.headers;
520 message += "<b>Header: </b> <i>"
521 + std::string(header->name) + ":</i> "
522 + std::string(header->value) + "<br/>\n";
523 header = header->next;
526 message += "</body>\n</html>\n";
530 void yf::SRUtoZ3950::Rep::http_response(metaproxy_1::Package &package,
531 const std::string &content,
535 Z_GDU *zgdu_req = package.request().get();
539 = odr.create_HTTP_Response(package.session(),
540 zgdu_req->u.HTTP_Request,
543 zgdu_res->u.HTTP_Response->content_len = content.size();
544 zgdu_res->u.HTTP_Response->content_buf
545 = (char*) odr_malloc(odr, zgdu_res->u.HTTP_Response->content_len);
547 strncpy(zgdu_res->u.HTTP_Response->content_buf,
548 content.c_str(), zgdu_res->u.HTTP_Response->content_len);
550 //z_HTTP_header_add(odr, &hres->headers,
551 // "Content-Type", content_type.c_str());
552 package.response() = zgdu_res;
558 static mp::filter::Base* filter_creator()
560 return new mp::filter::SRUtoZ3950;
564 struct metaproxy_1_filter_struct metaproxy_1_filter_sru_to_z3950 = {
575 * indent-tabs-mode: nil
576 * c-file-style: "stroustrup"
578 * vim: shiftwidth=4 tabstop=8 expandtab