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; }
static void cmd_settings(struct http_channel *c) { struct http_response *rs = c->response; struct http_request *rq = c->request; struct http_session *s = locate_session(c); const char *content_type = http_lookup_header(rq->headers, "Content-Type"); if (!s) return; if (rq->content_len && content_type && !yaz_strcmp_del("text/xml", content_type, "; ")) { xmlDoc *doc = xmlParseMemory(rq->content_buf, rq->content_len); xmlNode *root_n; int ret; if (!doc) { error(rs, PAZPAR2_MALFORMED_SETTING, 0); release_session(c,s); return; } root_n = xmlDocGetRootElement(doc); ret = settings_read_node_x(root_n, s->psession, apply_local_setting); xmlFreeDoc(doc); if (ret) { error(rs, PAZPAR2_MALFORMED_SETTING, 0); release_session(c,s); return; } } if (process_settings(s->psession, rq, rs) < 0) { release_session(c, s); return; } response_open(c, "settings"); response_close(c, "settings"); release_session(c, s); }
struct http_request *http_parse_request(struct http_channel *c, struct http_buf **queue, int len) { struct http_request *r = nmem_malloc(c->nmem, sizeof(*r)); char *p, *p2; char *start = nmem_malloc(c->nmem, len+1); char *buf = start; if (http_buf_read(c->http_server, queue, buf, len) < len) { yaz_log(YLOG_WARN, "http_buf_read < len (%d)", len); return 0; } r->search = ""; r->channel = c; r->arguments = 0; r->headers = 0; r->content_buf = 0; r->content_len = 0; // Parse first line for (p = buf, p2 = r->method; *p && *p != ' ' && p - buf < 19; p++) *(p2++) = *p; if (*p != ' ') { yaz_log(YLOG_WARN, "Unexpected HTTP method in request"); return 0; } *p2 = '\0'; if (!(buf = strchr(buf, ' '))) { yaz_log(YLOG_WARN, "Missing Request-URI in HTTP request"); return 0; } buf++; if (!(p = strchr(buf, ' '))) { yaz_log(YLOG_WARN, "HTTP Request-URI not terminated (too long?)"); return 0; } *(p++) = '\0'; if ((p2 = strchr(buf, '?'))) // Do we have arguments? *(p2++) = '\0'; r->path = nmem_strdup(c->nmem, buf); if (p2) { r->search = nmem_strdup(c->nmem, p2); // Parse Arguments http_parse_arguments(r, c->nmem, p2); } buf = p; if (strncmp(buf, "HTTP/", 5)) strcpy(r->http_version, "1.0"); else { size_t skipped; buf += 5; // strlen("HTTP/") p = (char*) next_crlf(buf, &skipped); if (!p || skipped < 3 || skipped > 5) return 0; memcpy(r->http_version, buf, skipped); r->http_version[skipped] = '\0'; buf = p; } strcpy(c->version, r->http_version); r->headers = 0; while (*buf) { size_t skipped; p = (char *) next_crlf(buf, &skipped); if (!p) { return 0; } else if (skipped == 0) { buf = p; break; } else { char *cp; char *n_v = nmem_malloc(c->nmem, skipped+1); struct http_header *h = nmem_malloc(c->nmem, sizeof(*h)); memcpy(n_v, buf, skipped); n_v[skipped] = '\0'; if (!(cp = strchr(n_v, ':'))) return 0; h->name = nmem_strdupn(c->nmem, n_v, cp - n_v); cp++; while (isspace(*cp)) cp++; h->value = nmem_strdup(c->nmem, cp); h->next = r->headers; r->headers = h; buf = p; } } // determine if we do keep alive if (!strcmp(c->version, "1.0")) { const char *v = http_lookup_header(r->headers, "Connection"); if (v && !strcmp(v, "Keep-Alive")) c->keep_alive = 1; else c->keep_alive = 0; } else { const char *v = http_lookup_header(r->headers, "Connection"); if (v && !strcmp(v, "close")) c->keep_alive = 0; else c->keep_alive = 1; } if (buf < start + len) { const char *content_type = http_lookup_header(r->headers, "Content-Type"); r->content_len = start + len - buf; r->content_buf = buf; if (!yaz_strcmp_del("application/x-www-form-urlencoded", content_type, "; ")) { http_parse_arguments(r, c->nmem, r->content_buf); } } return r; }
/** 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; }
static void cmd_init(struct http_channel *c) { struct http_request *r = c->request; const char *clear = http_argbyname(r, "clear"); const char *content_type = http_lookup_header(r->headers, "Content-Type"); unsigned int sesid; struct http_session *s; struct http_response *rs = c->response; struct conf_service *service = 0; /* no service (yet) */ if (r->content_len && content_type && !yaz_strcmp_del("text/xml", content_type, "; ")) { xmlDoc *doc = xmlParseMemory(r->content_buf, r->content_len); xmlNode *root_n; if (!doc) { error(rs, PAZPAR2_MALFORMED_SETTING, 0); return; } root_n = xmlDocGetRootElement(doc); service = service_create(c->server, root_n); xmlFreeDoc(doc); if (!service) { error(rs, PAZPAR2_MALFORMED_SETTING, 0); return; } } if (!service) { const char *service_name = http_argbyname(c->request, "service"); service = locate_service(c->server, service_name); if (!service) { error(rs, PAZPAR2_NO_SERVICE, service_name ? service_name : "unnamed"); return; } } sesid = make_sessionid(); s = http_session_create(service, c->http_sessions, sesid); yaz_log(c->http_sessions->log_level, "Session init %u ", sesid); if (!clear || *clear == '0') session_init_databases(s->psession); else yaz_log(YLOG_LOG, "Session %u init: No databases preloaded", sesid); if (process_settings(s->psession, c->request, c->response) < 0) return; response_open(c, "init"); wrbuf_printf(c->wrbuf, "<session>%d", sesid); if (c->server->server_id) { wrbuf_puts(c->wrbuf, "."); wrbuf_puts(c->wrbuf, c->server->server_id); } wrbuf_puts(c->wrbuf, "</session>" "<protocol>" PAZPAR2_PROTOCOL_VERSION "</protocol>"); wrbuf_printf(c->wrbuf, "<keepAlive>%d</keepAlive>\n", 1000 * ((s->psession->service->session_timeout >= 20) ? (s->psession->service->session_timeout - 10) : 50)); response_close(c, "init"); }