#include <yaz/cql.h>
#include <yaz/log.h>
#include <yaz/facet.h>
+#include <yaz/cookie.h>
#if HAVE_READLINE_READLINE_H
#include <readline/readline.h>
static Odr_int last_hit_count = 0;
static int pretty_xml = 0;
static Odr_int sru_maximumRecords = 0;
+static yaz_cookies_t yaz_cookies = 0;
typedef enum {
QueryType_Prefix,
int r;
const char *basep = 0;
+ yaz_cookies_destroy(yaz_cookies);
+ yaz_cookies = yaz_cookies_create();
+
r = session_connect_base(arg, &basep);
if (basep && *basep)
set_base(basep);
return send_srw_host_path(sr, cur_host, path);
}
-static int send_SRW_redirect(const char *uri, Z_HTTP_Response *cookie_hres)
+static int send_SRW_redirect(const char *uri)
{
const char *username = 0;
const char *password = 0;
- struct Z_HTTP_Header *h;
- char *combined_cookies = 0;
- int combined_cookies_len = 0;
Z_GDU *gdu = get_HTTP_Request_url(out, uri);
gdu->u.HTTP_Request->method = odr_strdup(out, "GET");
z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers, "Accept",
"text/xml");
- for (h = cookie_hres->headers; h; h = h->next)
- {
- if (!strcmp(h->name, "Set-Cookie"))
- {
- char *cp;
-
- if (!(cp = strchr(h->value, ';')))
- cp = h->value + strlen(h->value);
- if (cp - h->value >= 1)
- {
- combined_cookies = xrealloc(combined_cookies, combined_cookies_len + cp - h->value + 3);
- memcpy(combined_cookies+combined_cookies_len, h->value, cp - h->value);
- combined_cookies[combined_cookies_len + cp - h->value] = '\0';
- strcat(combined_cookies,"; ");
- combined_cookies_len = strlen(combined_cookies);
- }
- }
- }
- if (combined_cookies_len)
- {
- z_HTTP_header_add(out, &gdu->u.HTTP_Request->headers, "Cookie", combined_cookies);
- xfree(combined_cookies);
- }
-
+ yaz_cookies_request(yaz_cookies, out, gdu->u.HTTP_Request);
if (auth)
{
if (auth->which == Z_IdAuthentication_open)
static void exit_client(int code)
{
+ yaz_cookies_destroy(yaz_cookies);
file_history_save(file_history);
file_history_destroy(&file_history);
nmem_destroy(nmem_auth);
}
#endif
-#define max_HTTP_redirects 2
+#define max_HTTP_redirects 3
static void wait_and_handle_response(int one_response_only)
{
Z_HTTP_Response *hres = gdu->u.HTTP_Response;
int code = hres->code;
const char *location = 0;
+
+ yaz_cookies_response(yaz_cookies, hres);
if ((code == 301 || code == 302)
&& no_redirects < max_HTTP_redirects
&& !yaz_matchstr(sru_method, "get")
&& (location = z_HTTP_header_lookup(hres->headers, "Location")))
{
const char *base_tmp;
- session_connect_base(location, &base_tmp);
+
+ if (*location == '/')
+ {
+ char *args = 0;
+ char *nlocation = odr_malloc(in, strlen(location)
+ + strlen(cur_host) + 3);
+ strcpy(nlocation, cur_host);
+ cs_get_host_args(nlocation, (const char **) &args);
+ if (!args || !*args)
+ args = nlocation + strlen(nlocation);
+ else
+ args--;
+ strcpy(args, location);
+ location = nlocation;
+ }
+ else
+ {
+ session_connect_base(location, &base_tmp);
+ }
no_redirects++;
if (conn)
{
- if (send_SRW_redirect(location, hres) == 2)
+ if (send_SRW_redirect(location) == 2)
continue;
}
printf("Redirect failed\n");
noinst_HEADERS = icu_I18N.h
pkginclude_HEADERS= backend.h base64.h \
- ccl.h ccl_xml.h cql.h rpn2cql.h rpn2solr.h \
+ ccl.h ccl_xml.h cookie.h cql.h rpn2cql.h rpn2solr.h \
solr.h comstack.h \
diagbib1.h diagsrw.h diagsru_update.h sortspec.h log.h logrpn.h marcdisp.h \
nmem.h nmem_xml.h odr.h errno.h facet.h \
--- /dev/null
+/* This file is part of the YAZ toolkit.
+ * Copyright (C) Index Data.
+ * All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Index Data nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file cookie.h
+ * \brief HTTP cookie handling
+ */
+
+#ifndef YAZ_COOKIE_H
+#define YAZ_COOKIE_H
+
+#include <yaz/zgdu.h>
+
+YAZ_BEGIN_CDECL
+
+typedef struct yaz_cookies_s *yaz_cookies_t;
+
+YAZ_EXPORT yaz_cookies_t yaz_cookies_create(void);
+
+YAZ_EXPORT void yaz_cookies_destroy(yaz_cookies_t yt);
+
+YAZ_EXPORT void yaz_cookies_response(yaz_cookies_t yc, Z_HTTP_Response *res);
+
+YAZ_EXPORT void yaz_cookies_request(yaz_cookies_t yc, ODR odr,
+ Z_HTTP_Request *req);
+
+YAZ_END_CDECL
+
+#endif
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
libyaz_la_SOURCES=base64.c version.c options.c log.c \
$(GEN_FILES) \
- marcdisp.c \
+ cookie.c marcdisp.c \
marc_read_json.c marc_read_xml.c marc_read_iso2709.c marc_read_line.c \
wrbuf.c oid_db.c errno.c \
nmemsdup.c xmalloc.c readconf.c tpath.c nmem.c matchstr.c atoin.c \
--- /dev/null
+/* This file is part of the YAZ toolkit.
+ * Copyright (C) Index Data
+ * See the file LICENSE for details.
+ */
+/**
+ * \file cookie.c
+ * \brief HTTP cookie utility
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <yaz/cookie.h>
+#include <yaz/log.h>
+
+struct cookie {
+ char *name;
+ char *value;
+ char *path;
+ char *domain;
+ struct cookie *next;
+};
+
+struct yaz_cookies_s {
+ struct cookie *list;
+};
+
+yaz_cookies_t yaz_cookies_create(void)
+{
+ yaz_cookies_t yc = xmalloc(sizeof(*yc));
+ yc->list = 0;
+ return yc;
+}
+
+void yaz_cookies_destroy(yaz_cookies_t yc)
+{
+ if (yc)
+ {
+ struct cookie *c = yc->list;
+ while (c)
+ {
+ struct cookie *c1 = c->next;
+ xfree(c->name);
+ xfree(c->value);
+ xfree(c->path);
+ xfree(c->domain);
+ xfree(c);
+ c = c1;
+ }
+ xfree(yc);
+ }
+}
+
+void yaz_cookies_response(yaz_cookies_t yc, Z_HTTP_Response *res)
+{
+ struct Z_HTTP_Header *h;
+ for (h = res->headers; h; h = h->next)
+ {
+ if (!strcmp(h->name, "Set-Cookie"))
+ {
+ const char *cp;
+ const char *cp1;
+ size_t len;
+ struct cookie *c;
+ cp = strchr(h->value, '=');
+ if (!cp)
+ continue;
+ len = cp - h->value;
+ for (c = yc->list; c; c = c->next)
+ if (!strncmp(h->value, c->name, len) && c->name[len] == '\0')
+ break;
+ if (!c)
+ {
+ c = xmalloc(sizeof(*c));
+ c->name = xstrndup(h->value, len);
+ c->value = 0;
+ c->path = 0;
+ c->domain = 0;
+ c->next = yc->list;
+ yc->list = c;
+ }
+ cp++; /* skip = */
+ cp1 = strchr(cp, ';');
+ if (!cp1)
+ cp1 = cp + strlen(cp);
+ xfree(c->value);
+ c->value = xstrndup(cp, cp1 - cp);
+ }
+ }
+}
+
+void yaz_cookies_request(yaz_cookies_t yc, ODR odr, Z_HTTP_Request *req)
+{
+ struct cookie *c;
+ size_t sz = 0;
+
+ for (c = yc->list; c; c = c->next)
+ {
+ if (c->name && c->value)
+ sz += strlen(c->name) + strlen(c->value) + 3;
+ }
+ if (sz)
+ {
+ char *buf = odr_malloc(odr, sz + 1);
+
+ *buf = '\0';
+ for (c = yc->list; c; c = c->next)
+ {
+ if (*buf)
+ strcat(buf, "; ");
+ strcat(buf, c->name);
+ strcat(buf, "=");
+ strcat(buf, c->value);
+ }
+ z_HTTP_header_add(odr, &req->headers, "Cookie", buf);
+ }
+}
+
+/*
+ * Local variables:
+ * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
+ * indent-tabs-mode: nil
+ * End:
+ * vim: shiftwidth=4 tabstop=8 expandtab
+ */
+
c->sru_version = 0;
c->no_redirects = 0;
+ c->cookies = 0;
c->saveAPDU_wrbuf = 0;
return c;
}
c->async = ZOOM_options_get_bool(c->options, "async", 0);
+ yaz_cookies_destroy(c->cookies);
+ c->cookies = yaz_cookies_create();
+
if (c->sru_mode == zoom_sru_error)
{
ZOOM_set_error(c, ZOOM_ERROR_UNSUPPORTED_PROTOCOL, val);
xfree(c->group);
xfree(c->password);
xfree(c->sru_version);
+ yaz_cookies_destroy(c->cookies);
wrbuf_destroy(c->saveAPDU_wrbuf);
xfree(c);
}
#if YAZ_HAVE_XML2
-static zoom_ret send_HTTP_redirect(ZOOM_connection c, const char *uri,
- Z_HTTP_Response *cookie_hres)
+static zoom_ret send_HTTP_redirect(ZOOM_connection c, const char *uri)
{
- struct Z_HTTP_Header *h;
- char *combined_cookies = 0;
- int combined_cookies_len = 0;
Z_GDU *gdu = z_get_HTTP_Request_uri(c->odr_out, uri, 0, c->proxy ? 1 : 0);
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"))
- {
- char *cp;
-
- if (!(cp = strchr(h->value, ';')))
- cp = h->value + strlen(h->value);
- if (cp - h->value >= 1) {
- combined_cookies = xrealloc(combined_cookies, combined_cookies_len + cp - h->value + 3);
- memcpy(combined_cookies+combined_cookies_len, h->value, cp - h->value);
- combined_cookies[combined_cookies_len + cp - h->value] = '\0';
- strcat(combined_cookies,"; ");
- combined_cookies_len = strlen(combined_cookies);
- }
- }
- }
-
- if (combined_cookies_len)
- {
- z_HTTP_header_add(c->odr_out, &gdu->u.HTTP_Request->headers,
- "Cookie", combined_cookies);
- xfree(combined_cookies);
- }
-
+ yaz_cookies_request(c->cookies, c->odr_out, gdu->u.HTTP_Request);
if (c->user && c->password)
{
z_HTTP_header_add_basic_auth(c->odr_out, &gdu->u.HTTP_Request->headers,
ZOOM_connection_set_mask(c, 0);
yaz_log(c->log_details, "%p handle_http", c);
+ yaz_cookies_response(c->cookies, hres);
if ((hres->code == 301 || hres->code == 302) && c->sru_mode == zoom_sru_get
&& (location = z_HTTP_header_lookup(hres->headers, "Location")))
{
{
/* since redirect may change host we just reconnect. A smarter
implementation might check whether it's the same server */
- do_connect_host(c, location);
- send_HTTP_redirect(c, location, hres);
- /* we're OK for now. Operation is not really complete */
+ if (*location != '/')
+ {
+ /* full header */
+ do_connect_host(c, location);
+ send_HTTP_redirect(c, location);
+ }
+ else
+ { /* relative header - same host */
+ char *args = 0;
+ char *nlocation = odr_malloc(c->odr_in, strlen(location)
+ + strlen(c->host_port) + 3);
+ strcpy(nlocation, c->host_port);
+ cs_get_host_args(nlocation, (const char **) &args);
+ if (!args || !*args)
+ args = nlocation + strlen(nlocation);
+ else
+ args--;
+ strcpy(args, location);
+ send_HTTP_redirect(c, nlocation);
+ }
return;
}
}
#include <yaz/wrbuf.h>
#include <yaz/zoom.h>
#include <yaz/srw.h>
+#include <yaz/cookie.h>
#include <yaz/mutex.h>
#define SHPTR 1
ZOOM_Event m_queue_back;
zoom_sru_mode sru_mode;
int no_redirects; /* 0 for no redirects. >0 for number of redirects */
+ yaz_cookies_t cookies;
int log_details;
int log_api;
$(OBJDIR)\xmlquery.obj \
$(OBJDIR)\xmlerror.obj \
$(OBJDIR)\mime.obj \
+ $(OBJDIR)\cookie.obj \
$(OBJDIR)\cql.obj \
$(OBJDIR)\cql2ccl.obj \
$(OBJDIR)\cql_sortkeys.obj \