X-Git-Url: http://git.indexdata.com/?a=blobdiff_plain;f=src%2Ffilter_zoom.cpp;h=2edddd57d775b03de46f8f1d3b781f57c7a02c20;hb=55fdfbb42225f71fb791bb8f9ec033ca0fddbe44;hp=a75c4d4ae2c9ccdfa4c267c3ffde8d0e898dd835;hpb=9401913fbcdbead99f1180848f5fef0d02fd871e;p=metaproxy-moved-to-github.git diff --git a/src/filter_zoom.cpp b/src/filter_zoom.cpp index a75c4d4..2edddd5 100644 --- a/src/filter_zoom.cpp +++ b/src/filter_zoom.cpp @@ -1,5 +1,5 @@ /* This file is part of Metaproxy. - Copyright (C) 2005-2012 Index Data + Copyright (C) 2005-2013 Index Data Metaproxy is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free @@ -60,6 +60,7 @@ namespace metaproxy_1 { class Zoom::Searchable : boost::noncopyable { public: std::string authentication; + std::string authenticationMode; std::string cfAuth; std::string cfProxy; std::string cfSubDB; @@ -76,6 +77,8 @@ namespace metaproxy_1 { std::string urlRecipe; std::string contentConnector; std::string sortStrategy; + std::string extraArgs; + std::string rpn2cql_fname; bool use_turbomarc; bool piggyback; CCL_bibset ccl_bibset; @@ -98,6 +101,7 @@ namespace metaproxy_1 { bool enable_explain; xmlDoc *explain_doc; std::string m_proxy; + cql_transform_t cqlt; public: Backend(); ~Backend(); @@ -117,16 +121,21 @@ namespace metaproxy_1 { Impl *m_p; bool m_is_virtual; bool m_in_use; + std::string session_realm; yazpp_1::GDU m_init_gdu; BackendPtr m_backend; void handle_package(mp::Package &package); void handle_search(mp::Package &package); + void auth(mp::Package &package, Z_InitRequest *req, + int *error, char **addinfo, ODR odr); + BackendPtr explain_search(mp::Package &package, std::string &database, int *error, char **addinfo, mp::odr &odr, + std::string torus_url, std::string &torus_db, std::string &realm); void handle_present(mp::Package &package); @@ -145,7 +154,7 @@ namespace metaproxy_1 { std::string authentication, std::string proxy, std::string realm); - + void prepare_elements(BackendPtr b, Odr_oid *preferredRecordSyntax, const char *element_set_name, @@ -174,7 +183,7 @@ namespace metaproxy_1 { const char *element_set_name); bool retry(mp::Package &package, mp::odr &odr, - BackendPtr b, + BackendPtr b, int &error, char **addinfo, int &proxy_step, int &same_retries, int &proxy_retries); @@ -202,11 +211,12 @@ namespace metaproxy_1 { void release_frontend(mp::Package &package); SearchablePtr parse_torus_record(const xmlNode *ptr); struct cql_node *convert_cql_fields(struct cql_node *cn, ODR odr); - std::map m_clients; + std::map m_clients; boost::mutex m_mutex; boost::condition m_cond_session_ready; std::string torus_searchable_url; std::string torus_content_url; + std::string torus_auth_url; std::string default_realm; std::map fieldmap; std::string xsldir; @@ -218,6 +228,7 @@ namespace metaproxy_1 { CCL_bibset bibset; std::string element_transform; std::string element_raw; + std::string element_passthru; std::string proxy; xsltStylesheetPtr explain_xsp; xsltStylesheetPtr record_xsp; @@ -241,7 +252,7 @@ static xmlNode *xml_node_search(xmlNode *ptr, int *num, int m) return ptr; } else // else: we don't want to find nested nodes - { + { xmlNode *ret_node = xml_node_search(ptr->children, num, m); if (ret_node) return ret_node; @@ -252,7 +263,7 @@ static xmlNode *xml_node_search(xmlNode *ptr, int *num, int m) } // define Pimpl wrapper forwarding to Impl - + yf::Zoom::Zoom() : m_p(new Impl) { } @@ -284,6 +295,7 @@ yf::Zoom::Backend::Backend() enable_cproxy = true; enable_explain = false; explain_doc = 0; + cqlt = 0; } yf::Zoom::Backend::~Backend() @@ -292,6 +304,7 @@ yf::Zoom::Backend::~Backend() xsltFreeStylesheet(xsp); if (explain_doc) xmlFreeDoc(explain_doc); + cql_transform_close(cqlt); ZOOM_connection_destroy(m_connection); ZOOM_resultset_destroy(m_resultset); } @@ -309,14 +322,14 @@ void yf::Zoom::Backend::get_zoom_error(int *error, char **addinfo, { if (!dset) dset = "Unknown"; - + if (!strcmp(dset, "info:srw/diagnostic/1")) *error = yaz_diag_srw_to_bib1(error0); else if (!strcmp(dset, "Bib-1")) *error = error0; else if (!strcmp(dset, "ZOOM")) { - *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR; + *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR; if (error0 == ZOOM_ERROR_INIT) *error = YAZ_BIB1_INIT_AC_AUTHENTICATION_SYSTEM_ERROR; else if (error0 == ZOOM_ERROR_DECODE) @@ -331,7 +344,7 @@ void yf::Zoom::Backend::get_zoom_error(int *error, char **addinfo, } else *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR; - + *addinfo = (char *) odr_malloc( odr, 30 + strlen(dset) + strlen(msg) + (zoom_addinfo ? strlen(zoom_addinfo) : 0)); @@ -349,8 +362,12 @@ void yf::Zoom::Backend::connect(std::string zurl, int *error, char **addinfo, ODR odr) { + size_t h = zurl.find_first_of('#'); + if (h != std::string::npos) + zurl.erase(h); ZOOM_connection_connect(m_connection, zurl.length() ? zurl.c_str() : 0, 0); get_zoom_error(error, addinfo, odr); + } void yf::Zoom::Backend::search(ZOOM_query q, Odr_int *hits, @@ -403,7 +420,7 @@ yf::Zoom::Searchable::~Searchable() ccl_qual_rm(&ccl_bibset); } -yf::Zoom::Frontend::Frontend(Impl *impl) : +yf::Zoom::Frontend::Frontend(Impl *impl) : m_p(impl), m_is_virtual(false), m_in_use(true) { } @@ -417,13 +434,13 @@ yf::Zoom::FrontendPtr yf::Zoom::Impl::get_frontend(mp::Package &package) boost::mutex::scoped_lock lock(m_mutex); std::map::iterator it; - + while(true) { it = m_clients.find(package.session()); if (it == m_clients.end()) break; - + if (!it->second->m_in_use) { it->second->m_in_use = true; @@ -441,7 +458,7 @@ void yf::Zoom::Impl::release_frontend(mp::Package &package) { boost::mutex::scoped_lock lock(m_mutex); std::map::iterator it; - + it = m_clients.find(package.session()); if (it != m_clients.end()) { @@ -458,7 +475,8 @@ void yf::Zoom::Impl::release_frontend(mp::Package &package) } yf::Zoom::Impl::Impl() : - apdu_log(false), element_transform("pz2") , element_raw("raw"), + apdu_log(false), element_transform("pz2") , element_raw("raw") , + element_passthru("F"), zoom_timeout("40"), proxy_timeout(1) { bibset = ccl_qual_mk(); @@ -478,7 +496,7 @@ yf::Zoom::Impl::~Impl() yf::Zoom::SearchablePtr yf::Zoom::Impl::parse_torus_record(const xmlNode *ptr) { Zoom::SearchablePtr s(new Searchable(bibset)); - + for (ptr = ptr->children; ptr; ptr = ptr->next) { if (ptr->type != XML_ELEMENT_NODE) @@ -491,25 +509,30 @@ yf::Zoom::SearchablePtr yf::Zoom::Impl::parse_torus_record(const xmlNode *ptr) s->authentication = mp::xml::get_text(ptr); } else if (!strcmp((const char *) ptr->name, + "authenticationMode")) + { + s->authenticationMode = mp::xml::get_text(ptr); + } + else if (!strcmp((const char *) ptr->name, "cfAuth")) { s->cfAuth = mp::xml::get_text(ptr); - } + } else if (!strcmp((const char *) ptr->name, "cfProxy")) { s->cfProxy = mp::xml::get_text(ptr); - } + } else if (!strcmp((const char *) ptr->name, "cfSubDB")) { s->cfSubDB = mp::xml::get_text(ptr); - } + } else if (!strcmp((const char *) ptr->name, "contentConnector")) { s->contentConnector = mp::xml::get_text(ptr); - } + } else if (!strcmp((const char *) ptr->name, "udb")) { s->udb = mp::xml::get_text(ptr); @@ -593,6 +616,13 @@ yf::Zoom::SearchablePtr yf::Zoom::Impl::parse_torus_record(const xmlNode *ptr) { s->sortStrategy = mp::xml::get_text(ptr); } + else if (!strcmp((const char *) ptr->name, + "extraArgs")) + { + s->extraArgs = mp::xml::get_text(ptr); + } + else if (!strcmp((const char *) ptr->name, "rpn2cql")) + s->rpn2cql_fname = mp::xml::get_text(ptr); } return s; } @@ -601,7 +631,7 @@ void yf::Zoom::Impl::configure_local_records(const xmlNode *ptr, bool test_only) { while (ptr && ptr->type != XML_ELEMENT_NODE) ptr = ptr->next; - + if (ptr) { if (!strcmp((const char *) ptr->name, "records")) @@ -628,7 +658,7 @@ void yf::Zoom::Impl::configure_local_records(const xmlNode *ptr, bool test_only) else { throw mp::filter::FilterException - ("Bad element " + ("Bad element " + std::string((const char *) ptr->name) + " in zoom filter inside element " ""); @@ -638,7 +668,7 @@ void yf::Zoom::Impl::configure_local_records(const xmlNode *ptr, bool test_only) else { throw mp::filter::FilterException - ("Bad element " + ("Bad element " + std::string((const char *) ptr->name) + " in zoom filter inside element "); } @@ -668,6 +698,8 @@ void yf::Zoom::Impl::configure(const xmlNode *ptr, bool test_only, torus_searchable_url = mp::xml::get_text(attr->children); else if (!strcmp((const char *) attr->name, "content_url")) torus_content_url = mp::xml::get_text(attr->children); + else if (!strcmp((const char *) attr->name, "auth_url")) + torus_auth_url = mp::xml::get_text(attr->children); else if (!strcmp((const char *) attr->name, "realm")) default_realm = mp::xml::get_text(attr->children); else if (!strcmp((const char *) attr->name, "xsldir")) @@ -676,6 +708,8 @@ void yf::Zoom::Impl::configure(const xmlNode *ptr, bool test_only, element_transform = mp::xml::get_text(attr->children); else if (!strcmp((const char *) attr->name, "element_raw")) element_raw = mp::xml::get_text(attr->children); + else if (!strcmp((const char *) attr->name, "element_passthru")) + element_passthru = mp::xml::get_text(attr->children); else if (!strcmp((const char *) attr->name, "proxy")) proxy = mp::xml::get_text(attr->children); else if (!strcmp((const char *) attr->name, "explain_xsl")) @@ -726,9 +760,9 @@ void yf::Zoom::Impl::configure(const xmlNode *ptr, bool test_only, { yaz_log(YLOG_WARN, "contentProxy's server attribute is deprecated"); - yaz_log(YLOG_LOG, + yaz_log(YLOG_LOG, "Specify config_file instead. For example:"); - yaz_log(YLOG_LOG, + yaz_log(YLOG_LOG, " content_file=\"/etc/cf-proxy/cproxy.cfg\""); content_proxy_server = mp::xml::get_text(attr->children); } @@ -743,7 +777,7 @@ void yf::Zoom::Impl::configure(const xmlNode *ptr, bool test_only, } } else if (!strcmp((const char *) ptr->name, "log")) - { + { const struct _xmlAttr *attr; for (attr = ptr->properties; attr; attr = attr->next) { @@ -773,7 +807,7 @@ void yf::Zoom::Impl::configure(const xmlNode *ptr, bool test_only, else { throw mp::filter::FilterException - ("Bad element " + ("Bad element " + std::string((const char *) ptr->name) + " in zoom filter"); } @@ -782,12 +816,12 @@ void yf::Zoom::Impl::configure(const xmlNode *ptr, bool test_only, if (explain_xslt_fname.length()) { const char *path = 0; - + if (xsldir.length()) path = xsldir.c_str(); else path = file_path.c_str(); - + char fullpath[1024]; char *cp = yaz_filepath_resolve(explain_xslt_fname.c_str(), path, 0, fullpath); @@ -810,19 +844,19 @@ void yf::Zoom::Impl::configure(const xmlNode *ptr, bool test_only, xmlFreeDoc(xsp_doc); throw mp::filter::FilterException ("Cannot parse XSLT " + explain_xslt_fname); - + } } if (record_xslt_fname.length()) { const char *path = 0; - + if (xsldir.length()) path = xsldir.c_str(); else path = file_path.c_str(); - + char fullpath[1024]; char *cp = yaz_filepath_resolve(record_xslt_fname.c_str(), path, 0, fullpath); @@ -845,7 +879,7 @@ void yf::Zoom::Impl::configure(const xmlNode *ptr, bool test_only, xmlFreeDoc(xsp_doc); throw mp::filter::FilterException ("Cannot parse XSLT " + record_xslt_fname); - + } } } @@ -869,7 +903,7 @@ bool yf::Zoom::Frontend::create_content_session(mp::Package &package, proxyhostname = m_p->content_proxy_server; legacy_format = true; } - + if (m_p->content_tmp_file.length()) tmp_file = m_p->content_tmp_file; @@ -899,7 +933,7 @@ bool yf::Zoom::Frontend::create_content_session(mp::Package &package, while (*cp == ' ') cp++; if (!strcmp(buf, "proxyhostname")) - proxyhostname = cp; + proxyhostname = cp; if (!strcmp(buf, "sessiondir") && *cp) { if (cp[strlen(cp)-1] == '/') @@ -916,8 +950,8 @@ bool yf::Zoom::Frontend::create_content_session(mp::Package &package, "unable to open content config %s", m_p->content_config_file.c_str()); *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR; - *addinfo = (char *) odr_malloc(odr, 60 + tmp_file.length()); - sprintf(*addinfo, "unable to open content config %s", + *addinfo = (char *) odr_malloc(odr, 70 + tmp_file.length()); + sprintf(*addinfo, "zoom: unable to open content config %s", m_p->content_config_file.c_str()); return false; } @@ -941,7 +975,7 @@ bool yf::Zoom::Frontend::create_content_session(mp::Package &package, package.log("zoom", YLOG_WARN, "bad tmp_file %s", tmp_file.c_str()); *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR; *addinfo = (char *) odr_malloc(odr, 60 + tmp_file.length()); - sprintf(*addinfo, "bad format of content tmp_file: %s", + sprintf(*addinfo, "zoom: bad format of content tmp_file: %s", tmp_file.c_str()); xfree(fname); return false; @@ -959,8 +993,8 @@ bool yf::Zoom::Frontend::create_content_session(mp::Package &package, { package.log("zoom", YLOG_WARN|YLOG_ERRNO, "create %s", fname); *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR; - *addinfo = (char *) odr_malloc(odr, 40 + strlen(fname)); - sprintf(*addinfo, "Could not create %s", fname); + *addinfo = (char *) odr_malloc(odr, 50 + strlen(fname)); + sprintf(*addinfo, "zoom: could not create %s", fname); xfree(fname); return false; } @@ -991,7 +1025,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( std::string proxy; std::list::const_iterator map_it; - if (m_backend && !m_backend->enable_explain && + if (m_backend && !m_backend->enable_explain && m_backend->m_frontend_database == database) { connection_reuse = true; @@ -1012,7 +1046,9 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( std::string authentication; std::string content_authentication; std::string content_proxy; - std::string realm = m_p->default_realm; + std::string realm = session_realm; + if (realm.length() == 0) + realm = m_p->default_realm; const char *param_user = 0; const char *param_password = 0; @@ -1032,7 +1068,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( odr_malloc(odr, (10 + no_parms) * sizeof(*out_names)); const char **out_values = (const char **) odr_malloc(odr, (10 + no_parms) * sizeof(*out_values)); - + // may be changed if it's a content connection std::string torus_url = m_p->torus_searchable_url; int i; @@ -1079,7 +1115,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( else { proxy = dstr[*proxy_step]; - + (*proxy_step)++; if (*proxy_step == dnum) *proxy_step = 0; @@ -1092,8 +1128,10 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( out_values[no_out_args++] = value; torus_url = m_p->torus_content_url; } - else if (!strcmp(name, "realm")) + else if (!strcmp(name, "realm") && session_realm.length() == 0) realm = value; + else if (!strcmp(name, "torus_url") && session_realm.length() == 0) + torus_url = value; else if (name[0] == 'x' && name[1] == '-') { out_names[no_out_args] = name; @@ -1104,11 +1142,11 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( BackendPtr notfound; char *msg = (char*) odr_malloc(odr, strlen(name) + 30); *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR; - sprintf(msg, "Bad database argument: %s", name); + sprintf(msg, "zoom: bad database argument: %s", name); *addinfo = msg; return notfound; } - } + } if (proxy.length()) package.log("zoom", YLOG_LOG, "proxy: %s", proxy.c_str()); @@ -1132,9 +1170,9 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( } if (torus_db.compare("IR-Explain---1") == 0) - return explain_search(package, database, error, addinfo, odr, torus_db, - realm); - + return explain_search(package, database, error, addinfo, odr, torus_url, + torus_db, realm); + SearchablePtr sptr; std::map::iterator it; @@ -1156,27 +1194,44 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( return b; } const xmlNode *ptr = xmlDocGetRootElement(doc); - if (ptr) - { // presumably ptr is a records element node - // parse first record in document - for (ptr = ptr->children; ptr; ptr = ptr->next) + if (ptr && ptr->type == XML_ELEMENT_NODE) + { + if (!strcmp((const char *) ptr->name, "record")) + { + sptr = m_p->parse_torus_record(ptr); + } + else if (!strcmp((const char *) ptr->name, "records")) { - if (ptr->type == XML_ELEMENT_NODE - && !strcmp((const char *) ptr->name, "record")) + for (ptr = ptr->children; ptr; ptr = ptr->next) { - if (sptr) + if (ptr->type == XML_ELEMENT_NODE + && !strcmp((const char *) ptr->name, "record")) { - *error = YAZ_BIB1_UNSPECIFIED_ERROR; - *addinfo = (char*) odr_malloc(odr, 40 + database.length()), - sprintf(*addinfo, "multiple records for udb=%s", - database.c_str()); - xmlFreeDoc(doc); - BackendPtr b; - return b; + if (sptr) + { + *error = YAZ_BIB1_UNSPECIFIED_ERROR; + *addinfo = (char*) + odr_malloc(odr, 40 + torus_db.length()); + sprintf(*addinfo, "multiple records for udb=%s", + database.c_str()); + xmlFreeDoc(doc); + BackendPtr b; + return b; + } + sptr = m_p->parse_torus_record(ptr); } - sptr = m_p->parse_torus_record(ptr); } } + else + { + *error = YAZ_BIB1_UNSPECIFIED_ERROR; + *addinfo = (char*) odr_malloc( + odr, 40 + strlen((const char *) ptr->name)); + sprintf(*addinfo, "bad root element for torus: %s", ptr->name); + xmlFreeDoc(doc); + BackendPtr b; + return b; + } } xmlFreeDoc(doc); } @@ -1188,7 +1243,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( BackendPtr b; return b; } - + xsltStylesheetPtr xsp = 0; if (sptr->transform_xsl_content.length()) { @@ -1197,8 +1252,8 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( if (!xsp_doc) { *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR; - *addinfo = (char *) odr_malloc(odr, 40); - sprintf(*addinfo, "xmlParseMemory failed"); + *addinfo = odr_strdup(odr, "zoom: xmlParseMemory failed " + "for literalTransform XSL"); BackendPtr b; return b; } @@ -1206,7 +1261,9 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( if (!xsp) { *error = YAZ_BIB1_DATABASE_DOES_NOT_EXIST; - *addinfo = odr_strdup(odr, "xsltParseStylesheetDoc failed"); + *addinfo = + odr_strdup(odr,"zoom: xsltParseStylesheetDoc failed " + "for literalTransform XSL"); BackendPtr b; xmlFreeDoc(xsp_doc); return b; @@ -1232,7 +1289,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR; *addinfo = (char *) odr_malloc(odr, 40 + sptr->transform_xsl_fname.length()); - sprintf(*addinfo, "File could not be read: %s", + sprintf(*addinfo, "zoom: could not open file %s", sptr->transform_xsl_fname.c_str()); BackendPtr b; return b; @@ -1241,26 +1298,51 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( if (!xsp_doc) { *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR; - *addinfo = (char *) odr_malloc(odr, 40 + fname.length()); - sprintf(*addinfo, "xmlParseFile failed. File: %s", fname.c_str()); + *addinfo = (char *) odr_malloc(odr, 50 + fname.length()); + sprintf(*addinfo, "zoom: xmlParseFile failed for file %s", + fname.c_str()); BackendPtr b; return b; } xsp = xsltParseStylesheetDoc(xsp_doc); if (!xsp) { - *error = YAZ_BIB1_DATABASE_DOES_NOT_EXIST; - *addinfo = odr_strdup(odr, "xsltParseStylesheetDoc failed"); + *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR; + *addinfo = (char *) odr_malloc(odr, 50 + fname.length()); + sprintf(*addinfo, "zoom: xsltParseStylesheetDoc failed " + "for file %s", fname.c_str()); BackendPtr b; xmlFreeDoc(xsp_doc); return b; } } + cql_transform_t cqlt = 0; + if (sptr->rpn2cql_fname.length()) + { + char fullpath[1024]; + char *cp = yaz_filepath_resolve(sptr->rpn2cql_fname.c_str(), + m_p->file_path.c_str(), 0, fullpath); + if (cp) + cqlt = cql_transform_open_fname(fullpath); + } + else + cqlt = cql_transform_create(); + + if (!cqlt) + { + *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR; + *addinfo = odr_strdup(odr, "zoom: missing/invalid cql2rpn file"); + BackendPtr b; + xsltFreeStylesheet(xsp); + return b; + } + m_backend.reset(); BackendPtr b(new Backend); + b->cqlt = cqlt; b->sptr = sptr; b->xsp = xsp; b->m_frontend_database = database; @@ -1269,9 +1351,11 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( if (sptr->query_encoding.length()) b->set_option("rpnCharset", sptr->query_encoding); + std::string extraArgs = sptr->extraArgs; + b->set_option("timeout", m_p->zoom_timeout.c_str()); - - if (m_p->apdu_log) + + if (m_p->apdu_log) b->set_option("apdulog", "1"); if (sptr->piggyback && sptr->sru.length()) @@ -1285,7 +1369,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( if (proxy.length() == 0) proxy = sptr->cfProxy; b->m_proxy = proxy; - + if (sptr->cfAuth.length()) { // A CF target @@ -1308,7 +1392,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( out_names[no_out_args] = "user"; out_values[no_out_args++] = odr_strdup(odr, authentication.c_str()); - } + } } if (proxy.length()) { @@ -1328,37 +1412,74 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::get_backend_from_databases( } else { - size_t found = authentication.find('/'); - - if (sptr->sru.length() && found != std::string::npos) - { - b->set_option("user", authentication.substr(0, found)); - b->set_option("password", authentication.substr(found+1)); - } + if (sptr->sru.length() == 0) + b->set_option("user", authentication); /* Z39.50 */ else - b->set_option("user", authentication); + { + std::string user; + std::string password; + std::string authtype = sptr->authenticationMode; + { + const char *cstr = authentication.c_str(); + const char *cp1 = strchr(cstr, '/'); + if (cp1) + { + password.assign(cp1 + 1); + user.assign(cstr, cp1 - cstr); + } + else + user.assign(cstr); + } + + if (authtype.compare("url") == 0) + { + /* SRU URL encoding of auth stuff */ + ODR o = odr_createmem(ODR_ENCODE); + char *path = 0; + const char *names[3]; + const char *values[3]; + + names[0] = "x-username"; + values[0] = user.c_str(); + names[1] = "x-password"; + values[1] = password.c_str(); + names[2] = 0; + values[2] = 0; + + yaz_array_to_uri(&path, o, (char **) names, (char **) values); + if (extraArgs.length()) + extraArgs.append("&"); + extraArgs.append(path); + odr_destroy(o); + } + else + { + b->set_option("user", user); + if (password.length()) + b->set_option("password", password); + } + } if (proxy.length()) b->set_option("proxy", proxy); } - std::string url; + if (extraArgs.length()) + b->set_option("extraArgs", extraArgs); + + std::string url(sptr->target); if (sptr->sru.length()) { - url = "http://" + sptr->target; b->set_option("sru", sptr->sru); - + if (url.find("://") == std::string::npos) + url = "http://" + url; if (sptr->sru_version.length()) b->set_option("sru_version", sptr->sru_version); } - else - { - url = sptr->target; - } if (no_out_args) { char *x_args = 0; out_names[no_out_args] = 0; // terminate list - + yaz_array_to_uri(&x_args, odr, (char **) out_names, (char **) out_values); url += "," + std::string(x_args); @@ -1386,7 +1507,7 @@ void yf::Zoom::Frontend::prepare_elements(BackendPtr b, { char oid_name_str[OID_STR_MAX]; const char *syntax_name = 0; - + if (preferredRecordSyntax && !oid_oidcmp(preferredRecordSyntax, yaz_oid_recsyn_xml)) { @@ -1396,7 +1517,7 @@ void yf::Zoom::Frontend::prepare_elements(BackendPtr b, enable_pz2_retrieval = true; enable_pz2_transform = true; } - else if (element_set_name && + else if (element_set_name && !strcmp(element_set_name, m_p->element_raw.c_str())) { enable_pz2_retrieval = true; @@ -1408,14 +1529,14 @@ void yf::Zoom::Frontend::prepare_elements(BackendPtr b, enable_record_transform = true; } } - + if (enable_pz2_retrieval) { std::string configured_request_syntax = b->sptr->request_syntax; if (configured_request_syntax.length()) { syntax_name = configured_request_syntax.c_str(); - const Odr_oid *syntax_oid = + const Odr_oid *syntax_oid = yaz_string_to_oid(yaz_oid_std(), CLASS_RECSYN, syntax_name); if (!oid_oidcmp(syntax_oid, yaz_oid_recsyn_usmarc) || !oid_oidcmp(syntax_oid, yaz_oid_recsyn_opac)) @@ -1433,9 +1554,15 @@ void yf::Zoom::Frontend::prepare_elements(BackendPtr b, if (enable_pz2_retrieval) { - element_set_name = 0; - if (b->sptr->element_set.length()) - element_set_name = b->sptr->element_set.c_str(); + if (element_set_name && !strcmp(element_set_name, + m_p->element_passthru.c_str())) + ; + else + { + element_set_name = 0; + if (b->sptr->element_set.length()) + element_set_name = b->sptr->element_set.c_str(); + } } b->set_option("elementSetName", element_set_name); @@ -1466,12 +1593,12 @@ Z_Records *yf::Zoom::Frontend::get_explain_records( number_to_present = 10000; xmlNode *ptr = xmlDocGetRootElement(b->explain_doc); - + Z_NamePlusRecordList *npl = (Z_NamePlusRecordList *) odr_malloc(odr, sizeof(*npl)); npl->records = (Z_NamePlusRecord **) odr_malloc(odr, number_to_present * sizeof(*npl->records)); - + for (i = 0; i < number_to_present; i++) { int num = 0; @@ -1534,7 +1661,7 @@ Z_Records *yf::Zoom::Frontend::get_records(mp::Package &package, if (start < 0 || number_to_present <=0) return records; - + if (number_to_present > 10000) number_to_present = 10000; @@ -1555,7 +1682,7 @@ Z_Records *yf::Zoom::Frontend::get_records(mp::Package &package, const char *xsl_parms[3]; mp::wrbuf cproxy_host; - + if (b->enable_cproxy && b->cproxy_host.length()) { wrbuf_puts(cproxy_host, "\""); @@ -1586,7 +1713,7 @@ Z_Records *yf::Zoom::Frontend::get_records(mp::Package &package, int sur_error = ZOOM_record_error(recs[i], 0 /* msg */, &addinfo, 0 /* diagset */); - + if (sur_error) { log_diagnostic(package, sur_error, addinfo); @@ -1644,7 +1771,7 @@ Z_Records *yf::Zoom::Frontend::get_records(mp::Package &package, odr, odr_database, error, addinfo); } else - { + { // first stage XSLT - per target xsltStylesheetPtr xsp = b->xsp; xmlDoc *rec_res = xsltApplyStylesheet(xsp, rec_doc, @@ -1652,7 +1779,7 @@ Z_Records *yf::Zoom::Frontend::get_records(mp::Package &package, // insert generated-url if (rec_res) { - std::string res = + std::string res = mp::xml::url_recipe_handle(rec_res, b->sptr->urlRecipe); if (res.length()) @@ -1660,7 +1787,7 @@ Z_Records *yf::Zoom::Frontend::get_records(mp::Package &package, xmlNode *ptr = xmlDocGetRootElement(rec_res); while (ptr && ptr->type != XML_ELEMENT_NODE) ptr = ptr->next; - xmlNode *c = + xmlNode *c = xmlNewChild(ptr, 0, BAD_CAST "metadata", 0); xmlNewProp(c, BAD_CAST "type", BAD_CAST "generated-url"); @@ -1709,7 +1836,7 @@ Z_Records *yf::Zoom::Frontend::get_records(mp::Package &package, { if (!rec_buf) npr = zget_surrogateDiagRec( - odr, odr_database, + odr, odr_database, YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS, rec_type_str); else @@ -1739,7 +1866,7 @@ Z_Records *yf::Zoom::Frontend::get_records(mp::Package &package, else { npr = zget_surrogateDiagRec( - odr, odr_database, + odr, odr_database, YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS, "ZOOM_record, type ext"); } @@ -1803,6 +1930,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::explain_search(mp::Package &package, int *error, char **addinfo, mp::odr &odr, + std::string torus_url, std::string &torus_db, std::string &realm) { @@ -1812,7 +1940,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::explain_search(mp::Package &package, b->m_frontend_database = database; b->enable_explain = true; - + Z_GDU *gdu = package.request().get(); Z_APDU *apdu_req = gdu->u.z3950; Z_SearchRequest *sr = apdu_req->u.searchRequest; @@ -1829,7 +1957,6 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::explain_search(mp::Package &package, else if (query->which == Z_Query_type_104 && query->u.type_104->which == Z_External_CQL) { - std::string torus_url = m_p->torus_searchable_url; std::string torus_query(query->u.type_104->u.cql); xmlDoc *doc = mp::get_searchable(package, torus_url, "", torus_query, @@ -1851,7 +1978,7 @@ yf::Zoom::BackendPtr yf::Zoom::Frontend::explain_search(mp::Package &package, { xmlNode *ptr = xmlDocGetRootElement(doc); int hits = 0; - + xml_node_search(ptr, &hits, 0); Z_APDU *apdu_res = odr.create_searchResponse(apdu_req, 0, 0); @@ -1884,7 +2011,7 @@ static bool wait_conn(COMSTACK cs, int secs) pfd.fd = cs_fileno(cs); pfd.client_data = 0; - + int ret = yaz_poll(&pfd, 1, secs, 0); return ret > 0; } @@ -1903,12 +2030,12 @@ bool yf::Zoom::Impl::check_proxy(const char *proxy) Z_GDU *gdu = z_get_HTTP_Request_uri(odr, uri, 0, 1); gdu->u.HTTP_Request->method = odr_strdup(odr, "GET"); - + if (z_GDU(odr, &gdu, 0, 0)) { int len; char *buf = odr_getbuf(odr, &len, 0); - + int ret = cs_connect(conn, add); if (ret > 0 || (ret == 0 && wait_conn(conn, 1))) { @@ -1930,7 +2057,7 @@ bool yf::Zoom::Impl::check_proxy(const char *proxy) bool yf::Zoom::Frontend::retry(mp::Package &package, mp::odr &odr, - BackendPtr b, + BackendPtr b, int &error, char **addinfo, int &proxy_step, int &same_retries, int &proxy_retries) @@ -2047,7 +2174,7 @@ next_proxy: error = YAZ_BIB1_MALFORMED_QUERY; const char *addinfo = "CQL syntax error"; log_diagnostic(package, error, addinfo); - apdu_res = + apdu_res = odr.create_searchResponse(apdu_req, error, addinfo); package.response() = apdu_res; return; @@ -2061,15 +2188,14 @@ next_proxy: addinfo = 0; if (cn_error->which == CQL_NODE_ST) addinfo = cn_error->u.st.index; - + log_diagnostic(package, error, addinfo); apdu_res = odr.create_searchResponse(apdu_req, error, addinfo); package.response() = apdu_res; cql_parser_destroy(cp); return; } - char ccl_buf[1024]; - r = cql_to_ccl_buf(cn, ccl_buf, sizeof(ccl_buf)); + r = cql_to_ccl(cn, wrbuf_vp_puts, ccl_wrbuf); if (r) { error = YAZ_BIB1_MALFORMED_QUERY; @@ -2097,13 +2223,11 @@ next_proxy: mp::wrbuf sort_spec_wrbuf; yaz_srw_sortkeys_to_sort_spec(wrbuf_cstr(sru_sortkeys_wrbuf), sort_spec_wrbuf); - wrbuf_puts(ccl_wrbuf, ccl_buf); - yaz_tok_cfg_t tc = yaz_tok_cfg_create(); yaz_tok_parse_t tp = yaz_tok_parse_buf(tc, wrbuf_cstr(sort_spec_wrbuf)); yaz_tok_cfg_destroy(tc); - + /* go through sortspec and map fields */ int token = yaz_tok_move(tp); while (token != YAZ_TOK_EOF) @@ -2160,7 +2284,7 @@ next_proxy: switch (cerror) { case CCL_ERR_UNKNOWN_QUAL: - case CCL_ERR_TRUNC_NOT_LEFT: + case CCL_ERR_TRUNC_NOT_LEFT: case CCL_ERR_TRUNC_NOT_RIGHT: case CCL_ERR_TRUNC_NOT_BOTH: #ifdef CCL_ERR_TRUNC_NOT_EMBED @@ -2181,7 +2305,7 @@ next_proxy: package.log("zoom", YLOG_LOG, "RPN: %s", wrbuf_cstr(pqf_wrbuf)); ccl_rpn_delete(cn); } - + assert(pqf_wrbuf.len()); ZOOM_query q = ZOOM_query_create(); @@ -2193,22 +2317,18 @@ next_proxy: Z_RPNQuery *zquery; zquery = p_query_rpn(odr, wrbuf_cstr(pqf_wrbuf)); mp::wrbuf wrb; - + if (!strcmp(b->get_option("sru"), "solr")) { solr_transform_t cqlt = solr_transform_create(); - + status = solr_transform_rpn2solr_wrbuf(cqlt, wrb, zquery); - + solr_transform_close(cqlt); } else { - cql_transform_t cqlt = cql_transform_create(); - - status = cql_transform_rpn2cql_wrbuf(cqlt, wrb, zquery); - - cql_transform_close(cqlt); + status = cql_transform_rpn2cql_wrbuf(b->cqlt, wrb, zquery); } if (status == 0) { @@ -2217,11 +2337,11 @@ next_proxy: b->search(q, &hits, &error, &addinfo, odr); } ZOOM_query_destroy(q); - + if (status) { error = YAZ_BIB1_MALFORMED_QUERY; - const char *addinfo = "can not convert from RPN to CQL/SOLR"; + const char *addinfo = "can not convert from RPN to CQL/Solr"; log_diagnostic(package, error, addinfo); apdu_res = odr.create_searchResponse(apdu_req, error, addinfo); package.response() = apdu_res; @@ -2247,7 +2367,7 @@ next_proxy: Odr_int number_to_present = 0; if (!error) mp::util::piggyback_sr(sr, hits, number_to_present, &element_set_name); - + Odr_int number_of_records_returned = 0; Z_Records *records = get_records( package, @@ -2286,7 +2406,7 @@ void yf::Zoom::Frontend::handle_present(mp::Package &package) if (comp && comp->which != Z_RecordComp_simple) { package.response() = odr.create_presentResponse( - apdu_req, + apdu_req, YAZ_BIB1_PRESENT_COMP_SPEC_PARAMETER_UNSUPP, 0); return; } @@ -2304,7 +2424,7 @@ void yf::Zoom::Frontend::handle_present(mp::Package &package) *pr->resultSetStartPoint - 1, *pr->numberOfRecordsRequested, &error, &addinfo, &number_of_records_returned, odr, m_backend, pr->preferredRecordSyntax, element_set_name); - + apdu_res = odr.create_presentResponse(apdu_req, error, addinfo); if (records) { @@ -2321,7 +2441,7 @@ void yf::Zoom::Frontend::handle_present(mp::Package &package) *pr->resultSetStartPoint - 1, *pr->numberOfRecordsRequested, &error, &addinfo, &number_of_records_returned, odr, m_backend, pr->preferredRecordSyntax, element_set_name); - + apdu_res = odr.create_presentResponse(apdu_req, error, addinfo); if (records) { @@ -2381,6 +2501,127 @@ void yf::Zoom::Frontend::handle_package(mp::Package &package) } } +std::string escape_cql_term(std::string inp) +{ + std::string res; + size_t l = inp.length(); + size_t i; + for (i = 0; i < l; i++) + { + if (strchr("*?^\"", inp[i])) + res += "\\"; + res += inp[i]; + } + return res; +} + +void yf::Zoom::Frontend::auth(mp::Package &package, Z_InitRequest *req, + int *error, char **addinfo, ODR odr) +{ + if (m_p->torus_auth_url.length() == 0) + return; + + std::string user; + std::string password; + if (req->idAuthentication) + { + Z_IdAuthentication *auth = req->idAuthentication; + switch (auth->which) + { + case Z_IdAuthentication_open: + if (auth->u.open) + { + const char *cp = strchr(auth->u.open, '/'); + if (cp) + { + user.assign(auth->u.open, cp - auth->u.open); + password.assign(cp + 1); + } + } + break; + case Z_IdAuthentication_idPass: + if (auth->u.idPass->userId) + user.assign(auth->u.idPass->userId); + if (auth->u.idPass->password) + password.assign(auth->u.idPass->password); + break; + } + } + + std::string ip = package.origin().get_address(); + yaz_log(YLOG_LOG, "IP=%s", ip.c_str()); + + std::string torus_query; + int failure_code; + + if (user.length() && password.length()) + { + torus_query = "userName==\"" + escape_cql_term(user) + + "\" and password==\"" + escape_cql_term(password) + "\""; + failure_code = YAZ_BIB1_INIT_AC_BAD_USERID_AND_OR_PASSWORD; + } + else + { + const char *ip_cstr = ip.c_str(); + const char *cp = strchr(ip_cstr, ':'); + if (cp) + ip_cstr = cp + 1; + + torus_query = "ip encloses/net.ipaddress \""; + torus_query += escape_cql_term(std::string(ip_cstr)); + torus_query += "\""; + failure_code = YAZ_BIB1_INIT_AC_BLOCKED_NETWORK_ADDRESS; + } + + std::string dummy_db; + std::string dummy_realm; + xmlDoc *doc = mp::get_searchable(package, m_p->torus_auth_url, dummy_db, + torus_query, dummy_realm, m_p->proxy); + if (!doc) + { + // something fundamental broken in lookup. + *error = YAZ_BIB1_TEMPORARY_SYSTEM_ERROR; + *addinfo = odr_strdup(odr, "zoom: torus server unavailable or " + "incorrectly configured."); + return; + } + const xmlNode *ptr = xmlDocGetRootElement(doc); + if (ptr && ptr->type == XML_ELEMENT_NODE) + { + if (strcmp((const char *) ptr->name, "records") == 0) + { + ptr = ptr->children; + while (ptr && ptr->type != XML_ELEMENT_NODE) + ptr = ptr->next; + } + if (ptr && strcmp((const char *) ptr->name, "record") == 0) + { + ptr = ptr->children; + while (ptr && ptr->type != XML_ELEMENT_NODE) + ptr = ptr->next; + } + if (ptr && strcmp((const char *) ptr->name, "layer") == 0) + { + ptr = ptr->children; + while (ptr && ptr->type != XML_ELEMENT_NODE) + ptr = ptr->next; + } + while (ptr) + { + if (ptr && ptr->type == XML_ELEMENT_NODE && + !strcmp((const char *) ptr->name, "identityId")) + break; + ptr = ptr->next; + } + } + if (!ptr) + { + *error = failure_code; + return; + } + session_realm = mp::xml::get_text(ptr); +} + void yf::Zoom::Impl::process(mp::Package &package) { FrontendPtr f = get_frontend(package); @@ -2395,21 +2636,21 @@ void yf::Zoom::Impl::process(mp::Package &package) { Z_InitRequest *req = gdu->u.z3950->u.initRequest; f->m_init_gdu = gdu; - + mp::odr odr; Z_APDU *apdu = odr.create_initResponse(gdu->u.z3950, 0, 0); Z_InitResponse *resp = apdu->u.initResponse; - + int i; static const int masks[] = { Z_Options_search, Z_Options_present, - -1 + -1 }; for (i = 0; masks[i] != -1; i++) if (ODR_MASK_GET(req->options, masks[i])) ODR_MASK_SET(resp->options, masks[i]); - + static const int versions[] = { Z_ProtocolVersion_1, Z_ProtocolVersion_2, @@ -2421,12 +2662,23 @@ void yf::Zoom::Impl::process(mp::Package &package) ODR_MASK_SET(resp->protocolVersion, versions[i]); else break; - + *resp->preferredMessageSize = *req->preferredMessageSize; *resp->maximumRecordSize = *req->maximumRecordSize; - + + int error = 0; + char *addinfo = 0; + f->auth(package, req, &error, &addinfo, odr); + if (error) + { + resp->userInformationField = + zget_init_diagnostics(odr, error, addinfo); + *resp->result = 0; + package.session().close(); + } + else + f->m_is_virtual = true; package.response() = apdu; - f->m_is_virtual = true; } else package.move();