1 /* $Id: filter_sru_to_z3950.cpp,v 1.6 2006-09-14 23:07:35 marc Exp $
2 Copyright (c) 2005-2006, Index Data.
4 See the LICENSE file for details
11 #include "filter_sru_to_z3950.hpp"
16 #include <boost/thread/mutex.hpp>
23 namespace mp = metaproxy_1;
24 namespace yf = mp::filter;
30 std::string to_string(const T& t)
39 std::string http_header_value(const Z_HTTP_Header* header,
40 const std::string name)
42 while (header && header->name
43 && std::string(header->name) != name)
44 header = header->next;
46 if (header && header->name && std::string(header->name) == name
48 return std::string(header->value);
57 namespace metaproxy_1 {
59 class SRUtoZ3950::Rep {
60 //friend class SRUtoZ3950;
62 void configure(const xmlNode *xmlnode);
63 void process(metaproxy_1::Package &package) const;
65 std::string sru_protocol(const Z_HTTP_Request &http_req) const;
66 std::string debug_http(const Z_HTTP_Request &http_req) const;
67 void http_response(mp::Package &package,
68 const std::string &content,
69 int http_code = 200) const;
70 bool build_sru_debug_package(mp::Package &package) const;
71 bool z3950_init_request(mp::Package &package,
73 &database = "Default") const;
74 bool z3950_close_request(mp::Package &package) const;
75 bool z3950_search_request(mp::Package &package) const;
76 bool z3950_scan_request(mp::Package &package) const;
81 yf::SRUtoZ3950::SRUtoZ3950() : m_p(new Rep)
85 yf::SRUtoZ3950::~SRUtoZ3950()
86 { // must have a destructor because of boost::scoped_ptr
89 void yf::SRUtoZ3950::configure(const xmlNode *xmlnode)
91 m_p->configure(xmlnode);
94 void yf::SRUtoZ3950::process(mp::Package &package) const
96 m_p->process(package);
99 void yf::SRUtoZ3950::Rep::configure(const xmlNode *xmlnode)
103 void yf::SRUtoZ3950::Rep::process(mp::Package &package) const
105 Z_GDU *zgdu_req = package.request().get();
107 // ignoring all non HTTP_Request packages
108 if (!zgdu_req || !(zgdu_req->which == Z_GDU_HTTP_Request)){
113 // only working on HTTP_Request packages now
116 // TODO: Z3950 response parsing and translation to SRU package
117 Z_HTTP_Request* http_req = zgdu_req->u.HTTP_Request;
119 if (z3950_init_request(package))
121 z3950_search_request(package);
122 z3950_scan_request(package);
123 z3950_close_request(package);
126 build_sru_debug_package(package);
136 // SRU request package checking
140 Z_SRW_PDU *sru_pdu_req = 0;
141 Z_SRW_PDU *sru_pdu_res = 0;
142 Z_APDU *z3950_apdu_req = 0;
143 Z_APDU *z3950_apdu_res = 0;
146 Z_SOAP *soap_req = 0;
148 Z_SRW_diagnostic *diag = 0;
150 //mp::odr odr_de(ODR_DECODE);
152 if (0 == yaz_sru_decode(http_req, &sru_pdu_req, &soap_req,
153 odr(ODR_DECODE), &charset, &diag, &num_diags))
155 std::cout << "SRU GET/POST \n";
157 else if (0 == yaz_srw_decode(http_req, &sru_pdu_req, &soap_req,
158 odr(ODR_DECODE), &charset))
160 std::cout << "SRU SOAP \n";
164 std::cout << "SRU DECODING ERROR - SHOULD NEVER HAPPEN\n";
165 package.session().close();
171 std::cout << "SRU DIAGNOSTICS " << num_diags << "\n";
172 // TODO: make nice diagnostic return package
173 //Z_SRW_PDU *srw_pdu_res =
174 // yaz_srw_get(odr(ODR_ENCODE),
175 // Z_SRW_searchRetrieve_response);
176 // Z_SRW_searchRetrieveResponse *srw_res = srw_pdu_res->u.response;
178 // srw_res->diagnostics = diagnostic;
179 // srw_res->num_diagnostics = num_diagnostic;
180 // send_srw_response(srw_pdu_res);
183 // package.session().close();
188 // SRU request package translation to Z3950 package
191 if (sru_pdu_req && sru_pdu_req->which == Z_SRW_searchRetrieve_request)
193 Z_SRW_searchRetrieveRequest *srw_req = sru_pdu_req->u.request;
195 // recordXPath unsupported.
196 //if (srw_req->recordXPath)
197 // yaz_add_srw_diagnostic(odr_decode(),
198 // &diag, &num_diags, 72, 0);
200 // if (srw_req->sort_type != Z_SRW_sort_type_none)
201 // yaz_add_srw_diagnostic(odr_decode(),
202 // &diag, &num_diags, 80, 0);
206 std::cout << "SRU OPERATION NOT SUPPORTED \n";
207 // TODO: make nice diagnostic return package
208 // package.session().close();
214 bool yf::SRUtoZ3950::Rep::build_sru_debug_package(mp::Package &package) const
216 Z_GDU *zgdu_req = package.request().get();
217 if (zgdu_req && zgdu_req->which == Z_GDU_HTTP_Request)
219 Z_HTTP_Request* http_req = zgdu_req->u.HTTP_Request;
220 std::string content = debug_http(*http_req);
222 http_response(package, content, http_code);
230 yf::SRUtoZ3950::Rep::z3950_init_request(mp::Package &package,
231 const std::string &database) const
233 // prepare Z3950 package
235 //Package z3950_package(s, package.origin());
236 Package z3950_package(package.session(), package.origin());
237 z3950_package.copy_filter(package);
239 // set initRequest APDU
240 mp::odr odr_en(ODR_ENCODE);
241 Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_initRequest);
242 Z_InitRequest *init_req = apdu->u.initRequest;
243 //TODO: add user name in apdu
244 //TODO: add user passwd in apdu
245 //init_req->idAuthentication = org_init->idAuthentication;
246 //init_req->implementationId = "IDxyz";
247 //init_req->implementationName = "NAMExyz";
248 //init_req->implementationVersion = "VERSIONxyz";
250 ODR_MASK_SET(init_req->options, Z_Options_search);
251 ODR_MASK_SET(init_req->options, Z_Options_present);
252 ODR_MASK_SET(init_req->options, Z_Options_namedResultSets);
253 ODR_MASK_SET(init_req->options, Z_Options_scan);
255 ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_1);
256 ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_2);
257 ODR_MASK_SET(init_req->protocolVersion, Z_ProtocolVersion_3);
259 z3950_package.request() = apdu;
261 // send Z3950 package
262 z3950_package.move();
264 // dead Z3950 backend detection
265 if (z3950_package.session().is_closed()){
266 package.session().close();
270 // check successful initResponse
271 Z_GDU *z3950_gdu = z3950_package.response().get();
273 if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950
274 && z3950_gdu->u.z3950->which == Z_APDU_initResponse)
281 yf::SRUtoZ3950::Rep::z3950_close_request(mp::Package &package) const
283 // prepare Z3950 package
284 Package z3950_package(package.session(), package.origin());
285 z3950_package.copy_filter(package);
287 // set initRequest APDU
288 mp::odr odr_en(ODR_ENCODE);
289 Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_close);
290 //TODO: add database name in apdu
291 z3950_package.request() = apdu;
293 // send Z3950 package
294 z3950_package.move();
296 // dead Z3950 backend detection
297 if (z3950_package.session().is_closed()){
298 //package.session().close();
302 // check successful close response
303 Z_GDU *z3950_gdu = z3950_package.response().get();
304 if (z3950_gdu && z3950_gdu->which == Z_GDU_Z3950
305 && z3950_gdu->u.z3950->which == Z_APDU_close)
312 yf::SRUtoZ3950::Rep::z3950_search_request(mp::Package &package) const
314 Package z3950_package(package.session(), package.origin());
315 z3950_package.copy_filter(package);
316 mp::odr odr_en(ODR_ENCODE);
317 Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_searchRequest);
319 //TODO: add stuff in apdu
320 Z_SearchRequest *z_searchRequest = apdu->u.searchRequest;
321 z_searchRequest->num_databaseNames = 1;
322 //z_searchRequest->databaseNames = (char**)
323 // odr_malloc(m_s2z_odr_search, sizeof(char *));
324 //z_searchRequest->databaseNames[0] = odr_strdup(m_s2z_odr_search,
326 // TODO query transformation
327 Z_Query *query = (Z_Query *) odr_malloc(odr_en, sizeof(Z_Query));
328 z_searchRequest->query = query;
330 // if (srw_req->query_type == Z_SRW_query_type_cql)
332 // Z_External *ext = (Z_External *)
333 // odr_malloc(m_s2z_odr_search, sizeof(*ext));
334 // ext->direct_reference =
335 // odr_getoidbystr(m_s2z_odr_search, "1.2.840.10003.16.2");
336 // ext->indirect_reference = 0;
337 // ext->descriptor = 0;
338 // ext->which = Z_External_CQL;
339 // ext->u.cql = srw_req->query.cql;
341 // query->which = Z_Query_type_104;
342 // query->u.type_104 = ext;
344 // else if (srw_req->query_type == Z_SRW_query_type_pqf)
345 // Z_RPNQuery *RPNquery;
346 // YAZ_PQF_Parser pqf_parser;
348 // pqf_parser = yaz_pqf_create ();
350 // RPNquery = yaz_pqf_parse (pqf_parser, m_s2z_odr_search,
351 // srw_req->query.pqf);
354 // const char *pqf_msg;
356 // int code = yaz_pqf_error (pqf_parser, &pqf_msg, &off);
358 // yaz_log(YLOG_LOG, "%*s^\n", ioff+4, "");
359 // yaz_log(YLOG_LOG, "Bad PQF: %s (code %d)\n", pqf_msg, code);
361 // send_to_srw_client_error(10, 0);
364 // query->which = Z_Query_type_1;
365 // query->u.type_1 = RPNquery;
367 // yaz_pqf_destroy (pqf_parser);
371 // send_to_srw_client_error(7, "query");
375 z3950_package.request() = apdu;
376 z3950_package.move();
377 //TODO: check success condition
383 yf::SRUtoZ3950::Rep::z3950_scan_request(mp::Package &package) const
385 Package z3950_package(package.session(), package.origin());
386 z3950_package.copy_filter(package);
387 mp::odr odr_en(ODR_ENCODE);
388 Z_APDU *apdu = zget_APDU(odr_en, Z_APDU_scanRequest);
389 //TODO: add stuff in apdu
390 z3950_package.request() = apdu;
391 z3950_package.move();
392 //TODO: check success condition
400 yf::SRUtoZ3950::Rep::sru_protocol(const Z_HTTP_Request &http_req) const
402 const std::string mime_urlencoded("application/x-www-form-urlencoded");
403 const std::string mime_text_xml("text/xml");
404 const std::string mime_soap_xml("application/soap+xml");
406 const std::string http_method(http_req.method);
407 const std::string http_type
408 = http_header_value(http_req.headers, "Content-Type");
410 if (http_method == "GET")
413 if (http_method == "POST"
414 && http_type == mime_urlencoded)
417 if ( http_method == "POST"
418 && (http_type == mime_text_xml
419 || http_type == mime_soap_xml))
426 yf::SRUtoZ3950::Rep::debug_http(const Z_HTTP_Request &http_req) const
428 std::string message("<html>\n<body>\n<h1>"
429 "Metaproxy SRUtoZ3950 filter"
432 message += "<h3>HTTP Info</h3><br/>\n";
434 message += "<b>Method: </b> " + std::string(http_req.method) + "<br/>\n";
435 message += "<b>Version:</b> " + std::string(http_req.version) + "<br/>\n";
436 message += "<b>Path: </b> " + std::string(http_req.path) + "<br/>\n";
438 message += "<b>Content-Type:</b>"
439 + http_header_value(http_req.headers, "Content-Type")
441 message += "<b>Content-Length:</b>"
442 + http_header_value(http_req.headers, "Content-Length")
446 message += "<h3>Headers</h3><br/>\n";
448 Z_HTTP_Header* header = http_req.headers;
450 message += "<b>Header: </b> <i>"
451 + std::string(header->name) + ":</i> "
452 + std::string(header->value) + "<br/>\n";
453 header = header->next;
456 message += "</body>\n</html>\n";
460 void yf::SRUtoZ3950::Rep::http_response(metaproxy_1::Package &package,
461 const std::string &content,
465 Z_GDU *zgdu_req = package.request().get();
469 = odr.create_HTTP_Response(package.session(),
470 zgdu_req->u.HTTP_Request,
473 zgdu_res->u.HTTP_Response->content_len = content.size();
474 zgdu_res->u.HTTP_Response->content_buf
475 = (char*) odr_malloc(odr, zgdu_res->u.HTTP_Response->content_len);
477 strncpy(zgdu_res->u.HTTP_Response->content_buf,
478 content.c_str(), zgdu_res->u.HTTP_Response->content_len);
480 //z_HTTP_header_add(odr, &hres->headers,
481 // "Content-Type", content_type.c_str());
482 package.response() = zgdu_res;
488 static mp::filter::Base* filter_creator()
490 return new mp::filter::SRUtoZ3950;
494 struct metaproxy_1_filter_struct metaproxy_1_filter_sru_to_z3950 = {
505 * indent-tabs-mode: nil
506 * c-file-style: "stroustrup"
508 * vim: shiftwidth=4 tabstop=8 expandtab