X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=src%2Fzoom-c.c;h=c37e64fa359707c8d75548857f31066e01c1e06b;hp=44a56460dc23588aeb8a58530d7faaaf3d163444;hb=8535dd99e47effa0d28f0a4b5f2357b0290bc7df;hpb=5e240678f83361786067bdb9741ad5302b5bc5d7 diff --git a/src/zoom-c.c b/src/zoom-c.c index 44a5646..c37e64f 100644 --- a/src/zoom-c.c +++ b/src/zoom-c.c @@ -349,8 +349,6 @@ void ZOOM_connection_remove_task(ZOOM_connection c) } } -static int ZOOM_connection_exec_task(ZOOM_connection c); - void ZOOM_connection_remove_tasks(ZOOM_connection c) { while (c->tasks) @@ -416,6 +414,7 @@ ZOOM_API(ZOOM_connection) c->m_queue_back = 0; c->sru_version = 0; + c->no_redirects = 0; return c; } @@ -791,14 +790,21 @@ static zoom_ret do_write(ZOOM_connection c); ZOOM_API(void) ZOOM_connection_destroy(ZOOM_connection c) { - ZOOM_resultset r; + ZOOM_resultsets list; if (!c) return; yaz_log(log_api, "%p ZOOM_connection_destroy", c); if (c->cs) cs_close(c->cs); - for (r = c->resultsets; r; r = r->next) - r->connection = 0; + + // Remove the connection's usage of resultsets + list = c->resultsets; + while (list) { + ZOOM_resultsets removed = list; + ZOOM_resultset_destroy(list->resultset); + list = list->next; + xfree(removed); + } xfree(c->buf_in); xfree(c->addinfo); @@ -858,7 +864,6 @@ ZOOM_resultset ZOOM_resultset_create(void) r->r_sort_spec = 0; r->query = 0; r->connection = 0; - r->next = 0; r->databaseNames = 0; r->num_databaseNames = 0; return r; @@ -885,6 +890,7 @@ ZOOM_API(ZOOM_resultset) const char *cp; int start, count; const char *syntax, *elementSetName; + ZOOM_resultsets set; yaz_log(log_api, "%p ZOOM_connection_search set %p query %p", c, r, q); r->r_sort_spec = q->sort_spec; @@ -913,10 +919,12 @@ ZOOM_API(ZOOM_resultset) r->connection = c; - r->next = c->resultsets; - c->resultsets = r; - - + yaz_log(log_details, "%p ZOOM_connection_search: Adding new resultset (%p) to resultsets (%p) ", c, r, c->resultsets); + set = xmalloc(sizeof(*set)); + ZOOM_resultset_addref(r); + set->resultset = r; + set->next = c->resultsets; + c->resultsets = set; if (c->host_port && c->proto == PROTO_HTTP) { @@ -1057,21 +1065,8 @@ static void resultset_destroy(ZOOM_resultset r) { ZOOM_resultset_cache_reset(r); - if (r->connection) - { - /* remove ourselves from the resultsets in connection */ - ZOOM_resultset *rp = &r->connection->resultsets; - while (1) - { - assert(*rp); /* we must be in this list!! */ - if (*rp == r) - { /* OK, we're here - take us out of it */ - *rp = (*rp)->next; - break; - } - rp = &(*rp)->next; - } - } + yaz_log(log_details, "%p ZOOM_connection resultset_destroy: Deleting resultset (%p) ", r->connection, r); + ZOOM_query_destroy(r->query); ZOOM_options_destroy(r->options); odr_destroy(r->odr); @@ -1207,15 +1202,25 @@ static void get_cert(ZOOM_connection c) } } +static zoom_ret do_connect_host(ZOOM_connection c, + const char *effective_host, + const char *logical_url); + static zoom_ret do_connect(ZOOM_connection c) { - void *add; const char *effective_host; if (c->proxy) effective_host = c->proxy; else effective_host = c->host_port; + return do_connect_host(c, effective_host, c->host_port); +} + +static zoom_ret do_connect_host(ZOOM_connection c, const char *effective_host, + const char *logical_url) +{ + void *add; yaz_log(log_details, "%p do_connect effective_host=%s", c, effective_host); @@ -1226,14 +1231,17 @@ static zoom_ret do_connect(ZOOM_connection c) if (c->cs && c->cs->protocol == PROTO_HTTP) { #if YAZ_HAVE_XML2 - const char *db = 0; - - c->proto = PROTO_HTTP; - cs_get_host_args(c->host_port, &db); - xfree(c->path); - - c->path = xmalloc(strlen(db) * 3 + 2); - yaz_encode_sru_dbpath_buf(c->path, db); + if (logical_url) + { + const char *db = 0; + + c->proto = PROTO_HTTP; + cs_get_host_args(logical_url, &db); + xfree(c->path); + + c->path = xmalloc(strlen(db) * 3 + 2); + yaz_encode_sru_dbpath_buf(c->path, db); + } #else set_ZOOM_error(c, ZOOM_ERROR_UNSUPPORTED_PROTOCOL, "SRW"); do_close(c); @@ -1274,7 +1282,7 @@ static zoom_ret do_connect(ZOOM_connection c) } } c->state = STATE_IDLE; - set_ZOOM_error(c, ZOOM_ERROR_CONNECT, c->host_port); + set_ZOOM_error(c, ZOOM_ERROR_CONNECT, logical_url); return zoom_complete; } @@ -1724,12 +1732,12 @@ static zoom_ret ZOOM_connection_send_search(ZOOM_connection c) result sets on the server. */ for (ord = 1; ; ord++) { - ZOOM_resultset rp; + ZOOM_resultsets rsp; sprintf(setname, "%d", ord); - for (rp = c->resultsets; rp; rp = rp->next) - if (rp->setname && !strcmp(rp->setname, setname)) + for (rsp = c->resultsets; rsp; rsp = rsp->next) + if (rsp->resultset->setname && !strcmp(rsp->resultset->setname, setname)) break; - if (!rp) + if (!rsp) break; } r->setname = xstrdup(setname); @@ -2198,7 +2206,7 @@ ZOOM_API(const char *) } else if (!strcmp(type, "txml")) { - return get_record_format(rec, len, npr, YAZ_MARC_TMARCXML, charset, + return get_record_format(rec, len, npr, YAZ_MARC_TURBOMARC, charset, format); } else if (!strcmp(type, "raw")) @@ -2386,7 +2394,10 @@ static void handle_records(ZOOM_connection c, Z_Records *sr, { /* present response and we didn't get any records! */ Z_NamePlusRecord *myrec = - zget_surrogateDiagRec(resultset->odr, 0, 14, 0); + zget_surrogateDiagRec( + resultset->odr, 0, + YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS, + "ZOOM C generated. Present phase and no records"); record_cache_add(resultset, myrec, *start, syntax, elementSetName, 0, 0); } @@ -2395,7 +2406,10 @@ static void handle_records(ZOOM_connection c, Z_Records *sr, { /* present response and we didn't get any records! */ Z_NamePlusRecord *myrec = - zget_surrogateDiagRec(resultset->odr, 0, 14, 0); + zget_surrogateDiagRec( + resultset->odr, 0, + YAZ_BIB1_SYSTEM_ERROR_IN_PRESENTING_RECORDS, + "ZOOM C generated: Present response and no records"); record_cache_add(resultset, myrec, *start, syntax, elementSetName, 0, 0); } @@ -3606,7 +3620,8 @@ ZOOM_API(void) ZOOM_options_setl(p->options, key, val, len); } -static int ZOOM_connection_exec_task(ZOOM_connection c) +ZOOM_API(int) + ZOOM_connection_exec_task(ZOOM_connection c) { ZOOM_task task = c->tasks; zoom_ret ret = zoom_complete; @@ -4108,6 +4123,63 @@ static void handle_srw_scan_response(ZOOM_connection c, #endif #if YAZ_HAVE_XML2 +static Z_GDU *get_HTTP_Request_url(ODR odr, const char *url) +{ + Z_GDU *p = z_get_HTTP_Request(odr); + const char *host = url; + const char *cp0 = strstr(host, "://"); + const char *cp1 = 0; + if (cp0) + cp0 = cp0+3; + else + cp0 = host; + + cp1 = strchr(cp0, '/'); + if (!cp1) + cp1 = cp0 + strlen(cp0); + + if (cp0 && cp1) + { + char *h = (char*) odr_malloc(odr, cp1 - cp0 + 1); + memcpy (h, cp0, cp1 - cp0); + h[cp1-cp0] = '\0'; + z_HTTP_header_add(odr, &p->u.HTTP_Request->headers, "Host", h); + } + p->u.HTTP_Request->path = odr_strdup(odr, *cp1 ? cp1 : "/"); + return p; +} + +static zoom_ret send_SRW_redirect(ZOOM_connection c, const char *uri, + Z_HTTP_Response *cookie_hres) +{ + struct Z_HTTP_Header *h; + Z_GDU *gdu = get_HTTP_Request_url(c->odr_out, uri); + + gdu->u.HTTP_Request->method = odr_strdup(c->odr_out, "GET"); + z_HTTP_header_add(c->odr_out, &gdu->u.HTTP_Request->headers, "Accept", + "text/xml"); + + for (h = cookie_hres->headers; h; h = h->next) + { + if (!strcmp(h->name, "Set-Cookie")) + z_HTTP_header_add(c->odr_out, &gdu->u.HTTP_Request->headers, + "Cookie", h->value); + } + if (c->user && c->password) + { + z_HTTP_header_add_basic_auth(c->odr_out, &gdu->u.HTTP_Request->headers, + c->user, c->password); + } + if (!z_GDU(c->odr_out, &gdu, 0, 0)) + return zoom_complete; + if (c->odr_print) + z_GDU(c->odr_print, &gdu, 0, 0); + c->buf_out = odr_getbuf(c->odr_out, &c->len_out, 0); + + odr_reset(c->odr_out); + return do_write(c); +} + static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres) { zoom_ret cret = zoom_complete; @@ -4115,46 +4187,78 @@ static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres) const char *addinfo = 0; const char *connection_head = z_HTTP_header_lookup(hres->headers, "Connection"); + const char *location; + ZOOM_connection_set_mask(c, 0); yaz_log(log_details, "%p handle_http", c); - if (!yaz_srw_check_content_type(hres)) - addinfo = "content-type"; - else + if ((hres->code == 301 || hres->code == 302) && c->sru_mode == zoom_sru_get + && (location = z_HTTP_header_lookup(hres->headers, "Location"))) { - Z_SOAP *soap_package = 0; - ODR o = c->odr_in; - Z_SOAP_Handler soap_handlers[2] = { - {YAZ_XMLNS_SRU_v1_1, 0, (Z_SOAP_fun) yaz_srw_codec}, - {0, 0, 0} - }; - ret = z_soap_codec(o, &soap_package, - &hres->content_buf, &hres->content_len, - soap_handlers); - if (!ret && soap_package->which == Z_SOAP_generic && - soap_package->u.generic->no == 0) + c->no_redirects++; + if (c->no_redirects > 10) { - Z_SRW_PDU *sr = (Z_SRW_PDU*) soap_package->u.generic->p; - - ZOOM_options_set(c->options, "sru_version", sr->srw_version); - ZOOM_options_setl(c->options, "sru_extra_response_data", - sr->extraResponseData_buf, sr->extraResponseData_len); - if (sr->which == Z_SRW_searchRetrieve_response) - cret = handle_srw_response(c, sr->u.response); - else if (sr->which == Z_SRW_scan_response) - handle_srw_scan_response(c, sr->u.scan_response); - else - ret = -1; + set_HTTP_error(c, hres->code, 0, 0); + c->no_redirects = 0; + do_close(c); } - else if (!ret && (soap_package->which == Z_SOAP_fault - || soap_package->which == Z_SOAP_error)) + else { - set_HTTP_error(c, hres->code, - soap_package->u.fault->fault_code, - soap_package->u.fault->fault_string); + /* since redirect may change host we just reconnect. A smarter + implementation might check whether it's the same server */ + do_connect_host(c, location, 0); + send_SRW_redirect(c, location, hres); + /* we're OK for now. Operation is not really complete */ + ret = 0; + cret = zoom_pending; } + } + else + { /* not redirect (normal response) */ + if (!yaz_srw_check_content_type(hres)) + addinfo = "content-type"; else - ret = -1; + { + Z_SOAP *soap_package = 0; + ODR o = c->odr_in; + Z_SOAP_Handler soap_handlers[2] = { + {YAZ_XMLNS_SRU_v1_1, 0, (Z_SOAP_fun) yaz_srw_codec}, + {0, 0, 0} + }; + ret = z_soap_codec(o, &soap_package, + &hres->content_buf, &hres->content_len, + soap_handlers); + if (!ret && soap_package->which == Z_SOAP_generic && + soap_package->u.generic->no == 0) + { + Z_SRW_PDU *sr = (Z_SRW_PDU*) soap_package->u.generic->p; + + ZOOM_options_set(c->options, "sru_version", sr->srw_version); + ZOOM_options_setl(c->options, "sru_extra_response_data", + sr->extraResponseData_buf, sr->extraResponseData_len); + if (sr->which == Z_SRW_searchRetrieve_response) + cret = handle_srw_response(c, sr->u.response); + else if (sr->which == Z_SRW_scan_response) + handle_srw_scan_response(c, sr->u.scan_response); + else + ret = -1; + } + else if (!ret && (soap_package->which == Z_SOAP_fault + || soap_package->which == Z_SOAP_error)) + { + set_HTTP_error(c, hres->code, + soap_package->u.fault->fault_code, + soap_package->u.fault->fault_string); + } + else + ret = -1; + } + if (ret == 0) + { + if (c->no_redirects) /* end of redirect. change hosts again */ + do_close(c); + } + c->no_redirects = 0; } if (ret) {