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); } } }
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; }
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; }
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; }
/** * 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); } }
/** 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; }
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; }
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; }