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); }
static int http_proxy(struct http_request *rq) { struct http_channel *c = rq->channel; struct http_proxy *p = c->proxy; struct http_header *hp; struct http_buf *requestbuf; char server_port[16] = ""; struct conf_server *ser = c->server; if (!p) // This is a new connection. Create a proxy channel { int sock; struct protoent *pe; int one = 1; if (!(pe = getprotobyname("tcp"))) { abort(); } if ((sock = socket(PF_INET, SOCK_STREAM, pe->p_proto)) < 0) { yaz_log(YLOG_WARN|YLOG_ERRNO, "socket"); return -1; } if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*) &one, sizeof(one)) < 0) abort(); enable_nonblock(sock); if (connect(sock, (struct sockaddr *) c->server->http_server->proxy_addr, sizeof(*c->server->http_server->proxy_addr)) < 0) { if (!is_inprogress()) { yaz_log(YLOG_WARN|YLOG_ERRNO, "Proxy connect"); return -1; } } p = xmalloc(sizeof(struct http_proxy)); p->oqueue = 0; p->channel = c; p->first_response = 1; c->proxy = p; // We will add EVENT_OUTPUT below p->iochan = iochan_create(sock, proxy_io, EVENT_INPUT, "http_proxy"); iochan_setdata(p->iochan, p); iochan_add(ser->iochan_man, p->iochan); } // Do _not_ modify Host: header, just checking it's existence if (!http_lookup_header(rq->headers, "Host")) { yaz_log(YLOG_WARN, "Failed to find Host header in proxy"); return -1; } // Add new header about paraz2 version, host, remote client address, etc. { char server_via[128]; hp = rq->headers; hp = http_header_append(c, hp, "X-Pazpar2-Version", PACKAGE_VERSION); hp = http_header_append(c, hp, "X-Pazpar2-Server-Host", ser->host); sprintf(server_port, "%d", ser->port); hp = http_header_append(c, hp, "X-Pazpar2-Server-Port", server_port); yaz_snprintf(server_via, sizeof(server_via), "1.1 %s:%s (%s/%s)", ser->host ? ser->host : "@", server_port, PACKAGE_NAME, PACKAGE_VERSION); hp = http_header_append(c, hp, "Via" , server_via); hp = http_header_append(c, hp, "X-Forwarded-For", c->addr); } requestbuf = http_serialize_request(rq); http_buf_enqueue(&p->oqueue, requestbuf); iochan_setflag(p->iochan, EVENT_OUTPUT); return 0; }
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; }
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"); }