1 /* This file is part of Metaproxy.
2 Copyright (C) Index Data
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
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
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
20 #include <metaproxy/util.hpp>
23 #include <yaz/comstack.h>
24 #include <yaz/pquery.h>
25 #include <yaz/otherinfo.h>
26 #include <yaz/querytowrbuf.h>
27 #include <yaz/oid_db.h>
29 #include <yaz/match_glob.h>
31 #include <boost/algorithm/string.hpp>
35 namespace mp = metaproxy_1;
37 // Doxygen doesn't like mp::util, so we use this instead
38 namespace mp_util = metaproxy_1::util;
41 mp_util::record_composition_to_esn(Z_RecordComposition *comp)
43 if (comp && comp->which == Z_RecordComp_complex)
45 if (comp->u.complex->generic
46 && comp->u.complex->generic->elementSpec
47 && (comp->u.complex->generic->elementSpec->which ==
48 Z_ElementSpec_elementSetName))
49 return comp->u.complex->generic->elementSpec->u.elementSetName;
51 else if (comp && comp->which == Z_RecordComp_simple &&
52 comp->u.simple->which == Z_ElementSetNames_generic)
53 return comp->u.simple->u.generic;
59 std::string mp_util::http_header_value(const Z_HTTP_Header* header,
60 const std::string name)
62 while (header && header->name
63 && std::string(header->name) != name)
64 header = header->next;
66 if (header && header->name && std::string(header->name) == name
68 return std::string(header->value);
73 std::string mp_util::http_headers_debug(const Z_HTTP_Request &http_req)
75 std::string message("<html>\n<body>\n<h1>"
76 "Metaproxy SRUtoZ3950 filter"
79 message += "<h3>HTTP Info</h3><br/>\n";
81 message += "<b>Method: </b> " + std::string(http_req.method) + "<br/>\n";
82 message += "<b>Version:</b> " + std::string(http_req.version) + "<br/>\n";
83 message += "<b>Path: </b> " + std::string(http_req.path) + "<br/>\n";
85 message += "<b>Content-Type:</b>"
86 + mp_util::http_header_value(http_req.headers, "Content-Type")
88 message += "<b>Content-Length:</b>"
89 + mp_util::http_header_value(http_req.headers, "Content-Length")
93 message += "<h3>Headers</h3><br/>\n";
95 Z_HTTP_Header* header = http_req.headers;
97 message += "<b>Header: </b> <i>"
98 + std::string(header->name) + ":</i> "
99 + std::string(header->value) + "<br/>\n";
100 header = header->next;
103 message += "</body>\n</html>\n";
108 void mp_util::http_response(metaproxy_1::Package &package,
109 const std::string &content,
113 Z_GDU *zgdu_req = package.request().get();
117 = odr.create_HTTP_Response(package.session(),
118 zgdu_req->u.HTTP_Request,
121 zgdu_res->u.HTTP_Response->content_len = content.size();
122 zgdu_res->u.HTTP_Response->content_buf
123 = (char*) odr_malloc(odr, zgdu_res->u.HTTP_Response->content_len);
125 strncpy(zgdu_res->u.HTTP_Response->content_buf,
126 content.c_str(), zgdu_res->u.HTTP_Response->content_len);
128 //z_HTTP_header_add(odr, &hres->headers,
129 // "Content-Type", content_type.c_str());
130 package.response() = zgdu_res;
134 int mp_util::memcmp2(const void *buf1, int len1,
135 const void *buf2, int len2)
139 // compare buffer (common length)
140 int c = memcmp(buf1, buf2, d > 0 ? len2 : len1);
146 // compare (remaining bytes)
155 std::string mp_util::database_name_normalize(const std::string &s)
159 for (i = 0; i < r.length(); i++)
162 if (ch >= 'A' && ch <= 'Z')
163 r[i] = ch + 'a' - 'A';
169 Z_RecordComposition *mp_util::piggyback_to_RecordComposition(
170 ODR odr, Odr_int result_set_size, Z_SearchRequest *sreq)
172 Z_RecordComposition *comp = 0;
173 Odr_int present_dummy;
174 const char *element_set_name = 0;
175 mp::util::piggyback_sr(sreq, result_set_size,
176 present_dummy, &element_set_name);
177 if (element_set_name)
179 comp = (Z_RecordComposition *) odr_malloc(odr, sizeof(*comp));
180 comp->which = Z_RecordComp_simple;
181 comp->u.simple = (Z_ElementSetNames *)
182 odr_malloc(odr, sizeof(Z_ElementSetNames));
183 comp->u.simple->which = Z_ElementSetNames_generic;
184 comp->u.simple->u.generic = odr_strdup(odr, element_set_name);
189 void mp_util::piggyback_sr(Z_SearchRequest *sreq,
190 Odr_int result_set_size,
191 Odr_int &number_to_present,
192 const char **element_set_name)
194 Z_ElementSetNames *esn;
195 const char *smallSetElementSetNames = 0;
196 const char *mediumSetElementSetNames = 0;
198 esn = sreq->smallSetElementSetNames;
199 if (esn && esn->which == Z_ElementSetNames_generic)
200 smallSetElementSetNames = esn->u.generic;
202 esn = sreq->mediumSetElementSetNames;
203 if (esn && esn->which == Z_ElementSetNames_generic)
204 mediumSetElementSetNames = esn->u.generic;
206 piggyback(*sreq->smallSetUpperBound,
207 *sreq->largeSetLowerBound,
208 *sreq->mediumSetPresentNumber,
209 smallSetElementSetNames,
210 mediumSetElementSetNames,
216 void mp_util::piggyback(int smallSetUpperBound,
217 int largeSetLowerBound,
218 int mediumSetPresentNumber,
220 int &number_to_present)
222 Odr_int tmp = number_to_present;
223 piggyback(smallSetUpperBound, largeSetLowerBound, mediumSetPresentNumber,
224 0, 0, result_set_size, tmp, 0);
225 number_to_present = tmp;
228 void mp_util::piggyback(Odr_int smallSetUpperBound,
229 Odr_int largeSetLowerBound,
230 Odr_int mediumSetPresentNumber,
231 const char *smallSetElementSetNames,
232 const char *mediumSetElementSetNames,
233 Odr_int result_set_size,
234 Odr_int &number_to_present,
235 const char **element_set_name)
237 // deal with piggyback
239 if (result_set_size < smallSetUpperBound)
241 // small set . Return all records in set
242 number_to_present = result_set_size;
243 if (element_set_name && smallSetElementSetNames)
244 *element_set_name = smallSetElementSetNames;
247 else if (result_set_size > largeSetLowerBound)
249 // large set . Return no records
250 number_to_present = 0;
251 if (element_set_name)
252 *element_set_name = 0;
256 // medium set . Return mediumSetPresentNumber records
257 number_to_present = mediumSetPresentNumber;
258 if (number_to_present > result_set_size)
259 number_to_present = result_set_size;
260 if (element_set_name && mediumSetElementSetNames)
261 *element_set_name = mediumSetElementSetNames;
265 bool mp_util::pqf(ODR odr, Z_APDU *apdu, const std::string &q)
267 YAZ_PQF_Parser pqf_parser = yaz_pqf_create();
269 Z_RPNQuery *rpn = yaz_pqf_parse(pqf_parser, odr, q.c_str());
272 yaz_pqf_destroy(pqf_parser);
275 yaz_pqf_destroy(pqf_parser);
276 Z_Query *query = (Z_Query *) odr_malloc(odr, sizeof(Z_Query));
277 query->which = Z_Query_type_1;
278 query->u.type_1 = rpn;
280 apdu->u.searchRequest->query = query;
285 std::string mp_util::zQueryToString(Z_Query *query)
287 std::string query_str = "";
289 if (query && query->which == Z_Query_type_1)
291 Z_RPNQuery *rpn = query->u.type_1;
298 yaz_rpnquery_to_wrbuf(w, rpn);
300 // from w to std::string
301 query_str = std::string(w.buf(), w.len());
306 if (query && query->which == Z_Query_type_1){
308 // allocate wrbuf (strings in YAZ!)
309 WRBUF w = wrbuf_alloc();
312 yaz_query_to_wrbuf(w, query);
314 // from w to std::string
315 query_str = std::string(wrbuf_buf(w), wrbuf_len(w));
324 void mp_util::get_default_diag(Z_DefaultDiagFormat *r,
325 int &error_code, std::string &addinfo)
327 error_code = *r->condition;
330 case Z_DefaultDiagFormat_v2Addinfo:
331 addinfo = std::string(r->u.v2Addinfo);
333 case Z_DefaultDiagFormat_v3Addinfo:
334 addinfo = r->u.v3Addinfo;
339 void mp_util::get_init_diagnostics(
340 Z_InitResponse *initrs, int &error_code, std::string &addinfo)
343 Z_DefaultDiagFormat *df = yaz_decode_init_diag(0, initrs);
346 get_default_diag(df, error_code, addinfo);
349 int mp_util::get_or_remove_vhost_otherinfo(
350 Z_OtherInformation **otherInformation,
352 std::list<std::string> &vhosts)
355 for (cat = 1; ; cat++)
357 // check virtual host
359 yaz_oi_get_string_oid(otherInformation,
360 yaz_oid_userinfo_proxy,
361 cat /* categoryValue */,
362 remove_flag /* delete flag */);
365 vhosts.push_back(std::string(vhost));
371 void mp_util::get_vhost_otherinfo(
372 Z_OtherInformation *otherInformation,
373 std::list<std::string> &vhosts)
375 get_or_remove_vhost_otherinfo(&otherInformation, false, vhosts);
378 int mp_util::remove_vhost_otherinfo(
379 Z_OtherInformation **otherInformation,
380 std::list<std::string> &vhosts)
382 return get_or_remove_vhost_otherinfo(otherInformation, true, vhosts);
385 void mp_util::set_vhost_otherinfo(
386 Z_OtherInformation **otherInformation, ODR odr,
387 const std::list<std::string> &vhosts)
390 std::list<std::string>::const_iterator it = vhosts.begin();
392 for (cat = 1; it != vhosts.end() ; cat++, it++)
394 yaz_oi_set_string_oid(otherInformation, odr,
395 yaz_oid_userinfo_proxy, cat, it->c_str());
399 void mp_util::set_vhost_otherinfo(
400 Z_OtherInformation **otherInformation, ODR odr,
401 const std::string vhost, const int cat)
403 yaz_oi_set_string_oid(otherInformation, odr,
404 yaz_oid_userinfo_proxy, cat, vhost.c_str());
407 void mp_util::split_zurl(std::string zurl, std::string &host,
408 std::list<std::string> &db)
410 const char *zurl_cstr = zurl.c_str();
411 const char *args = 0;
412 cs_get_host_args(zurl_cstr, &args);
416 host = std::string(zurl_cstr, args - zurl_cstr);
418 const char *cp1 = args;
421 const char *cp2 = strchr(cp1, '+');
423 db.push_back(std::string(cp1, cp2 - cp1));
426 db.push_back(std::string(cp1));
436 bool mp_util::set_databases_from_zurl(
437 ODR odr, std::string zurl,
438 int *db_num, char ***db_strings)
441 std::list<std::string> dblist;
443 split_zurl(zurl, host, dblist);
445 if (dblist.size() == 0)
447 *db_num = dblist.size();
448 *db_strings = (char **) odr_malloc(odr, sizeof(char*) * (*db_num));
450 std::list<std::string>::const_iterator it = dblist.begin();
451 for (int i = 0; it != dblist.end(); it++, i++)
452 (*db_strings)[i] = odr_strdup(odr, it->c_str());
456 mp::odr::odr(int type)
458 m_odr = odr_createmem(type);
463 m_odr = odr_createmem(ODR_ENCODE);
471 mp::odr::operator ODR() const
476 Z_APDU *mp::odr::create_close(const Z_APDU *in_apdu,
477 int reason, const char *addinfo)
479 Z_APDU *apdu = create_APDU(Z_APDU_close, in_apdu);
481 *apdu->u.close->closeReason = reason;
483 apdu->u.close->diagnosticInformation = odr_strdup(m_odr, addinfo);
487 Z_APDU *mp::odr::create_APDU(int type, const Z_APDU *in_apdu)
489 return mp::util::create_APDU(m_odr, type, in_apdu);
492 Z_APDU *mp_util::create_APDU(ODR odr, int type, const Z_APDU *in_apdu)
494 Z_APDU *out_apdu = zget_APDU(odr, type);
495 transfer_referenceId(odr, in_apdu, out_apdu);
499 void mp_util::transfer_referenceId(ODR odr, const Z_APDU *src, Z_APDU *dst)
501 Z_ReferenceId **id_to = mp::util::get_referenceId(dst);
505 Z_ReferenceId **id_from = mp::util::get_referenceId(src);
506 if (id_from && *id_from)
507 *id_to = odr_create_Odr_oct(odr, (*id_from)->buf,
512 Z_APDU *mp::odr::create_initResponse(const Z_APDU *in_apdu,
513 int error, const char *addinfo)
515 Z_APDU *apdu = create_APDU(Z_APDU_initResponse, in_apdu);
518 apdu->u.initResponse->userInformationField =
519 zget_init_diagnostics(m_odr, error, addinfo);
520 *apdu->u.initResponse->result = 0;
522 apdu->u.initResponse->implementationName =
523 odr_prepend(m_odr, "Metaproxy",
524 apdu->u.initResponse->implementationName);
525 apdu->u.initResponse->implementationVersion =
527 VERSION, apdu->u.initResponse->implementationVersion);
532 Z_APDU *mp::odr::create_searchResponse(const Z_APDU *in_apdu,
533 int error, const char *addinfo)
535 Z_APDU *apdu = create_APDU(Z_APDU_searchResponse, in_apdu);
538 Z_Records *rec = (Z_Records *) odr_malloc(m_odr, sizeof(Z_Records));
539 *apdu->u.searchResponse->searchStatus = 0;
540 apdu->u.searchResponse->records = rec;
541 rec->which = Z_Records_NSD;
542 rec->u.nonSurrogateDiagnostic =
543 zget_DefaultDiagFormat(m_odr, error, addinfo);
549 Z_APDU *mp::odr::create_presentResponse(const Z_APDU *in_apdu,
550 int error, const char *addinfo)
552 Z_APDU *apdu = create_APDU(Z_APDU_presentResponse, in_apdu);
555 Z_Records *rec = (Z_Records *) odr_malloc(m_odr, sizeof(Z_Records));
556 apdu->u.presentResponse->records = rec;
558 rec->which = Z_Records_NSD;
559 rec->u.nonSurrogateDiagnostic =
560 zget_DefaultDiagFormat(m_odr, error, addinfo);
561 *apdu->u.presentResponse->presentStatus = Z_PresentStatus_failure;
566 Z_APDU *mp::odr::create_scanResponse(const Z_APDU *in_apdu,
567 int error, const char *addinfo)
569 Z_APDU *apdu = create_APDU(Z_APDU_scanResponse, in_apdu);
570 Z_ScanResponse *res = apdu->u.scanResponse;
571 res->entries = (Z_ListEntries *) odr_malloc(m_odr, sizeof(*res->entries));
572 res->entries->num_entries = 0;
573 res->entries->entries = 0;
577 *res->scanStatus = Z_Scan_failure;
579 res->entries->num_nonsurrogateDiagnostics = 1;
580 res->entries->nonsurrogateDiagnostics = (Z_DiagRec **)
581 odr_malloc(m_odr, sizeof(Z_DiagRec *));
582 res->entries->nonsurrogateDiagnostics[0] =
583 zget_DiagRec(m_odr, error, addinfo);
587 res->entries->num_nonsurrogateDiagnostics = 0;
588 res->entries->nonsurrogateDiagnostics = 0;
593 Z_GDU *mp::odr::create_HTTP_Response_details(mp::Session &session,
594 Z_HTTP_Request *hreq, int code,
597 const char *response_version = "1.0";
598 bool keepalive = false;
599 if (!strcmp(hreq->version, "1.0"))
601 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
602 if (v && !strcmp(v, "Keep-Alive"))
606 response_version = "1.0";
610 const char *v = z_HTTP_header_lookup(hreq->headers, "Connection");
611 if (v && !strcmp(v, "close"))
615 response_version = "1.1";
618 Z_GDU *gdu = z_get_HTTP_Response_server(
619 m_odr, code, details, "Metaproxy/" VERSION,
620 "http://www.indexdata.com/metaproxy");
621 Z_HTTP_Response *hres = gdu->u.HTTP_Response;
622 hres->version = odr_strdup(m_odr, response_version);
624 z_HTTP_header_add(m_odr, &hres->headers, "Connection", "Keep-Alive");
628 Z_GDU *mp::odr::create_HTTP_Response(mp::Session &session,
629 Z_HTTP_Request *hreq, int code)
631 return create_HTTP_Response_details(session, hreq, code, 0);
635 Z_ReferenceId **mp_util::get_referenceId(const Z_APDU *apdu)
639 case Z_APDU_initRequest:
640 return &apdu->u.initRequest->referenceId;
641 case Z_APDU_initResponse:
642 return &apdu->u.initResponse->referenceId;
643 case Z_APDU_searchRequest:
644 return &apdu->u.searchRequest->referenceId;
645 case Z_APDU_searchResponse:
646 return &apdu->u.searchResponse->referenceId;
647 case Z_APDU_presentRequest:
648 return &apdu->u.presentRequest->referenceId;
649 case Z_APDU_presentResponse:
650 return &apdu->u.presentResponse->referenceId;
651 case Z_APDU_deleteResultSetRequest:
652 return &apdu->u.deleteResultSetRequest->referenceId;
653 case Z_APDU_deleteResultSetResponse:
654 return &apdu->u.deleteResultSetResponse->referenceId;
655 case Z_APDU_accessControlRequest:
656 return &apdu->u.accessControlRequest->referenceId;
657 case Z_APDU_accessControlResponse:
658 return &apdu->u.accessControlResponse->referenceId;
659 case Z_APDU_resourceControlRequest:
660 return &apdu->u.resourceControlRequest->referenceId;
661 case Z_APDU_resourceControlResponse:
662 return &apdu->u.resourceControlResponse->referenceId;
663 case Z_APDU_triggerResourceControlRequest:
664 return &apdu->u.triggerResourceControlRequest->referenceId;
665 case Z_APDU_resourceReportRequest:
666 return &apdu->u.resourceReportRequest->referenceId;
667 case Z_APDU_resourceReportResponse:
668 return &apdu->u.resourceReportResponse->referenceId;
669 case Z_APDU_scanRequest:
670 return &apdu->u.scanRequest->referenceId;
671 case Z_APDU_scanResponse:
672 return &apdu->u.scanResponse->referenceId;
673 case Z_APDU_sortRequest:
674 return &apdu->u.sortRequest->referenceId;
675 case Z_APDU_sortResponse:
676 return &apdu->u.sortResponse->referenceId;
677 case Z_APDU_segmentRequest:
678 return &apdu->u.segmentRequest->referenceId;
679 case Z_APDU_extendedServicesRequest:
680 return &apdu->u.extendedServicesRequest->referenceId;
681 case Z_APDU_extendedServicesResponse:
682 return &apdu->u.extendedServicesResponse->referenceId;
684 return &apdu->u.close->referenceId;
689 std::string mp_util::uri_encode(std::string s)
691 char *x = (char *) xmalloc(1 + s.length() * 3);
692 yaz_encode_uri_component(x, s.c_str());
693 std::string result(x);
699 std::string mp_util::uri_decode(std::string s)
701 char *x = (char *) xmalloc(1 + s.length());
702 yaz_decode_uri_component(x, s.c_str(), s.length());
703 std::string result(x);
710 m_wrbuf = wrbuf_alloc();
715 wrbuf_destroy(m_wrbuf);
718 mp::wrbuf::operator WRBUF() const
723 size_t mp::wrbuf::len()
725 return wrbuf_len(m_wrbuf);
728 const char *mp::wrbuf::buf()
730 return wrbuf_buf(m_wrbuf);
733 const char *mp::wrbuf::c_str()
735 return wrbuf_cstr(m_wrbuf);
738 const char *mp::wrbuf::c_str_null()
740 return wrbuf_cstr_null(m_wrbuf);
743 bool mp::util::match_ip(const std::string &pattern, const std::string &value)
745 std::vector<std::string> globitems;
746 boost::split(globitems, pattern, boost::is_any_of(" "));
747 std::vector<std::string>::const_iterator it = globitems.begin();
748 bool ret_value = true; // for now (if only empty values)
749 for (; it != globitems.end(); it++)
751 const char *c_str = (*it).c_str();
754 ret_value = false; // at least one non-empty value
755 if (yaz_match_glob(c_str, value.c_str()))
765 * c-file-style: "Stroustrup"
766 * indent-tabs-mode: nil
768 * vim: shiftwidth=4 tabstop=8 expandtab