mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-30 00:00:16 +01:00
client chunked transfer encoding
Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
parent
c3c2d6d953
commit
5c8906e931
5 changed files with 128 additions and 12 deletions
|
@ -79,7 +79,7 @@ just deferred until an ah becomes available.
|
||||||
8) The test client pays attention to if you give it an http:/ or https://
|
8) The test client pays attention to if you give it an http:/ or https://
|
||||||
protocol string to its argument in URL format. If so, it stays in http[s]
|
protocol string to its argument in URL format. If so, it stays in http[s]
|
||||||
client mode and doesn't upgrade to ws[s], allowing you to do generic http client
|
client mode and doesn't upgrade to ws[s], allowing you to do generic http client
|
||||||
operations.
|
operations. Receiving transfer-encoding: chunked is supported.
|
||||||
|
|
||||||
9) The test server has a new URI path http://localhost:7681/proxytest
|
9) The test server has a new URI path http://localhost:7681/proxytest
|
||||||
If you visit here, a client connection to http://example.com:80 is spawned,
|
If you visit here, a client connection to http://example.com:80 is spawned,
|
||||||
|
|
14
lib/client.c
14
lib/client.c
|
@ -628,6 +628,17 @@ lws_client_interpret_server_handshake(struct lws *wsi)
|
||||||
goto bail2;
|
goto bail2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* he may choose to send us stuff in chunked transfer-coding */
|
||||||
|
wsi->chunked = 0;
|
||||||
|
wsi->chunk_remaining = 0; /* ie, next thing is chunk size */
|
||||||
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_TRANSFER_ENCODING)) {
|
||||||
|
wsi->chunked = !strcmp(lws_hdr_simple_ptr(wsi,
|
||||||
|
WSI_TOKEN_HTTP_TRANSFER_ENCODING),
|
||||||
|
"chunked");
|
||||||
|
/* first thing is hex, after payload there is crlf */
|
||||||
|
wsi->chunk_parser = ELCP_HEX;
|
||||||
|
}
|
||||||
|
|
||||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
|
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
|
||||||
wsi->u.http.content_length =
|
wsi->u.http.content_length =
|
||||||
atoi(lws_hdr_simple_ptr(wsi,
|
atoi(lws_hdr_simple_ptr(wsi,
|
||||||
|
@ -635,7 +646,8 @@ lws_client_interpret_server_handshake(struct lws *wsi)
|
||||||
lwsl_notice("%s: incoming content length %d\n", __func__,
|
lwsl_notice("%s: incoming content length %d\n", __func__,
|
||||||
wsi->u.http.content_length);
|
wsi->u.http.content_length);
|
||||||
wsi->u.http.content_remain = wsi->u.http.content_length;
|
wsi->u.http.content_remain = wsi->u.http.content_length;
|
||||||
} else /* can't do 1.1 without a content length */
|
} else /* can't do 1.1 without a content length or chunked */
|
||||||
|
if (!wsi->chunked)
|
||||||
wsi->u.http.connection_type = HTTP_CONNECTION_CLOSE;
|
wsi->u.http.connection_type = HTTP_CONNECTION_CLOSE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -496,7 +496,7 @@ lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static signed char char_to_hex(const char c)
|
signed char char_to_hex(const char c)
|
||||||
{
|
{
|
||||||
if (c >= '0' && c <= '9')
|
if (c >= '0' && c <= '9')
|
||||||
return c - '0';
|
return c - '0';
|
||||||
|
|
|
@ -1054,7 +1054,18 @@ struct lws_cgi {
|
||||||
|
|
||||||
unsigned int being_closed:1;
|
unsigned int being_closed:1;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
signed char char_to_hex(const char c);
|
||||||
|
|
||||||
|
#ifndef LWS_NO_CLIENT
|
||||||
|
enum lws_chunk_parser {
|
||||||
|
ELCP_HEX,
|
||||||
|
ELCP_CR,
|
||||||
|
ELCP_CONTENT,
|
||||||
|
ELCP_POST_CR,
|
||||||
|
ELCP_POST_LF,
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct lws {
|
struct lws {
|
||||||
|
@ -1121,6 +1132,9 @@ struct lws {
|
||||||
unsigned int trunc_alloc_len; /* size of malloc */
|
unsigned int trunc_alloc_len; /* size of malloc */
|
||||||
unsigned int trunc_offset; /* where we are in terms of spilling */
|
unsigned int trunc_offset; /* where we are in terms of spilling */
|
||||||
unsigned int trunc_len; /* how much is buffered */
|
unsigned int trunc_len; /* how much is buffered */
|
||||||
|
#ifndef LWS_NO_CLIENT
|
||||||
|
int chunk_remaining;
|
||||||
|
#endif
|
||||||
|
|
||||||
unsigned int hdr_parsing_completed:1;
|
unsigned int hdr_parsing_completed:1;
|
||||||
unsigned int user_space_externally_allocated:1;
|
unsigned int user_space_externally_allocated:1;
|
||||||
|
@ -1129,6 +1143,7 @@ struct lws {
|
||||||
unsigned int more_rx_waiting:1; /* has to live here since ah may stick to end */
|
unsigned int more_rx_waiting:1; /* has to live here since ah may stick to end */
|
||||||
#ifndef LWS_NO_CLIENT
|
#ifndef LWS_NO_CLIENT
|
||||||
unsigned int do_ws:1; /* whether we are doing http or ws flow */
|
unsigned int do_ws:1; /* whether we are doing http or ws flow */
|
||||||
|
unsigned int chunked:1; /* if the clientside connection is chunked */
|
||||||
#endif
|
#endif
|
||||||
#ifndef LWS_NO_EXTENSIONS
|
#ifndef LWS_NO_EXTENSIONS
|
||||||
unsigned int extension_data_pending:1;
|
unsigned int extension_data_pending:1;
|
||||||
|
@ -1161,6 +1176,9 @@ struct lws {
|
||||||
char cgi_channel; /* which of stdin/out/err */
|
char cgi_channel; /* which of stdin/out/err */
|
||||||
char hdr_state;
|
char hdr_state;
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef LWS_NO_CLIENT
|
||||||
|
char chunk_parser; /* enum lws_chunk_parser */
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
LWS_EXTERN int log_level;
|
LWS_EXTERN int log_level;
|
||||||
|
|
102
lib/service.c
102
lib/service.c
|
@ -760,24 +760,110 @@ read:
|
||||||
*/
|
*/
|
||||||
drain:
|
drain:
|
||||||
if (wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED) {
|
if (wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED) {
|
||||||
lwsl_notice("%s: calling LWS_CALLBACK_RECEIVE_CLIENT_HTTP, "
|
/*
|
||||||
"rem %d len %d\n", __func__,
|
* server may insist on transfer-encoding: chunked,
|
||||||
wsi->u.http.content_remain, eff_buf.token_len);
|
* so http client must deal with it
|
||||||
if ((int)wsi->u.http.content_remain < eff_buf.token_len)
|
*/
|
||||||
|
spin_chunks:
|
||||||
|
while (wsi->chunked &&
|
||||||
|
(wsi->chunk_parser != ELCP_CONTENT) &&
|
||||||
|
eff_buf.token_len) {
|
||||||
|
switch (wsi->chunk_parser) {
|
||||||
|
case ELCP_HEX:
|
||||||
|
if (eff_buf.token[0] == '\x0d') {
|
||||||
|
wsi->chunk_parser = ELCP_CR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
n = char_to_hex(eff_buf.token[0]);
|
||||||
|
if (n < 0)
|
||||||
|
goto close_and_handled;
|
||||||
|
wsi->chunk_remaining <<= 4;
|
||||||
|
wsi->chunk_remaining |= n;
|
||||||
|
break;
|
||||||
|
case ELCP_CR:
|
||||||
|
if (eff_buf.token[0] != '\x0a')
|
||||||
|
goto close_and_handled;
|
||||||
|
wsi->chunk_parser = ELCP_CONTENT;
|
||||||
|
lwsl_info("chunk %d\n",
|
||||||
|
wsi->chunk_remaining);
|
||||||
|
if (wsi->chunk_remaining)
|
||||||
|
break;
|
||||||
|
lwsl_info("final chunk\n");
|
||||||
|
if (user_callback_handle_rxflow(
|
||||||
|
wsi->protocol->callback,
|
||||||
|
wsi, LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
|
||||||
|
wsi->user_space, NULL, 0))
|
||||||
|
goto close_and_handled;
|
||||||
|
if (lws_http_transaction_completed(wsi))
|
||||||
|
goto close_and_handled;
|
||||||
|
n = 0;
|
||||||
|
goto handled;
|
||||||
|
|
||||||
|
case ELCP_CONTENT:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ELCP_POST_CR:
|
||||||
|
if (eff_buf.token[0] == '\x0d') {
|
||||||
|
wsi->chunk_parser = ELCP_POST_LF;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
goto close_and_handled;
|
||||||
|
|
||||||
|
case ELCP_POST_LF:
|
||||||
|
if (eff_buf.token[0] == '\x0a') {
|
||||||
|
wsi->chunk_parser = ELCP_HEX;
|
||||||
|
wsi->chunk_remaining = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
goto close_and_handled;
|
||||||
|
}
|
||||||
|
eff_buf.token++;
|
||||||
|
eff_buf.token_len--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wsi->chunked && !wsi->chunk_remaining) {
|
||||||
|
n = 0;
|
||||||
|
goto handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wsi->u.http.content_remain &&
|
||||||
|
wsi->u.http.content_remain < eff_buf.token_len)
|
||||||
n = wsi->u.http.content_remain;
|
n = wsi->u.http.content_remain;
|
||||||
else
|
else
|
||||||
n = eff_buf.token_len;
|
n = eff_buf.token_len;
|
||||||
|
|
||||||
|
if (wsi->chunked && wsi->chunk_remaining &&
|
||||||
|
wsi->chunk_remaining < n)
|
||||||
|
n = wsi->chunk_remaining;
|
||||||
|
|
||||||
if (user_callback_handle_rxflow(wsi->protocol->callback,
|
if (user_callback_handle_rxflow(wsi->protocol->callback,
|
||||||
wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
|
wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
|
||||||
wsi->user_space, (void *)eff_buf.token,
|
wsi->user_space, (void *)eff_buf.token,
|
||||||
eff_buf.token_len))
|
n))
|
||||||
goto close_and_handled;
|
goto close_and_handled;
|
||||||
|
|
||||||
|
if (wsi->chunked && wsi->chunk_remaining) {
|
||||||
|
eff_buf.token += n;
|
||||||
|
wsi->chunk_remaining -= n;
|
||||||
|
eff_buf.token_len -= n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wsi->chunked && !wsi->chunk_remaining)
|
||||||
|
wsi->chunk_parser = ELCP_POST_CR;
|
||||||
|
|
||||||
|
if (wsi->chunked && eff_buf.token_len) {
|
||||||
|
goto spin_chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wsi->chunked) {
|
||||||
|
n = 0;
|
||||||
|
goto handled;
|
||||||
|
}
|
||||||
|
|
||||||
wsi->u.http.content_remain -= n;
|
wsi->u.http.content_remain -= n;
|
||||||
if (wsi->u.http.content_remain)
|
if (wsi->u.http.content_remain)
|
||||||
goto handled;
|
goto handled;
|
||||||
|
|
||||||
lwsl_notice("%s: client http receved all content\n",
|
|
||||||
__func__);
|
|
||||||
if (user_callback_handle_rxflow(wsi->protocol->callback,
|
if (user_callback_handle_rxflow(wsi->protocol->callback,
|
||||||
wsi, LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
|
wsi, LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
|
||||||
wsi->user_space, NULL, 0))
|
wsi->user_space, NULL, 0))
|
||||||
|
@ -821,7 +907,7 @@ drain:
|
||||||
} while (more);
|
} while (more);
|
||||||
|
|
||||||
if (wsi->u.hdr.ah) {
|
if (wsi->u.hdr.ah) {
|
||||||
lwsl_err("%s: %p: detaching inherited used ah\n",
|
lwsl_info("%s: %p: detaching inherited used ah\n",
|
||||||
__func__, wsi);
|
__func__, wsi);
|
||||||
/* show we used all the pending rx up */
|
/* show we used all the pending rx up */
|
||||||
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
|
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
|
||||||
|
|
Loading…
Add table
Reference in a new issue