Fix ZOOM HTTP redirect failing on Windows+Solaris YAZ-755
[yaz-moved-to-github.git] / src / zoom-c.c
index b1874ea..b7bb1fe 100644 (file)
@@ -50,6 +50,7 @@ static void initlog(void)
 }
 
 void ZOOM_connection_remove_tasks(ZOOM_connection c);
+static zoom_ret send_HTTP_redirect(ZOOM_connection c, const char *uri);
 
 void ZOOM_set_dset_error(ZOOM_connection c, int error,
                          const char *dset,
@@ -296,11 +297,10 @@ ZOOM_API(ZOOM_connection)
     c->sru_version = 0;
     c->no_redirects = 0;
     c->cookies = 0;
+    c->location = 0;
     c->saveAPDU_wrbuf = 0;
 
-#if HAVE_LIBMEMCACHED_MEMCACHED_H
-    c->mc_st = 0;
-#endif
+    ZOOM_memcached_init(c);
     return c;
 }
 
@@ -363,7 +363,6 @@ ZOOM_API(void)
                             const char *host, int portnum)
 {
     const char *val;
-    const char *http_lead;
 
     initlog();
 
@@ -373,19 +372,6 @@ ZOOM_API(void)
     ZOOM_set_error(c, ZOOM_ERROR_NONE, 0);
     ZOOM_connection_remove_tasks(c);
 
-    if (c->odr_print)
-    {
-        odr_setprint(c->odr_print, 0); /* prevent destroy from fclose'ing */
-        odr_destroy(c->odr_print);
-    }
-    if (ZOOM_options_get_bool(c->options, "apdulog", 0))
-    {
-        c->odr_print = odr_createmem(ODR_PRINT);
-        odr_setprint(c->odr_print, yaz_log_file());
-    }
-    else
-        c->odr_print = 0;
-
     if (c->cs)
     {
         yaz_log(c->log_details, "%p ZOOM_connection_connect reconnect ok", c);
@@ -430,16 +416,18 @@ ZOOM_API(void)
     else
         c->lang = 0;
 
-    val = ZOOM_options_get(c->options, "sru");
-    if (val && *val && !strstr(host, "://"))
-        http_lead = "http://";
-    else
-        http_lead = "";
-    c->sru_mode = get_sru_mode_from_string(val);
-
     if (host)
     {
         char hostn[128];
+        const char *http_lead;
+
+        val = ZOOM_options_get(c->options, "sru");
+        if (val && *val && !strstr(host, "://"))
+            http_lead = "http://";
+        else
+            http_lead = "";
+        c->sru_mode = get_sru_mode_from_string(val);
+
         xfree(c->host_port);
         if (portnum)
         {
@@ -545,29 +533,11 @@ ZOOM_API(void)
     yaz_cookies_destroy(c->cookies);
     c->cookies = yaz_cookies_create();
 
-#if HAVE_LIBMEMCACHED_MEMCACHED_H
-    if (c->mc_st)
+    if (ZOOM_memcached_configure(c))
     {
-        memcached_free(c->mc_st);
-        c->mc_st = 0;
-    }
-#endif
-    val = ZOOM_options_get(c->options, "memcached");
-    if (val && *val)
-    {
-#if HAVE_LIBMEMCACHED_MEMCACHED_H
-        c->mc_st = memcached(val, strlen(val));
-        if (!c->mc_st)
-        {
-            ZOOM_set_error(c, ZOOM_ERROR_MEMCACHED, val);
-            return;
-        }
-#else
-        ZOOM_set_error(c, ZOOM_ERROR_MEMCACHED, "not enabled");
+        ZOOM_connection_remove_tasks(c);
         return;
-#endif
     }
-
     if (c->sru_mode == zoom_sru_error)
     {
         ZOOM_set_error(c, ZOOM_ERROR_UNSUPPORTED_PROTOCOL, val);
@@ -575,6 +545,33 @@ ZOOM_API(void)
         return;
     }
 
+    if (c->odr_print)
+        odr_destroy(c->odr_print);
+    c->odr_print = 0;
+    val = ZOOM_options_get(c->options, "apdufile");
+    if (val)
+    {
+        c->odr_print = odr_createmem(ODR_PRINT);
+        if (strcmp(val, "-"))
+        {
+            FILE *f = fopen(val, "a");
+            if (!f)
+            {
+                WRBUF w = wrbuf_alloc();
+                wrbuf_printf(w, "fopen: %s", val);
+                ZOOM_set_error(c, ZOOM_ERROR_INTERNAL, wrbuf_cstr(w));
+                wrbuf_destroy(w);
+                return;
+            }
+            odr_setprint(c->odr_print, f);
+        }
+    }
+    else if (ZOOM_options_get_bool(c->options, "apdulog", 0))
+    {
+        c->odr_print = odr_createmem(ODR_PRINT);
+        odr_setprint_noclose(c->odr_print, yaz_log_file());
+    }
+
     yaz_log(c->log_details, "%p ZOOM_connection_connect async=%d", c, c->async);
     ZOOM_connection_add_task(c, ZOOM_TASK_CONNECT);
 
@@ -613,10 +610,7 @@ ZOOM_API(void)
         return;
     yaz_log(c->log_api, "%p ZOOM_connection_destroy", c);
 
-#if HAVE_LIBMEMCACHED_MEMCACHED_H
-    if (c->mc_st)
-        memcached_free(c->mc_st);
-#endif
+    ZOOM_memcached_destroy(c);
     if (c->cs)
         cs_close(c->cs);
 
@@ -631,10 +625,7 @@ ZOOM_API(void)
     if (c->odr_save)
         odr_destroy(c->odr_save);
     if (c->odr_print)
-    {
-        odr_setprint(c->odr_print, 0); /* prevent destroy from fclose'ing */
         odr_destroy(c->odr_print);
-    }
     ZOOM_options_destroy(c->options);
     ZOOM_connection_remove_tasks(c);
     ZOOM_connection_remove_events(c);
@@ -650,6 +641,7 @@ ZOOM_API(void)
     xfree(c->group);
     xfree(c->password);
     xfree(c->sru_version);
+    xfree(c->location);
     yaz_cookies_destroy(c->cookies);
     wrbuf_destroy(c->saveAPDU_wrbuf);
     xfree(c);
@@ -709,8 +701,9 @@ ZOOM_resultset ZOOM_resultset_create(void)
     r->connection = 0;
     r->databaseNames = 0;
     r->num_databaseNames = 0;
-    r->facets = 0;
-    r->num_facets = 0;
+    r->req_facets = 0;
+    r->res_facets = 0;
+    r->num_res_facets = 0;
     r->facets_names = 0;
     r->mutex = 0;
     yaz_mutex_create(&r->mutex);
@@ -743,7 +736,6 @@ ZOOM_API(ZOOM_resultset)
     ZOOM_connection_search(ZOOM_connection c, ZOOM_query q)
 {
     ZOOM_resultset r = ZOOM_resultset_create();
-    const char *cp;
     ZOOM_task task;
     int start, count;
     const char *syntax, *elementSetName, *schema;
@@ -754,6 +746,8 @@ ZOOM_API(ZOOM_resultset)
 
     r->options = ZOOM_options_create_with_parent(c->options);
 
+    r->req_facets = odr_strdup_null(r->odr,
+                                    ZOOM_options_get(r->options, "facets"));
     start = ZOOM_options_get_int(r->options, "start", 0);
     count = ZOOM_options_get_int(r->options, "count", 0);
     {
@@ -763,34 +757,16 @@ ZOOM_API(ZOOM_resultset)
                                        (cp != 0 ? "presentChunk": "step"), 0);
     }
     r->piggyback = ZOOM_options_get_bool(r->options, "piggyback", 1);
-    cp = ZOOM_options_get(r->options, "setname");
-    if (cp)
-        r->setname = xstrdup(cp);
-
-    r->databaseNames = ZOOM_connection_get_databases(c, c->options, &r->num_databaseNames,
-                                         r->odr);
-
+    r->setname = odr_strdup_null(r->odr,
+                                 ZOOM_options_get(r->options, "setname"));
+    r->databaseNames = ZOOM_connection_get_databases(c, c->options,
+                                                     &r->num_databaseNames,
+                                                     r->odr);
     r->connection = c;
     r->next = c->resultsets;
     c->resultsets = r;
 
-#if HAVE_LIBMEMCACHED_MEMCACHED_H
-    r->mc_key = wrbuf_alloc();
-    wrbuf_puts(r->mc_key, "0;");
-    wrbuf_puts(r->mc_key, c->host_port);
-    wrbuf_puts(r->mc_key, ";");
-    if (c->user)
-        wrbuf_puts(r->mc_key, c->user);
-    wrbuf_puts(r->mc_key, ";");
-    if (c->group)
-        wrbuf_puts(r->mc_key, c->group);
-    wrbuf_puts(r->mc_key, ";");
-    if (c->password)
-        wrbuf_sha1_puts(r->mc_key, c->password, 1);
-    wrbuf_puts(r->mc_key, ";");
-    wrbuf_sha1_puts(r->mc_key, ZOOM_query_get_query_string(q), 1);
-    wrbuf_puts(r->mc_key, ";");
-#endif
+    ZOOM_memcached_resultset(r, q);
 
     if (c->host_port && c->proto == PROTO_HTTP)
     {
@@ -908,7 +884,6 @@ static void resultset_destroy(ZOOM_resultset r)
         ZOOM_query_destroy(r->query);
         ZOOM_options_destroy(r->options);
         odr_destroy(r->odr);
-        xfree(r->setname);
         yaz_mutex_destroy(&r->mutex);
 #if SHPTR
         YAZ_SHPTR_DEC(r->record_wrbuf, wrbuf_destroy);
@@ -1019,14 +994,14 @@ ZOOM_API(void)
 ZOOM_API(size_t)
     ZOOM_resultset_facets_size(ZOOM_resultset r)
 {
-    return r->num_facets;
+    return r->num_res_facets;
 }
 
 ZOOM_API(ZOOM_facet_field)
     ZOOM_resultset_get_facet_field(ZOOM_resultset r, const char *name)
 {
-    int num = r->num_facets;
-    ZOOM_facet_field *facets = r->facets;
+    int num = r->num_res_facets;
+    ZOOM_facet_field *facets = r->res_facets;
     int i;
     for (i = 0; i < num; i++)
         if (!strcmp(facets[i]->facet_name, name))
@@ -1037,8 +1012,8 @@ ZOOM_API(ZOOM_facet_field)
 ZOOM_API(ZOOM_facet_field)
     ZOOM_resultset_get_facet_field_by_index(ZOOM_resultset r, int idx)
 {
-    int num = r->num_facets;
-    ZOOM_facet_field *facets = r->facets;
+    int num = r->num_res_facets;
+    ZOOM_facet_field *facets = r->res_facets;
     if (idx >= 0 && idx < num)
         return facets[idx];
     return 0;
@@ -1047,7 +1022,7 @@ ZOOM_API(ZOOM_facet_field)
 ZOOM_API(ZOOM_facet_field *)
     ZOOM_resultset_facets(ZOOM_resultset r)
 {
-    return r->facets;
+    return r->res_facets;
 }
 
 ZOOM_API(const char**)
@@ -1103,7 +1078,7 @@ static zoom_ret do_connect_host(ZOOM_connection c, const char *logical_url)
 
     if (c->cs)
         cs_close(c->cs);
-    c->cs = cs_create_host_proxy(logical_url, 0, &add,
+    c->cs = cs_create_host_proxy(logical_url, CS_FLAGS_DNS_NO_BLOCK, &add,
                                  c->tproxy ? c->tproxy : c->proxy);
 
     if (c->cs && c->cs->protocol == PROTO_HTTP)
@@ -1132,7 +1107,11 @@ static zoom_ret do_connect_host(ZOOM_connection c, const char *logical_url)
                 assert(c->tasks->which == ZOOM_TASK_CONNECT);
                 ZOOM_connection_remove_task(c);
                 ZOOM_connection_set_mask(c, 0);
-                ZOOM_connection_exec_task(c);
+
+                if (c->cs && c->location)
+                    send_HTTP_redirect(c, c->location);
+                else
+                    ZOOM_connection_exec_task(c);
             }
             c->state = STATE_ESTABLISHED;
             return zoom_pending;
@@ -1168,7 +1147,7 @@ ZOOM_API(ZOOM_record)
     const char *schema =
         ZOOM_options_get(s->options, "schema");
 
-    return ZOOM_record_cache_lookup(s, pos, syntax, elementSetName, schema);
+    return ZOOM_record_cache_lookup_i(s, pos, syntax, elementSetName, schema);
 }
 
 ZOOM_API(ZOOM_record)
@@ -1537,6 +1516,8 @@ static zoom_ret send_HTTP_redirect(ZOOM_connection c, const char *uri)
         z_HTTP_header_add_basic_auth(c->odr_out, &gdu->u.HTTP_Request->headers,
                                      c->user, c->password);
     }
+    xfree(c->location);
+    c->location = 0;
     return ZOOM_send_GDU(c, gdu);
 }
 
@@ -1600,9 +1581,9 @@ static void handle_http(ZOOM_connection c, Z_HTTP_Response *hres)
             int host_change = 0;
             location = yaz_check_location(c->odr_in, c->host_port,
                                           location, &host_change);
-            if (do_connect_host(c, location) == zoom_complete)
-                return;  /* connect failed.. */
-            send_HTTP_redirect(c, location);
+            xfree(c->location);
+            c->location = xstrdup(location);
+            do_connect_host(c, location);
             return;
         }
     }
@@ -1999,7 +1980,7 @@ static void ZOOM_connection_do_io(ZOOM_connection c, int mask)
             if (c->cs->io_pending & CS_WANT_READ)
                 mask += ZOOM_SELECT_READ;
             ZOOM_connection_set_mask(c, mask);
-            event = ZOOM_Event_create(ZOOM_EVENT_NONE);
+            event = ZOOM_Event_create(ZOOM_EVENT_CONNECT);
             ZOOM_connection_put_event(c, event);
         }
         else if (ret == 0)
@@ -2012,10 +1993,15 @@ static void ZOOM_connection_do_io(ZOOM_connection c, int mask)
             else
             {
                 /* no init request for SRW .. */
-                assert(c->tasks->which == ZOOM_TASK_CONNECT);
-                ZOOM_connection_remove_task(c);
-                ZOOM_connection_set_mask(c, 0);
-                ZOOM_connection_exec_task(c);
+                if (c->tasks->which == ZOOM_TASK_CONNECT)
+                {
+                    ZOOM_connection_remove_task(c);
+                    ZOOM_connection_set_mask(c, 0);
+                }
+                if (c->cs && c->location)
+                    send_HTTP_redirect(c, c->location);
+                else
+                    ZOOM_connection_exec_task(c);
             }
             c->state = STATE_ESTABLISHED;
         }