| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849 |
- /*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
- #include "private-lib-core.h"
- /* max individual proxied header payload size */
- #define MAXHDRVAL 1024
- #if defined(LWS_WITH_HTTP_PROXY)
- static int
- proxy_header(struct lws *wsi, struct lws *par, unsigned char *temp,
- int temp_len, int index, unsigned char **p, unsigned char *end)
- {
- int n = lws_hdr_total_length(par, index);
- if (n < 1) {
- lwsl_debug("%s: no index %d:\n", __func__, index);
- return 0;
- }
- if (lws_hdr_copy(par, (char *)temp, temp_len, index) < 0) {
- lwsl_notice("%s: unable to copy par hdr idx %d (len %d)\n",
- __func__, index, n);
- return -1;
- }
- lwsl_debug("%s: index %d: %s\n", __func__, index, (char *)temp);
- if (lws_add_http_header_by_token(wsi, index, temp, n, p, end)) {
- lwsl_notice("%s: unable to append par hdr idx %d (len %d)\n",
- __func__, index, n);
- return -1;
- }
- return 0;
- }
- static int
- stream_close(struct lws *wsi)
- {
- char buf[LWS_PRE + 6], *out = buf + LWS_PRE;
- if (wsi->http.did_stream_close)
- return 0;
- wsi->http.did_stream_close = 1;
- if (wsi->mux_substream) {
- if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0,
- LWS_WRITE_HTTP_FINAL) < 0) {
- lwsl_info("%s: COMPL_CLIENT_HTTP: h2 fin wr failed\n",
- __func__);
- return -1;
- }
- } else {
- *out++ = '0';
- *out++ = '\x0d';
- *out++ = '\x0a';
- *out++ = '\x0d';
- *out++ = '\x0a';
- if (lws_write(wsi, (unsigned char *)buf + LWS_PRE, 5,
- LWS_WRITE_HTTP_FINAL) < 0) {
- lwsl_err("%s: COMPL_CLIENT_HTTP: "
- "h2 final write failed\n", __func__);
- return -1;
- }
- }
- return 0;
- }
- #endif
- struct lws_proxy_pkt {
- struct lws_dll2 pkt_list;
- size_t len;
- char binary;
- char first;
- char final;
- /* data follows */
- };
- #if defined(LWS_WITH_HTTP_PROXY) && defined(LWS_ROLE_WS)
- int
- lws_callback_ws_proxy(struct lws *wsi, enum lws_callback_reasons reason,
- void *user, void *in, size_t len)
- {
- struct lws_proxy_pkt *pkt;
- struct lws_dll2 *dll;
- switch (reason) {
- /* h1 ws proxying... child / client / onward */
- case LWS_CALLBACK_CLIENT_ESTABLISHED:
- if (!wsi->h1_ws_proxied || !wsi->parent)
- break;
- if (lws_process_ws_upgrade2(wsi->parent))
- return -1;
- #if defined(LWS_WITH_HTTP2)
- if (wsi->parent->mux_substream)
- lwsl_info("%s: proxied h2 -> h1 ws established\n", __func__);
- #endif
- break;
- case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED:
- return 1;
- case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
- case LWS_CALLBACK_CLIENT_CLOSED:
- lwsl_info("%s: client closed: parent %p\n", __func__, wsi->parent);
- if (wsi->parent)
- lws_set_timeout(wsi->parent, 1, LWS_TO_KILL_ASYNC);
- break;
- case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
- {
- unsigned char **p = (unsigned char **)in, *end = (*p) + len,
- tmp[MAXHDRVAL];
- proxy_header(wsi, wsi->parent, tmp, sizeof(tmp),
- WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, p, end);
- proxy_header(wsi, wsi->parent, tmp, sizeof(tmp),
- WSI_TOKEN_HTTP_COOKIE, p, end);
- proxy_header(wsi, wsi->parent, tmp, sizeof(tmp),
- WSI_TOKEN_HTTP_SET_COOKIE, p, end);
- break;
- }
- case LWS_CALLBACK_CLIENT_RECEIVE:
- wsi->parent->ws->proxy_buffered += len;
- if (wsi->parent->ws->proxy_buffered > 10 * 1024 * 1024) {
- lwsl_err("%s: proxied ws connection excessive buffering: dropping\n",
- __func__);
- return -1;
- }
- pkt = lws_zalloc(sizeof(*pkt) + LWS_PRE + len, __func__);
- if (!pkt)
- return -1;
- pkt->len = len;
- pkt->first = lws_is_first_fragment(wsi);
- pkt->final = lws_is_final_fragment(wsi);
- pkt->binary = lws_frame_is_binary(wsi);
- memcpy(((uint8_t *)&pkt[1]) + LWS_PRE, in, len);
- lws_dll2_add_tail(&pkt->pkt_list, &wsi->parent->ws->proxy_owner);
- lws_callback_on_writable(wsi->parent);
- break;
- case LWS_CALLBACK_CLIENT_WRITEABLE:
- dll = lws_dll2_get_head(&wsi->ws->proxy_owner);
- if (!dll)
- break;
- pkt = (struct lws_proxy_pkt *)dll;
- if (lws_write(wsi, ((unsigned char *)&pkt[1]) +
- LWS_PRE, pkt->len, lws_write_ws_flags(
- pkt->binary ? LWS_WRITE_BINARY : LWS_WRITE_TEXT,
- pkt->first, pkt->final)) < 0)
- return -1;
- lws_dll2_remove(dll);
- lws_free(pkt);
- if (lws_dll2_get_head(&wsi->ws->proxy_owner))
- lws_callback_on_writable(wsi);
- break;
- /* h1 ws proxying... parent / server / incoming */
- case LWS_CALLBACK_CONFIRM_EXTENSION_OKAY:
- return 1;
- case LWS_CALLBACK_CLOSED:
- lwsl_info("%s: closed\n", __func__);
- return -1;
- case LWS_CALLBACK_RECEIVE:
- pkt = lws_zalloc(sizeof(*pkt) + LWS_PRE + len, __func__);
- if (!pkt)
- return -1;
- pkt->len = len;
- pkt->first = lws_is_first_fragment(wsi);
- pkt->final = lws_is_final_fragment(wsi);
- pkt->binary = lws_frame_is_binary(wsi);
- memcpy(((uint8_t *)&pkt[1]) + LWS_PRE, in, len);
- lws_dll2_add_tail(&pkt->pkt_list, &wsi->child_list->ws->proxy_owner);
- lws_callback_on_writable(wsi->child_list);
- break;
- case LWS_CALLBACK_SERVER_WRITEABLE:
- dll = lws_dll2_get_head(&wsi->ws->proxy_owner);
- if (!dll)
- break;
- pkt = (struct lws_proxy_pkt *)dll;
- if (lws_write(wsi, ((unsigned char *)&pkt[1]) +
- LWS_PRE, pkt->len, lws_write_ws_flags(
- pkt->binary ? LWS_WRITE_BINARY : LWS_WRITE_TEXT,
- pkt->first, pkt->final)) < 0)
- return -1;
- wsi->ws->proxy_buffered -= pkt->len;
- lws_dll2_remove(dll);
- lws_free(pkt);
- if (lws_dll2_get_head(&wsi->ws->proxy_owner))
- lws_callback_on_writable(wsi);
- break;
- default:
- return 0;
- }
- return 0;
- }
- const struct lws_protocols lws_ws_proxy = {
- "lws-ws-proxy",
- lws_callback_ws_proxy,
- 0,
- 8192,
- 8192, NULL, 0
- };
- #endif
- int
- lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
- void *user, void *in, size_t len)
- {
- struct lws_ssl_info *si;
- #ifdef LWS_WITH_CGI
- struct lws_cgi_args *args;
- #endif
- #if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY)
- char buf[LWS_PRE + 32 + 8192];
- int n;
- #endif
- #if defined(LWS_WITH_HTTP_PROXY)
- unsigned char **p, *end;
- struct lws *parent;
- #endif
- switch (reason) {
- #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
- case LWS_CALLBACK_HTTP:
- #if defined(LWS_WITH_SERVER)
- if (lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL))
- return -1;
- if (lws_http_transaction_completed(wsi))
- #endif
- return -1;
- break;
- #if defined(LWS_WITH_SERVER)
- case LWS_CALLBACK_HTTP_BODY_COMPLETION:
- #if defined(LWS_WITH_HTTP_PROXY)
- if (wsi->child_list) {
- lwsl_user("%s: LWS_CALLBACK_HTTP_BODY_COMPLETION: %d\n", __func__, (int)len);
- break;
- }
- #endif
- /* fallthru */
- case LWS_CALLBACK_HTTP_FILE_COMPLETION:
- if (lws_http_transaction_completed(wsi))
- return -1;
- break;
- #endif
- #if defined(LWS_WITH_HTTP_PROXY)
- case LWS_CALLBACK_HTTP_BODY:
- if (wsi->child_list) {
- lwsl_user("%s: LWS_CALLBACK_HTTP_BODY: stashing %d\n", __func__, (int)len);
- if (lws_buflist_append_segment(&wsi->http.buflist_post_body, in, len) < 0)
- return -1;
- lws_callback_on_writable(wsi->child_list);
- }
- break;
- #endif
- case LWS_CALLBACK_HTTP_WRITEABLE:
- // lwsl_err("%s: LWS_CALLBACK_HTTP_WRITEABLE\n", __func__);
- #ifdef LWS_WITH_CGI
- if (wsi->reason_bf & (LWS_CB_REASON_AUX_BF__CGI_HEADERS |
- LWS_CB_REASON_AUX_BF__CGI)) {
- n = lws_cgi_write_split_stdout_headers(wsi);
- if (n < 0) {
- lwsl_debug("AUX_BF__CGI forcing close\n");
- return -1;
- }
- if (!n && wsi->http.cgi && wsi->http.cgi->lsp &&
- wsi->http.cgi->lsp->stdwsi[LWS_STDOUT])
- lws_rx_flow_control(
- wsi->http.cgi->lsp->stdwsi[LWS_STDOUT], 1);
- if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_HEADERS)
- wsi->reason_bf &=
- ~LWS_CB_REASON_AUX_BF__CGI_HEADERS;
- else
- wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__CGI;
- if (wsi->http.cgi && wsi->http.cgi->cgi_transaction_over) {
- lwsl_info("%s: txn over\n", __func__);
- return -1;
- }
- break;
- }
- if ((wsi->http.cgi && wsi->http.cgi->cgi_transaction_over) ||
- (wsi->reason_bf & LWS_CB_REASON_AUX_BF__CGI_CHUNK_END)) {
- if (!wsi->mux_substream) {
- memcpy(buf + LWS_PRE, "0\x0d\x0a\x0d\x0a", 5);
- lwsl_debug("writing chunk term and exiting\n");
- lws_write(wsi, (unsigned char *)buf +
- LWS_PRE, 5, LWS_WRITE_HTTP);
- } else
- lws_write(wsi, (unsigned char *)buf +
- LWS_PRE, 0,
- LWS_WRITE_HTTP_FINAL);
- /* always close after sending it */
- if (lws_http_transaction_completed(wsi))
- return -1;
- return 0;
- }
- #endif
- #if defined(LWS_WITH_HTTP_PROXY)
- if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY_HEADERS) {
- wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY_HEADERS;
- n = LWS_WRITE_HTTP_HEADERS;
- if (!wsi->http.prh_content_length)
- n |= LWS_WRITE_H2_STREAM_END;
- lwsl_debug("%s: %p: issuing proxy headers: clen %d\n",
- __func__, wsi, (int)wsi->http.prh_content_length);
- n = lws_write(wsi, wsi->http.pending_return_headers +
- LWS_PRE,
- wsi->http.pending_return_headers_len, n);
- lws_free_set_NULL(wsi->http.pending_return_headers);
- if (n < 0) {
- lwsl_err("%s: EST_CLIENT_HTTP: write failed\n",
- __func__);
- return -1;
- }
- lws_callback_on_writable(wsi);
- break;
- }
- if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY) {
- char *px = buf + LWS_PRE;
- int lenx = sizeof(buf) - LWS_PRE - 32;
- /*
- * our sink is writeable and our source has something
- * to read. So read a lump of source material of
- * suitable size to send or what's available, whichever
- * is the smaller.
- */
- wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY;
- if (!lws_get_child(wsi))
- break;
- /* this causes LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ */
- if (lws_http_client_read(lws_get_child(wsi), &px,
- &lenx) < 0) {
- lwsl_info("%s: LWS_CB_REASON_AUX_BF__PROXY: "
- "client closed\n", __func__);
- stream_close(wsi);
- return -1;
- }
- break;
- }
- if (wsi->reason_bf & LWS_CB_REASON_AUX_BF__PROXY_TRANS_END) {
- lwsl_info("%s: LWS_CB_REASON_AUX_BF__PROXY_TRANS_END\n",
- __func__);
- wsi->reason_bf &= ~LWS_CB_REASON_AUX_BF__PROXY_TRANS_END;
- if (stream_close(wsi))
- return -1;
- if (lws_http_transaction_completed(wsi))
- return -1;
- }
- #endif
- break;
- #if defined(LWS_WITH_HTTP_PROXY)
- case LWS_CALLBACK_RECEIVE_CLIENT_HTTP:
- assert(lws_get_parent(wsi));
- if (!lws_get_parent(wsi))
- break;
- lws_get_parent(wsi)->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY;
- lws_callback_on_writable(lws_get_parent(wsi));
- break;
- case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: {
- char *out = buf + LWS_PRE;
- assert(lws_get_parent(wsi));
- if (wsi->http.proxy_parent_chunked) {
- if (len > sizeof(buf) - LWS_PRE - 16) {
- lwsl_err("oversize buf %d %d\n", (int)len,
- (int)sizeof(buf) - LWS_PRE - 16);
- return -1;
- }
- /*
- * this only needs dealing with on http/1.1 to allow
- * pipelining
- */
- n = lws_snprintf(out, 14, "%X\x0d\x0a", (int)len);
- out += n;
- memcpy(out, in, len);
- out += len;
- *out++ = '\x0d';
- *out++ = '\x0a';
- n = lws_write(lws_get_parent(wsi),
- (unsigned char *)buf + LWS_PRE,
- len + n + 2, LWS_WRITE_HTTP);
- } else
- n = lws_write(lws_get_parent(wsi), (unsigned char *)in,
- len, LWS_WRITE_HTTP);
- if (n < 0)
- return -1;
- break; }
- /* h1 http proxying... */
- case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: {
- unsigned char *start, *p, *end;
- /*
- * We want to proxy these headers, but we are being called
- * at the point the onward client was established, which is
- * unrelated to the state or writability of our proxy
- * connection.
- *
- * Therefore produce the headers using the onward client ah
- * while we have it, and stick them on the output buflist to be
- * written on the proxy connection as soon as convenient.
- */
- parent = lws_get_parent(wsi);
- if (!parent)
- return 0;
- start = p = (unsigned char *)buf + LWS_PRE;
- end = p + sizeof(buf) - LWS_PRE - MAXHDRVAL;
- if (lws_add_http_header_status(lws_get_parent(wsi),
- lws_http_client_http_response(wsi), &p, end))
- return 1;
- /*
- * copy these headers from the client connection to the parent
- */
- proxy_header(parent, wsi, end, MAXHDRVAL,
- WSI_TOKEN_HTTP_CONTENT_LENGTH, &p, end);
- proxy_header(parent, wsi, end, MAXHDRVAL,
- WSI_TOKEN_HTTP_CONTENT_TYPE, &p, end);
- proxy_header(parent, wsi, end, MAXHDRVAL,
- WSI_TOKEN_HTTP_ETAG, &p, end);
- proxy_header(parent, wsi, end, MAXHDRVAL,
- WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, &p, end);
- proxy_header(parent, wsi, end, MAXHDRVAL,
- WSI_TOKEN_HTTP_CONTENT_ENCODING, &p, end);
- proxy_header(parent, wsi, end, MAXHDRVAL,
- WSI_TOKEN_HTTP_CACHE_CONTROL, &p, end);
- proxy_header(parent, wsi, end, MAXHDRVAL,
- WSI_TOKEN_HTTP_SET_COOKIE, &p, end);
- proxy_header(parent, wsi, end, MAXHDRVAL,
- WSI_TOKEN_HTTP_LOCATION, &p, end);
- if (!parent->mux_substream)
- if (lws_add_http_header_by_token(parent,
- WSI_TOKEN_CONNECTION, (unsigned char *)"close",
- 5, &p, end))
- return -1;
- /*
- * We proxy using h1 only atm, and strip any chunking so it
- * can go back out on h2 just fine.
- *
- * However if we are actually going out on h1, we need to add
- * our own chunking since we still don't know the size.
- */
- if (!parent->mux_substream &&
- !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
- lwsl_debug("downstream parent chunked\n");
- if (lws_add_http_header_by_token(parent,
- WSI_TOKEN_HTTP_TRANSFER_ENCODING,
- (unsigned char *)"chunked", 7, &p, end))
- return -1;
- wsi->http.proxy_parent_chunked = 1;
- }
- if (lws_finalize_http_header(parent, &p, end))
- return 1;
- parent->http.prh_content_length = -1;
- if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH))
- parent->http.prh_content_length = atoll(
- lws_hdr_simple_ptr(wsi,
- WSI_TOKEN_HTTP_CONTENT_LENGTH));
- parent->http.pending_return_headers_len = lws_ptr_diff(p, start);
- parent->http.pending_return_headers =
- lws_malloc(parent->http.pending_return_headers_len +
- LWS_PRE, "return proxy headers");
- if (!parent->http.pending_return_headers)
- return -1;
- memcpy(parent->http.pending_return_headers + LWS_PRE, start,
- parent->http.pending_return_headers_len);
- parent->reason_bf |= LWS_CB_REASON_AUX_BF__PROXY_HEADERS;
- lwsl_debug("%s: LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: "
- "prepared %d headers (len %d)\n", __func__,
- lws_http_client_http_response(wsi),
- (int)parent->http.prh_content_length);
- /*
- * so at this point, the onward client connection can bear
- * traffic. We might be doing a POST and have pending cached
- * inbound stuff to send, it can go now.
- */
- lws_callback_on_writable(parent);
- break; }
- case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
- lwsl_info("%s: COMPLETED_CLIENT_HTTP: %p (parent %p)\n",
- __func__, wsi, lws_get_parent(wsi));
- if (!lws_get_parent(wsi))
- break;
- lws_get_parent(wsi)->reason_bf |=
- LWS_CB_REASON_AUX_BF__PROXY_TRANS_END;
- lws_callback_on_writable(lws_get_parent(wsi));
- break;
- case LWS_CALLBACK_CLOSED_CLIENT_HTTP:
- if (!lws_get_parent(wsi))
- break;
- // lwsl_err("%s: LWS_CALLBACK_CLOSED_CLIENT_HTTP\n", __func__);
- lws_set_timeout(lws_get_parent(wsi), LWS_TO_KILL_ASYNC,
- PENDING_TIMEOUT_KILLED_BY_PROXY_CLIENT_CLOSE);
- break;
- case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
- parent = lws_get_parent(wsi);
- if (!parent)
- break;
- p = (unsigned char **)in;
- end = (*p) + len;
- /*
- * copy these headers from the parent request to the client
- * connection's request
- */
- proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
- WSI_TOKEN_HTTP_ETAG, p, end);
- proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
- WSI_TOKEN_HTTP_IF_MODIFIED_SINCE, p, end);
- proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
- WSI_TOKEN_HTTP_ACCEPT_LANGUAGE, p, end);
- proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
- WSI_TOKEN_HTTP_ACCEPT_ENCODING, p, end);
- proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
- WSI_TOKEN_HTTP_CACHE_CONTROL, p, end);
- proxy_header(wsi, parent, (unsigned char *)buf, sizeof(buf),
- WSI_TOKEN_HTTP_COOKIE, p, end);
- buf[0] = '\0';
- lws_get_peer_simple(parent, buf, sizeof(buf));
- if (lws_add_http_header_by_token(wsi, WSI_TOKEN_X_FORWARDED_FOR,
- (unsigned char *)buf, (int)strlen(buf), p, end))
- return -1;
- break;
- #endif
- #ifdef LWS_WITH_CGI
- /* CGI IO events (POLLIN/OUT) appear here, our default policy is:
- *
- * - POST data goes on subprocess stdin
- * - subprocess stdout goes on http via writeable callback
- * - subprocess stderr goes to the logs
- */
- case LWS_CALLBACK_CGI:
- args = (struct lws_cgi_args *)in;
- switch (args->ch) { /* which of stdin/out/err ? */
- case LWS_STDIN:
- /* TBD stdin rx flow control */
- break;
- case LWS_STDOUT:
- if (args->stdwsi[LWS_STDOUT])
- /* quench POLLIN on STDOUT until MASTER got writeable */
- lws_rx_flow_control(args->stdwsi[LWS_STDOUT], 0);
- wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI;
- /* when writing to MASTER would not block */
- lws_callback_on_writable(wsi);
- break;
- case LWS_STDERR:
- n = lws_get_socket_fd(args->stdwsi[LWS_STDERR]);
- if (n < 0)
- break;
- n = read(n, buf, sizeof(buf) - 2);
- if (n > 0) {
- if (buf[n - 1] != '\n')
- buf[n++] = '\n';
- buf[n] = '\0';
- lwsl_notice("CGI-stderr: %s\n", buf);
- }
- break;
- }
- break;
- case LWS_CALLBACK_CGI_TERMINATED:
- lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: %d %" PRIu64 "\n",
- wsi->http.cgi->explicitly_chunked,
- (uint64_t)wsi->http.cgi->content_length);
- if (!(wsi->http.cgi->explicitly_chunked && wsi->mux_substream) &&
- !wsi->http.cgi->content_length) {
- /* send terminating chunk */
- lwsl_debug("LWS_CALLBACK_CGI_TERMINATED: ending\n");
- wsi->reason_bf |= LWS_CB_REASON_AUX_BF__CGI_CHUNK_END;
- lws_callback_on_writable(wsi);
- lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, 3);
- break;
- }
- if (wsi->mux_substream && !wsi->cgi_stdout_zero_length)
- lws_write(wsi, (unsigned char *)buf + LWS_PRE, 0,
- LWS_WRITE_HTTP_FINAL);
- if (lws_http_transaction_completed(wsi))
- return -1;
- return 0;
- case LWS_CALLBACK_CGI_STDIN_DATA: /* POST body for stdin */
- args = (struct lws_cgi_args *)in;
- args->data[args->len] = '\0';
- if (!args->stdwsi[LWS_STDIN])
- return -1;
- n = lws_get_socket_fd(args->stdwsi[LWS_STDIN]);
- if (n < 0)
- return -1;
- #if defined(LWS_WITH_ZLIB)
- if (wsi->http.cgi->gzip_inflate) {
- /* gzip handling */
- if (!wsi->http.cgi->gzip_init) {
- lwsl_info("inflating gzip\n");
- memset(&wsi->http.cgi->inflate, 0,
- sizeof(wsi->http.cgi->inflate));
- if (inflateInit2(&wsi->http.cgi->inflate,
- 16 + 15) != Z_OK) {
- lwsl_err("%s: iniflateInit failed\n",
- __func__);
- return -1;
- }
- wsi->http.cgi->gzip_init = 1;
- }
- wsi->http.cgi->inflate.next_in = args->data;
- wsi->http.cgi->inflate.avail_in = args->len;
- do {
- wsi->http.cgi->inflate.next_out =
- wsi->http.cgi->inflate_buf;
- wsi->http.cgi->inflate.avail_out =
- sizeof(wsi->http.cgi->inflate_buf);
- n = inflate(&wsi->http.cgi->inflate,
- Z_SYNC_FLUSH);
- switch (n) {
- case Z_NEED_DICT:
- case Z_STREAM_ERROR:
- case Z_DATA_ERROR:
- case Z_MEM_ERROR:
- inflateEnd(&wsi->http.cgi->inflate);
- wsi->http.cgi->gzip_init = 0;
- lwsl_err("zlib error inflate %d\n", n);
- return -1;
- }
- if (wsi->http.cgi->inflate.avail_out !=
- sizeof(wsi->http.cgi->inflate_buf)) {
- int written;
- written = write(args->stdwsi[LWS_STDIN]->desc.filefd,
- wsi->http.cgi->inflate_buf,
- sizeof(wsi->http.cgi->inflate_buf) -
- wsi->http.cgi->inflate.avail_out);
- if (written != (int)(
- sizeof(wsi->http.cgi->inflate_buf) -
- wsi->http.cgi->inflate.avail_out)) {
- lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: "
- "sent %d only %d went", n, args->len);
- }
- if (n == Z_STREAM_END) {
- lwsl_err("gzip inflate end\n");
- inflateEnd(&wsi->http.cgi->inflate);
- wsi->http.cgi->gzip_init = 0;
- break;
- }
- } else
- break;
- if (wsi->http.cgi->inflate.avail_out)
- break;
- } while (1);
- return args->len;
- }
- #endif /* WITH_ZLIB */
- n = write(n, args->data, args->len);
- // lwsl_hexdump_notice(args->data, args->len);
- if (n < args->len)
- lwsl_notice("LWS_CALLBACK_CGI_STDIN_DATA: "
- "sent %d only %d went", n, args->len);
- lwsl_notice("%s: proxied %d bytes\n", __func__, n);
- if (wsi->http.cgi->post_in_expected && args->stdwsi[LWS_STDIN] &&
- args->stdwsi[LWS_STDIN]->desc.filefd > 0) {
- wsi->http.cgi->post_in_expected -= n;
- if (!wsi->http.cgi->post_in_expected) {
- struct lws *siwsi = args->stdwsi[LWS_STDIN];
- /*
- * The situation here is that we finished
- * proxying the incoming body from the net to
- * the STDIN stdwsi... and we want to close it
- * so it can understand we are done (necessary
- * if no content-length)...
- */
- lwsl_notice("%s: expected POST in end: "
- "closing stdin wsi %p, fd %d\n",
- __func__, siwsi,
- siwsi->desc.sockfd);
- /*
- * We don't want the child / parent relationship
- * to be handled in close, since we want the
- * rest of the cgi and children to stay up
- */
- lws_remove_child_from_any_parent(siwsi);
- lws_wsi_close(siwsi, LWS_TO_KILL_ASYNC);
- wsi->http.cgi->lsp->stdwsi[LWS_STDIN] = NULL;
- lws_spawn_stdwsi_closed(wsi->http.cgi->lsp, siwsi);
- }
- }
- return n;
- #endif /* WITH_CGI */
- #endif /* ROLE_ H1 / H2 */
- case LWS_CALLBACK_SSL_INFO:
- si = in;
- (void)si;
- lwsl_notice("LWS_CALLBACK_SSL_INFO: where: 0x%x, ret: 0x%x\n",
- si->where, si->ret);
- break;
- #if LWS_MAX_SMP > 1
- case LWS_CALLBACK_GET_THREAD_ID:
- return (int)(lws_intptr_t)pthread_self();
- #endif
- default:
- break;
- }
- return 0;
- }
|