void yf::HttpRewrite1::Rep::rewrite_response(mp::odr &o, Z_HTTP_Response *hres)
{
    const char *ctype = z_HTTP_header_lookup(hres->headers, "Content-Type");
    if (ctype && hres->content_buf)
    {
        std::string text(hres->content_buf, hres->content_len);
        std::list<Rule>::const_iterator it;
        int number_of_replaces = 0;
        for (it = rules.begin(); it != rules.end(); it++)
        {
            if (strcmp(ctype, it->content_type.c_str()) == 0)
            {
                boost::regex::flag_type b_mode = boost::regex::perl;
                if (it->mode.find_first_of('i') != std::string::npos)
                    b_mode |= boost::regex::icase;
                boost::regex e(it->pattern, b_mode);
                boost::match_flag_type match_mode = boost::format_first_only;
                if (it->mode.find_first_of('g') != std::string::npos)
                    match_mode = boost::format_all;
                text = regex_replace(text, e, it->replacement, match_mode);
                number_of_replaces++;
            }
        }
        if (number_of_replaces > 0)
        {
            hres->content_buf = odr_strdup(o, text.c_str());
            hres->content_len = strlen(hres->content_buf);
        }
    }
}
Esempio n. 2
0
int yaz_srw_check_content_type(Z_HTTP_Response *hres)
{
    const char *content_type = z_HTTP_header_lookup(hres->headers,
                                                    "Content-Type");
    if (content_type)
    {
        if (!yaz_strcmp_del("text/xml", content_type, "; "))
            return 1;
        if (!yaz_strcmp_del("application/xml", content_type, "; "))
            return 1;
    }
    return 0;
}
Esempio n. 3
0
File: http.c Progetto: nla/yaz
int yaz_encode_http_request(ODR o, Z_HTTP_Request *hr)
{
    Z_HTTP_Header *h;
    int top0 = o->top;

    odr_write(o, (unsigned char *) hr->method,
              strlen(hr->method));
    odr_write(o, (unsigned char *) " ", 1);
    odr_write(o, (unsigned char *) hr->path,
              strlen(hr->path));
    odr_write(o, (unsigned char *) " HTTP/", 6);
    odr_write(o, (unsigned char *) hr->version,
              strlen(hr->version));
    odr_write(o, (unsigned char *) "\r\n", 2);
    if (hr->content_len &&
        !z_HTTP_header_lookup(hr->headers,
                              "Content-Length"))
    {
        char lstr[60];
        sprintf(lstr, "Content-Length: %d\r\n",
                hr->content_len);
        odr_write(o, (unsigned char *) lstr, strlen(lstr));
    }
    for (h = hr->headers; h; h = h->next)
    {
        odr_write(o, (unsigned char *) h->name, strlen(h->name));
        odr_write(o, (unsigned char *) ": ", 2);
        odr_write(o, (unsigned char *) h->value, strlen(h->value));
        odr_write(o, (unsigned char *) "\r\n", 2);
    }
    odr_write(o, (unsigned char *) "\r\n", 2);
    if (hr->content_buf)
        odr_write(o, (unsigned char *)
                  hr->content_buf,
                  hr->content_len);
    if (o->direction == ODR_PRINT)
    {
        odr_printf(o, "-- HTTP request:\n%.*s\n", o->top - top0,
                   o->buf + top0);
        odr_printf(o, "-- \n");
    }
    return 1;
}
Esempio n. 4
0
File: http.c Progetto: nla/yaz
int yaz_encode_http_response(ODR o, Z_HTTP_Response *hr)
{
    char sbuf[80];
    Z_HTTP_Header *h;
    int top0 = o->top;

    sprintf(sbuf, "HTTP/%s %d %s\r\n", hr->version,
            hr->code,
            z_HTTP_errmsg(hr->code));
    odr_write(o, (unsigned char *) sbuf, strlen(sbuf));
    /* apply Content-Length if not already applied */
    if (!z_HTTP_header_lookup(hr->headers,
                              "Content-Length"))
    {
        char lstr[60];
        sprintf(lstr, "Content-Length: %d\r\n",
                hr->content_len);
        odr_write(o, (unsigned char *) lstr, strlen(lstr));
    }
    for (h = hr->headers; h; h = h->next)
    {
        odr_write(o, (unsigned char *) h->name, strlen(h->name));
        odr_write(o, (unsigned char *) ": ", 2);
        odr_write(o, (unsigned char *) h->value, strlen(h->value));
        odr_write(o, (unsigned char *) "\r\n", 2);
    }
    odr_write(o, (unsigned char *) "\r\n", 2);
    if (hr->content_buf)
        odr_write(o, (unsigned char *)
                  hr->content_buf,
                  hr->content_len);
    if (o->direction == ODR_PRINT)
    {
        odr_printf(o, "-- HTTP response:\n%.*s\n", o->top - top0,
                   o->buf + top0);
        odr_printf(o, "-- \n");
    }
    return 1;
}
Esempio n. 5
0
/**
 * Look for authentication tokens in HTTP Basic parameters or in x-username/x-password
 * parameters. Added by SH.
 */
static void yaz_srw_decodeauth(Z_SRW_PDU *sr, Z_HTTP_Request *hreq,
                               char *username, char *password, ODR decode)
{
    const char *basic = z_HTTP_header_lookup(hreq->headers, "Authorization");

    if (username)
        sr->username = username;
    if (password)
        sr->password = password;

    if (basic)
    {
        int len;
        char out[256];
        char ubuf[256] = "", pbuf[256] = "", *p;
        if (strncmp(basic, "Basic ", 6))
            return;
        basic += 6;
        len = strlen(basic);
        if (!len || len > 256)
            return;
        yaz_base64decode(basic, out);
        /* Format of out should be username:password at this point */
        strcpy(ubuf, out);
        if ((p = strchr(ubuf, ':')))
        {
            *(p++) = '\0';
            if (*p)
                strcpy(pbuf, p);
        }
        if (*ubuf)
            sr->username = odr_strdup(decode, ubuf);
        if (*pbuf)
            sr->password = odr_strdup(decode, pbuf);
    }
}
Esempio n. 6
0
/**
   http://www.loc.gov/z3950/agency/zing/srw/service.html
*/
int yaz_sru_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
                   Z_SOAP **soap_package, ODR decode, char **charset,
                   Z_SRW_diagnostic **diag, int *num_diag)
{
#if YAZ_HAVE_XML2
    static Z_SOAP_Handler soap_handlers[2] = {
        {YAZ_XMLNS_SRU_v1_1, 0, (Z_SOAP_fun) yaz_srw_codec},
        {0, 0, 0}
    };
#endif
    const char *content_type = z_HTTP_header_lookup(hreq->headers,
                                                    "Content-Type");

    /*
      SRU GET: ignore content type.
      SRU POST: we support "application/x-www-form-urlencoded";
      not  "multipart/form-data" .
    */
    if (!strcmp(hreq->method, "GET")
        ||
        (!strcmp(hreq->method, "POST") && content_type &&
         !yaz_strcmp_del("application/x-www-form-urlencoded",
                         content_type, "; ")))
    {
        char *db = "Default";
        const char *p0 = hreq->path, *p1;
#if YAZ_HAVE_XML2
        const char *operation = 0;
        char *version = 0;
        char *query = 0;
        char *queryType = "cql";
        char *username = 0;
        char *password = 0;
        char *sortKeys = 0;
        char *stylesheet = 0;
        char *scanClause = 0;
        char *recordXPath = 0;
        char *recordSchema = 0;
        char *recordXMLEscaping = 0;
        char *recordPacking = 0;
        char *maximumRecords = 0;
        char *startRecord = 0;
        char *maximumTerms = 0;
        char *responsePosition = 0;
        const char *facetLimit = 0;
        const char *facetStart = 0;
        const char *facetSort = 0;
        Z_SRW_extra_arg *extra_args = 0;
#endif
        char **uri_name;
        char **uri_val;

        grab_charset(decode, content_type, charset);
        if (charset && *charset == 0 && !strcmp(hreq->method, "GET"))
            *charset = "UTF-8";

        if (*p0 == '/')
            p0++;
        p1 = strchr(p0, '?');
        if (!p1)
            p1 = p0 + strlen(p0);
        if (p1 != p0)
            db = yaz_decode_sru_dbpath_odr(decode, p0, p1 - p0);
        if (!strcmp(hreq->method, "POST"))
            p1 = hreq->content_buf;
        yaz_uri_to_array(p1, decode, &uri_name, &uri_val);
#if YAZ_HAVE_XML2
        if (uri_name)
        {
            int i;
            for (i = 0; uri_name[i]; i++)
            {
                char *n = uri_name[i];
                char *v = uri_val[i];
                if (!strcmp(n, "query"))
                    query = v;
                else if (!strcmp(n, "x-pquery"))
                {
                    query = v;
                    queryType = "pqf";
                }
                else if (!strcmp(n, "queryType"))
                    queryType = v;
                else if (!strcmp(n, "x-username"))
                    username = v;
                else if (!strcmp(n, "x-password"))
                    password = v;
                else if (!strcmp(n, "operation"))
                    operation = v;
                else if (!strcmp(n, "stylesheet"))
                    stylesheet = v;
                else if (!strcmp(n, "sortKeys"))
                    sortKeys = v;
                else if (!strcmp(n, "recordXPath"))
                    recordXPath = v;
                else if (!strcmp(n, "recordSchema"))
                    recordSchema = v;
                else if (!strcmp(n, "recordPacking"))
                    recordPacking = v;
                else if (!strcmp(n, "recordXMLEscaping"))
                    recordXMLEscaping = v;
                else if (!strcmp(n, "version"))
                    version = v;
                else if (!strcmp(n, "scanClause"))
                    scanClause = v;
                else if (!strcmp(n, "x-pScanClause"))
                {
                    scanClause = v;
                    queryType = "pqf";
                }
                else if (!strcmp(n, "maximumRecords"))
                    maximumRecords = v;
                else if (!strcmp(n, "startRecord"))
                    startRecord = v;
                else if (!strcmp(n, "maximumTerms"))
                    maximumTerms = v;
                else if (!strcmp(n, "responsePosition"))
                    responsePosition = v;
                else if (!strcmp(n, "facetLimit"))
                    facetLimit = v;
                else if (!strcmp(n, "facetStart"))
                    facetStart = v;
                else if (!strcmp(n, "facetSort"))
                    facetSort = v;
                else if (!strcmp(n, "extraRequestData"))
                    ; /* ignoring extraRequestData */
                else if (n[0] == 'x' && n[1] == '-')
                {
                    append_extra_arg(decode, &extra_args, n, v);
                }
                else
                {
                    if (*num_diag < 10)
                        yaz_add_srw_diagnostic(decode, diag, num_diag,
                                               YAZ_SRW_UNSUPP_PARAMETER, n);
                }
            }
        }
        if (!operation)
        {
            if (query)
                operation = "searchRetrieve";
            else if (scanClause)
                operation = "scan";
            else
                operation = "explain";
        }
        version = yaz_negotiate_sru_version(version);

        if (!version)
        {   /* negotiation failed. */
            yaz_add_srw_diagnostic(decode, diag, num_diag,
                                   YAZ_SRW_UNSUPP_VERSION, "2.0");
            version = "2.0";
        }
        if (!operation)
        {
            if (uri_name)
                yaz_add_srw_diagnostic(
                    decode, diag, num_diag,
                    YAZ_SRW_MANDATORY_PARAMETER_NOT_SUPPLIED, "operation");
            operation = "explain";
        }
        if (strcmp(version, "2.0"))
        {
            if (recordXMLEscaping)
            {
                yaz_add_srw_diagnostic(decode, diag, num_diag,
                                       YAZ_SRW_UNSUPP_PARAMETER,
                                       "recordXMLEscaping");

            }
            recordXMLEscaping = recordPacking;
            recordPacking = "packed";
        }
        if (!recordXMLEscaping)
            recordXMLEscaping = "xml";
        if (!strcmp(operation, "searchRetrieve"))
        {
            Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_searchRetrieve_request);

            sr->srw_version = version;
            sr->extra_args = extra_args;
            *srw_pdu = sr;
            yaz_srw_decodeauth(sr, hreq, username, password, decode);

            sr->u.request->queryType = queryType;
            sr->u.request->query = query;

            if (!query)
                yaz_add_srw_diagnostic(
                    decode, diag, num_diag,
                    YAZ_SRW_MANDATORY_PARAMETER_NOT_SUPPLIED, "query");

            if (sortKeys)
            {
                sr->u.request->sort_type = Z_SRW_sort_type_sort;
                sr->u.request->sort.sortKeys = sortKeys;
            }
            sr->u.request->recordXPath = recordXPath;
            sr->u.request->recordSchema = recordSchema;
            sr->u.request->recordPacking = recordXMLEscaping;
            sr->u.request->packing = recordPacking;
            sr->u.request->stylesheet = stylesheet;
            yaz_sru_facet_request(decode , &sr->u.request->facetList,
                                  &facetLimit, &facetStart, &facetSort);

            yaz_sru_decode_integer(decode, "maximumRecords", maximumRecords,
                                   &sr->u.request->maximumRecords,
                                   diag, num_diag, 0);

            yaz_sru_decode_integer(decode, "startRecord", startRecord,
                                   &sr->u.request->startRecord,
                                   diag, num_diag, 1);

            sr->u.request->database = db;

            (*soap_package) = (Z_SOAP *)
                odr_malloc(decode, sizeof(**soap_package));
            (*soap_package)->which = Z_SOAP_generic;

            (*soap_package)->u.generic = (Z_SOAP_Generic *)
                odr_malloc(decode, sizeof(*(*soap_package)->u.generic));

            (*soap_package)->u.generic->p = sr;
            (*soap_package)->u.generic->ns = soap_handlers[0].ns;
            (*soap_package)->u.generic->no = 0;

            (*soap_package)->ns = "SRU";

            return 0;
        }
        else if (!strcmp(operation, "explain"))
        {
            /* Transfer SRU explain parameters to common struct */
            /* http://www.loc.gov/z3950/agency/zing/srw/explain.html */
            Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);

            sr->srw_version = version;
            sr->extra_args = extra_args;
            yaz_srw_decodeauth(sr, hreq, username, password, decode);
            *srw_pdu = sr;
            sr->u.explain_request->recordPacking = recordXMLEscaping;
            sr->u.explain_request->packing = recordPacking;
            sr->u.explain_request->database = db;

            sr->u.explain_request->stylesheet = stylesheet;

            (*soap_package) = (Z_SOAP *)
                odr_malloc(decode, sizeof(**soap_package));
            (*soap_package)->which = Z_SOAP_generic;

            (*soap_package)->u.generic = (Z_SOAP_Generic *)
                odr_malloc(decode, sizeof(*(*soap_package)->u.generic));

            (*soap_package)->u.generic->p = sr;
            (*soap_package)->u.generic->ns = soap_handlers[0].ns;
            (*soap_package)->u.generic->no = 0;

            (*soap_package)->ns = "SRU";

            return 0;
        }
        else if (!strcmp(operation, "scan"))
        {
            /* Transfer SRU scan parameters to common struct */
            /* http://www.loc.gov/z3950/agency/zing/srw/scan.html */
            Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_scan_request);

            sr->srw_version = version;
            sr->extra_args = extra_args;
            *srw_pdu = sr;
            yaz_srw_decodeauth(sr, hreq, username, password, decode);

            sr->u.scan_request->queryType = queryType;
            sr->u.scan_request->scanClause = scanClause;

            if (!scanClause)
                yaz_add_srw_diagnostic(
                    decode, diag, num_diag,
                    YAZ_SRW_MANDATORY_PARAMETER_NOT_SUPPLIED, "scanClause");
            sr->u.scan_request->database = db;

            yaz_sru_decode_integer(decode, "maximumTerms",
                                   maximumTerms,
                                   &sr->u.scan_request->maximumTerms,
                                   diag, num_diag, 0);

            yaz_sru_decode_integer(decode, "responsePosition",
                                   responsePosition,
                                   &sr->u.scan_request->responsePosition,
                                   diag, num_diag, 0);

            sr->u.scan_request->stylesheet = stylesheet;

            (*soap_package) = (Z_SOAP *)
                odr_malloc(decode, sizeof(**soap_package));
            (*soap_package)->which = Z_SOAP_generic;

            (*soap_package)->u.generic = (Z_SOAP_Generic *)
                odr_malloc(decode, sizeof(*(*soap_package)->u.generic));

            (*soap_package)->u.generic->p = sr;
            (*soap_package)->u.generic->ns = soap_handlers[0].ns;
            (*soap_package)->u.generic->no = 0;

            (*soap_package)->ns = "SRU";

            return 0;
        }
        else
        {
            /* unsupported operation ... */
            /* Act as if we received a explain request and throw diagnostic. */

            Z_SRW_PDU *sr = yaz_srw_get(decode, Z_SRW_explain_request);

            sr->srw_version = version;
            *srw_pdu = sr;
            sr->u.explain_request->recordPacking = recordPacking;
            sr->u.explain_request->database = db;

            sr->u.explain_request->stylesheet = stylesheet;

            (*soap_package) = (Z_SOAP *)
                odr_malloc(decode, sizeof(**soap_package));
            (*soap_package)->which = Z_SOAP_generic;

            (*soap_package)->u.generic = (Z_SOAP_Generic *)
                odr_malloc(decode, sizeof(*(*soap_package)->u.generic));

            (*soap_package)->u.generic->p = sr;
            (*soap_package)->u.generic->ns = soap_handlers[0].ns;
            (*soap_package)->u.generic->no = 0;

            (*soap_package)->ns = "SRU";

            yaz_add_srw_diagnostic(decode, diag, num_diag,
                                   YAZ_SRW_UNSUPP_OPERATION, operation);
            return 0;
        }
#else
        return 1;
#endif
    }
    return 2;
}
Esempio n. 7
0
int yaz_srw_decode(Z_HTTP_Request *hreq, Z_SRW_PDU **srw_pdu,
                   Z_SOAP **soap_package, ODR decode, char **charset)
{
    if (!strcmp(hreq->method, "POST"))
    {
        const char *content_type = z_HTTP_header_lookup(hreq->headers,
                                                        "Content-Type");
        if (content_type &&
            (!yaz_strcmp_del("text/xml", content_type, "; ") ||
             !yaz_strcmp_del("application/soap+xml", content_type, "; ") ||
             !yaz_strcmp_del("text/plain", content_type, "; ")))
        {
            char *db = "Default";
            const char *p0 = hreq->path, *p1;
            int ret = -1;

            static Z_SOAP_Handler soap_handlers[5] = {
#if YAZ_HAVE_XML2
                { YAZ_XMLNS_SRU_v1_1, 0, (Z_SOAP_fun) yaz_srw_codec },
                { YAZ_XMLNS_SRU_v1_0, 0, (Z_SOAP_fun) yaz_srw_codec },
                { YAZ_XMLNS_UPDATE_v0_9, 0, (Z_SOAP_fun) yaz_ucp_codec },
                { YAZ_XMLNS_SRU_v2_mask, 0, (Z_SOAP_fun) yaz_srw_codec },
#endif
                {0, 0, 0}
            };

            if (*p0 == '/')
                p0++;
            p1 = strchr(p0, '?');
            if (!p1)
                p1 = p0 + strlen(p0);
            if (p1 != p0)
                db = yaz_decode_sru_dbpath_odr(decode, p0, p1 - p0);

            ret = z_soap_codec(decode, soap_package,
                               &hreq->content_buf, &hreq->content_len,
                               soap_handlers);
            if (ret == 0 && (*soap_package)->which == Z_SOAP_generic)
            {
                *srw_pdu = (Z_SRW_PDU*) (*soap_package)->u.generic->p;
                yaz_srw_decodeauth(*srw_pdu, hreq, 0, 0, decode);

                /* last entry in handlers - SRU 2.0 - is turned into
                   offset 0.. due to other pieces relying on it */
                if ((*soap_package)->u.generic->no == 3)
                    (*soap_package)->u.generic->no = 0;
                if ((*srw_pdu)->which == Z_SRW_searchRetrieve_request &&
                    (*srw_pdu)->u.request->database == 0)
                    (*srw_pdu)->u.request->database = db;

                if ((*srw_pdu)->which == Z_SRW_explain_request &&
                    (*srw_pdu)->u.explain_request->database == 0)
                    (*srw_pdu)->u.explain_request->database = db;

                if ((*srw_pdu)->which == Z_SRW_scan_request &&
                    (*srw_pdu)->u.scan_request->database == 0)
                    (*srw_pdu)->u.scan_request->database = db;

                if ((*srw_pdu)->which == Z_SRW_update_request &&
                    (*srw_pdu)->u.update_request->database == 0)
                    (*srw_pdu)->u.update_request->database = db;

                return 0;
            }
            return 1;
        }
    }
    return 2;
}
Esempio n. 8
0
Z_HTTP_Response *yaz_url_exec(yaz_url_t p, const char *uri,
                              const char *method,
                              Z_HTTP_Header *user_headers,
                              const char *buf, size_t len)
{
    Z_HTTP_Response *res = 0;
    int number_of_redirects = 0;

    yaz_cookies_reset(p->cookies);
    wrbuf_rewind(p->w_error);
    while (1)
    {
        void *add;
        COMSTACK conn = 0;
        int code;
        const char *location = 0;
        char *http_user = 0;
        char *http_pass = 0;
        char *uri_lean = 0;
        Z_GDU *gdu;

        extract_user_pass(p->odr_out->mem, uri, &uri_lean,
                          &http_user, &http_pass);

        gdu = z_get_HTTP_Request_uri(p->odr_out, uri_lean, 0, p->proxy ? 1 : 0);
        gdu->u.HTTP_Request->method = odr_strdup(p->odr_out, method);

        yaz_cookies_request(p->cookies, p->odr_out, gdu->u.HTTP_Request);
        for ( ; user_headers; user_headers = user_headers->next)
        {
            /* prefer new Host over user-supplied Host */
            if (!strcmp(user_headers->name, "Host"))
                ;
            /* prefer user-supplied User-Agent over YAZ' own */
            else if (!strcmp(user_headers->name, "User-Agent"))
                z_HTTP_header_set(p->odr_out, &gdu->u.HTTP_Request->headers,
                                  user_headers->name, user_headers->value);
            else
                z_HTTP_header_add(p->odr_out, &gdu->u.HTTP_Request->headers,
                                  user_headers->name, user_headers->value);
        }
        if (http_user && http_pass)
            z_HTTP_header_add_basic_auth(p->odr_out,
                                         &gdu->u.HTTP_Request->headers,
                                         http_user, http_pass);

        res = 0;
        if (buf && len)
        {
            gdu->u.HTTP_Request->content_buf = (char *) buf;
            gdu->u.HTTP_Request->content_len = len;
        }
        if (!z_GDU(p->odr_out, &gdu, 0, 0))
        {
            wrbuf_printf(p->w_error, "Can not encode HTTP request for URL %s",
                         uri);
            log_warn(p);
            return 0;
        }
        conn = cs_create_host_proxy(uri_lean, 1, &add, p->proxy);
        if (!conn)
        {
            wrbuf_printf(p->w_error, "Can not resolve URL %s", uri);
            log_warn(p);
        }
        else if (cs_connect(conn, add) < 0)
        {
            wrbuf_printf(p->w_error, "Can not connect to URL %s", uri);
            log_warn(p);
        }
        else
        {
            int len;
            char *buf = odr_getbuf(p->odr_out, &len, 0);

            if (p->verbose)
                fwrite(buf, 1, len, stdout);

            if (cs_put(conn, buf, len) < 0)
            {
                wrbuf_printf(p->w_error, "cs_put fail for URL %s", uri);
                log_warn(p);
            }
            else
            {
                char *netbuffer = 0;
                int netlen = 0;
                int cs_res = cs_get(conn, &netbuffer, &netlen);
                if (cs_res <= 0)
                {
                    wrbuf_printf(p->w_error, "cs_get failed for URL %s", uri);
                    log_warn(p);
                }
                else
                {
                    Z_GDU *gdu;
                    if (p->verbose)
                        fwrite(netbuffer, 1, cs_res, stdout);
                    odr_setbuf(p->odr_in, netbuffer, cs_res, 0);
                    if (!z_GDU(p->odr_in, &gdu, 0, 0)
                            || gdu->which != Z_GDU_HTTP_Response)
                    {
                        wrbuf_printf(p->w_error, "HTTP decoding fail for "
                                     "URL %s", uri);
                        log_warn(p);
                    }
                    else
                    {
                        res = gdu->u.HTTP_Response;
                    }
                }
                xfree(netbuffer);
            }
        }
        if (conn)
            cs_close(conn);
        if (!res)
            break;
        code = res->code;
        location = z_HTTP_header_lookup(res->headers, "Location");
        if (++number_of_redirects <= p->max_redirects &&
                location && (code == 301 || code == 302 || code == 307))
        {
            int host_change = 0;
            const char *nlocation = yaz_check_location(p->odr_in, uri,
                                    location, &host_change);

            odr_reset(p->odr_out);
            uri = odr_strdup(p->odr_out, nlocation);
        }
        else
            break;
        yaz_cookies_response(p->cookies, res);
        odr_reset(p->odr_in);
    }
    return res;
}