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://
|
||||
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
|
||||
operations.
|
||||
operations. Receiving transfer-encoding: chunked is supported.
|
||||
|
||||
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,
|
||||
|
|
16
lib/client.c
16
lib/client.c
|
@ -628,6 +628,17 @@ lws_client_interpret_server_handshake(struct lws *wsi)
|
|||
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)) {
|
||||
wsi->u.http.content_length =
|
||||
atoi(lws_hdr_simple_ptr(wsi,
|
||||
|
@ -635,8 +646,9 @@ lws_client_interpret_server_handshake(struct lws *wsi)
|
|||
lwsl_notice("%s: incoming content length %d\n", __func__,
|
||||
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 */
|
||||
wsi->u.http.connection_type = HTTP_CONNECTION_CLOSE;
|
||||
} else /* can't do 1.1 without a content length or chunked */
|
||||
if (!wsi->chunked)
|
||||
wsi->u.http.connection_type = HTTP_CONNECTION_CLOSE;
|
||||
|
||||
/*
|
||||
* we seem to be good to go, give client last chance to check
|
||||
|
|
|
@ -496,7 +496,7 @@ lws_hdr_simple_create(struct lws *wsi, enum lws_token_indexes h, const char *s)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static signed char char_to_hex(const char c)
|
||||
signed char char_to_hex(const char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
|
|
|
@ -1054,7 +1054,18 @@ struct lws_cgi {
|
|||
|
||||
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
|
||||
|
||||
struct lws {
|
||||
|
@ -1121,6 +1132,9 @@ struct lws {
|
|||
unsigned int trunc_alloc_len; /* size of malloc */
|
||||
unsigned int trunc_offset; /* where we are in terms of spilling */
|
||||
unsigned int trunc_len; /* how much is buffered */
|
||||
#ifndef LWS_NO_CLIENT
|
||||
int chunk_remaining;
|
||||
#endif
|
||||
|
||||
unsigned int hdr_parsing_completed: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 */
|
||||
#ifndef LWS_NO_CLIENT
|
||||
unsigned int do_ws:1; /* whether we are doing http or ws flow */
|
||||
unsigned int chunked:1; /* if the clientside connection is chunked */
|
||||
#endif
|
||||
#ifndef LWS_NO_EXTENSIONS
|
||||
unsigned int extension_data_pending:1;
|
||||
|
@ -1161,6 +1176,9 @@ struct lws {
|
|||
char cgi_channel; /* which of stdin/out/err */
|
||||
char hdr_state;
|
||||
#endif
|
||||
#ifndef LWS_NO_CLIENT
|
||||
char chunk_parser; /* enum lws_chunk_parser */
|
||||
#endif
|
||||
};
|
||||
|
||||
LWS_EXTERN int log_level;
|
||||
|
|
102
lib/service.c
102
lib/service.c
|
@ -760,24 +760,110 @@ read:
|
|||
*/
|
||||
drain:
|
||||
if (wsi->mode == LWSCM_HTTP_CLIENT_ACCEPTED) {
|
||||
lwsl_notice("%s: calling LWS_CALLBACK_RECEIVE_CLIENT_HTTP, "
|
||||
"rem %d len %d\n", __func__,
|
||||
wsi->u.http.content_remain, eff_buf.token_len);
|
||||
if ((int)wsi->u.http.content_remain < eff_buf.token_len)
|
||||
/*
|
||||
* server may insist on transfer-encoding: chunked,
|
||||
* so http client must deal with it
|
||||
*/
|
||||
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;
|
||||
else
|
||||
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,
|
||||
wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP,
|
||||
wsi->user_space, (void *)eff_buf.token,
|
||||
eff_buf.token_len))
|
||||
n))
|
||||
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;
|
||||
if (wsi->u.http.content_remain)
|
||||
goto handled;
|
||||
|
||||
lwsl_notice("%s: client http receved all content\n",
|
||||
__func__);
|
||||
if (user_callback_handle_rxflow(wsi->protocol->callback,
|
||||
wsi, LWS_CALLBACK_COMPLETED_CLIENT_HTTP,
|
||||
wsi->user_space, NULL, 0))
|
||||
|
@ -821,7 +907,7 @@ drain:
|
|||
} while (more);
|
||||
|
||||
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);
|
||||
/* show we used all the pending rx up */
|
||||
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
|
||||
|
|
Loading…
Add table
Reference in a new issue