1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

http proxy: support POST

This commit is contained in:
Andy Green 2019-03-22 06:22:40 +08:00
parent f7860b6ac6
commit da3d8cb593
7 changed files with 135 additions and 10 deletions

View file

@ -326,6 +326,11 @@ __lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason,
just_kill_connection:
#if defined(LWS_WITH_HTTP_PROXY)
if (wsi->http.buflist_post_body)
lws_buflist_destroy_all_segments(&wsi->http.buflist_post_body);
#endif
if (wsi->role_ops->close_kill_connection)
wsi->role_ops->close_kill_connection(wsi, reason);

View file

@ -250,13 +250,29 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
break;
#if !defined(LWS_NO_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
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);
lws_buflist_append_segment(&wsi->http.buflist_post_body, in, len);
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)) {
@ -317,6 +333,7 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
__func__);
return -1;
}
lws_callback_on_writable(wsi);
break;
}
@ -494,6 +511,13 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
lwsl_debug("%s: LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: "
"prepared headers\n", __func__);
/*
* 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; }
@ -518,7 +542,6 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
parent = lws_get_parent(wsi);
if (!parent)
break;
@ -550,7 +573,6 @@ lws_callback_http_dummy(struct lws *wsi, enum lws_callback_reasons reason,
return -1;
break;
#endif
#ifdef LWS_WITH_CGI

View file

@ -654,8 +654,51 @@ rops_handle_POLLIN_h1(struct lws_context_per_thread *pt, struct lws *wsi,
static int
rops_handle_POLLOUT_h1(struct lws *wsi)
{
if (lwsi_state(wsi) == LRS_ISSUE_HTTP_BODY)
if (lwsi_state(wsi) == LRS_ISSUE_HTTP_BODY) {
#if defined(LWS_WITH_HTTP_PROXY)
if (wsi->http.proxy_clientside) {
unsigned char *buf;
size_t len = lws_buflist_next_segment_len(
&wsi->parent->http.buflist_post_body, &buf);
int n;
lwsl_debug("%s: %p: proxying body %d %d %d %d %d\n",
__func__, wsi, (int)len,
(int)wsi->http.tx_content_length,
(int)wsi->http.tx_content_remain,
(int)wsi->http.rx_content_length,
(int)wsi->http.rx_content_remain
);
n = lws_write(wsi, buf, len, LWS_WRITE_HTTP);
if (n < 0) {
lwsl_err("%s: PROXY_BODY: write failed\n",
__func__);
return -1;
}
lws_buflist_use_segment(&wsi->parent->http.buflist_post_body, len);
if (wsi->parent->http.buflist_post_body)
lws_callback_on_writable(wsi);
else {
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
/* prepare ourselves to do the parsing */
wsi->http.ah->parser_state = WSI_TOKEN_NAME_PART;
wsi->http.ah->lextable_pos = 0;
#if defined(LWS_WITH_CUSTOM_HEADERS)
wsi->http.ah->unk_pos = 0;
#endif
#endif
lwsi_set_state(wsi, LRS_WAITING_SERVER_REPLY);
lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
wsi->context->timeout_secs);
}
}
#endif
return LWS_HP_RET_USER_SERVICE;
}
if (lwsi_role_client(wsi))
return LWS_HP_RET_USER_SERVICE;

View file

@ -979,6 +979,9 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
lwsl_info(" h2 action start...\n");
n = lws_http_action(w);
if (n < 0)
lwsl_info (" h2 action result %d\n", n);
else
lwsl_info(" h2 action result %d "
"(wsi->http.rx_content_remain %lld)\n",
n, w->http.rx_content_remain);
@ -989,7 +992,7 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
* states. In those cases we will hear about
* END_STREAM going out in the POLLOUT handler.
*/
if (!w->h2.pending_status_body &&
if (n >= 0 && !w->h2.pending_status_body &&
(n || w->h2.send_END_STREAM)) {
lwsl_info("closing stream after h2 action\n");
lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
@ -997,6 +1000,9 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi)
wa = &wsi->h2.child_list;
}
if (n < 0)
wa = &wsi->h2.child_list;
goto next_child;
}

View file

@ -403,10 +403,15 @@ start_ws_handshake:
}
if (wsi->client_http_body_pending) {
lwsl_debug("body pending\n");
lwsi_set_state(wsi, LRS_ISSUE_HTTP_BODY);
lws_set_timeout(wsi,
PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,
context->timeout_secs);
#if defined(LWS_WITH_HTTP_PROXY)
if (wsi->http.proxy_clientside)
lws_callback_on_writable(wsi);
#endif
/* user code must ask for writable callback */
break;
}
@ -436,6 +441,12 @@ start_ws_handshake:
goto client_http_body_sent;
case LRS_ISSUE_HTTP_BODY:
#if defined(LWS_WITH_HTTP_PROXY)
if (wsi->http.proxy_clientside) {
lws_callback_on_writable(wsi);
break;
}
#endif
if (wsi->client_http_body_pending) {
//lws_set_timeout(wsi,
// PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD,
@ -1083,6 +1094,22 @@ lws_generate_client_handshake(struct lws *wsi, char *pkt)
lws_hdr_simple_ptr(wsi,
_WSI_TOKEN_CLIENT_ORIGIN));
}
#if defined(LWS_WITH_HTTP_PROXY)
if (wsi->parent &&
lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
p += snprintf(p, 128, "Content-Length: %s\x0d\x0a",
lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH));
if (atoi(lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_LENGTH)))
wsi->client_http_body_pending = 1;
}
if (wsi->parent &&
lws_hdr_total_length(wsi->parent, WSI_TOKEN_HTTP_CONTENT_TYPE)) {
p += snprintf(p, 128, "Content-Type: %s\x0d\x0a",
lws_hdr_simple_ptr(wsi->parent, WSI_TOKEN_HTTP_CONTENT_TYPE));
}
#endif
#if defined(LWS_ROLE_WS)
if (wsi->do_ws) {
const char *conn1 = "";

View file

@ -215,6 +215,7 @@ struct _lws_http_mode_related {
#if defined(LWS_WITH_HTTP_PROXY)
struct lws_rewrite *rw;
struct lws_buflist *buflist_post_body;
#endif
struct allocated_headers *ah;
struct lws *ah_wait_list;

View file

@ -746,6 +746,7 @@ lws_find_mount(struct lws *wsi, const char *uri_ptr, int uri_len)
if (hm->origin_protocol == LWSMPRO_CALLBACK ||
((hm->origin_protocol == LWSMPRO_CGI ||
lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) ||
lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI) ||
(wsi->http2_substream &&
lws_hdr_total_length(wsi,
WSI_TOKEN_HTTP_COLON_PATH)) ||
@ -1095,8 +1096,19 @@ lws_http_proxy_start(struct lws *wsi, const struct lws_http_mount *hit,
else
i.host = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HOST);
i.origin = NULL;
if (!ws)
i.method = "GET";
if (!ws) {
if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI)
#if defined(LWS_WITH_HTTP2)
|| (
lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD) &&
!strcmp(lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_COLON_METHOD), "post")
)
#endif
)
i.method = "POST";
else
i.method = "GET";
}
lws_snprintf(host, sizeof(host), "%s:%d", i.address, i.port);
i.host = host;
@ -1402,11 +1414,20 @@ lws_http_action(struct lws *wsi)
* The mount is a reverse proxy?
*/
// if (hit)
// lwsl_notice("%s: origin_protocol: %d\n", __func__, hit->origin_protocol);
//else
// lwsl_notice("%s: no hit\n", __func__);
if (hit->origin_protocol == LWSMPRO_HTTPS ||
hit->origin_protocol == LWSMPRO_HTTP)
return lws_http_proxy_start(wsi, hit, uri_ptr, 0);
hit->origin_protocol == LWSMPRO_HTTP) {
n = lws_http_proxy_start(wsi, hit, uri_ptr, 0);
lwsl_notice("proxy start says %d\n", n);
if (n)
return n;
goto deal_body;
}
#endif
/*
@ -1534,7 +1555,7 @@ after:
return 1;
}
#ifdef LWS_WITH_CGI
#if defined(LWS_WITH_CGI) || defined(LWS_WITH_HTTP_PROXY)
deal_body:
#endif
/*
@ -1547,7 +1568,7 @@ deal_body:
*/
if (lwsi_state(wsi) != LRS_ISSUING_FILE) {
/* Prepare to read body if we have a content length: */
lwsl_debug("wsi->http.rx_content_length %lld %d %d\n",
lwsl_notice("wsi->http.rx_content_length %lld %d %d\n",
(long long)wsi->http.rx_content_length,
wsi->upgraded_to_http2, wsi->http2_substream);