X-Git-Url: http://git.indexdata.com/?a=blobdiff_plain;f=src%2Fzoom-c.c;h=806cac4c91019108037473145901c3d29f52bd95;hb=e2ee7361cc2ac8d8d00bbf4e74c46a77ccef1911;hp=c579957484be7cb1f998d1056ce902d596e8f12e;hpb=fb276eb339f39e6233de8e7540c4408089e8d3b3;p=yaz-moved-to-github.git diff --git a/src/zoom-c.c b/src/zoom-c.c index c579957..806cac4 100644 --- a/src/zoom-c.c +++ b/src/zoom-c.c @@ -414,6 +414,7 @@ ZOOM_API(ZOOM_connection) c->m_queue_back = 0; c->sru_version = 0; + c->no_redirects = 0; return c; } @@ -789,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); @@ -830,9 +838,11 @@ void ZOOM_resultset_addref(ZOOM_resultset r) { if (r) { + yaz_mutex_enter(r->mutex); (r->refcount)++; yaz_log(log_details, "%p ZOOM_resultset_addref count=%d", r, r->refcount); + yaz_mutex_leave(r->mutex); } } @@ -856,9 +866,10 @@ 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; + r->mutex = 0; + yaz_mutex_create(&r->mutex); return r; } @@ -883,6 +894,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; @@ -911,10 +923,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) { @@ -1048,35 +1062,25 @@ static void resultset_destroy(ZOOM_resultset r) { if (!r) return; + yaz_mutex_enter(r->mutex); (r->refcount)--; yaz_log(log_details, "%p ZOOM_resultset_destroy r=%p count=%d", r, r, r->refcount); if (r->refcount == 0) { + yaz_mutex_leave(r->mutex); + yaz_log(log_details, "%p ZOOM_connection resultset_destroy: Deleting resultset (%p) ", r->connection, 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; - } - } ZOOM_query_destroy(r->query); ZOOM_options_destroy(r->options); odr_destroy(r->odr); xfree(r->setname); xfree(r->schema); + yaz_mutex_destroy(&r->mutex); xfree(r); } + else + yaz_mutex_leave(r->mutex); } ZOOM_API(size_t) @@ -1205,15 +1209,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); @@ -1224,14 +1238,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); @@ -1272,7 +1289,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; } @@ -1722,12 +1739,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); @@ -4113,6 +4130,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; @@ -4120,46 +4194,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) {