diff --git a/lib/handshake.c b/lib/handshake.c index b7107de2..a2f89333 100644 --- a/lib/handshake.c +++ b/lib/handshake.c @@ -63,7 +63,7 @@ LWS_VISIBLE int lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len) { unsigned char *last_char, *oldbuf = buf; - lws_filepos_t body_chunk_len; + lws_filepos_t body_chunk_len, inlen = len; size_t n; switch (wsi->state) { @@ -71,7 +71,6 @@ lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len) case LWSS_HTTP2_AWAIT_CLIENT_PREFACE: case LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS: case LWSS_HTTP2_ESTABLISHED: - n = 0; /* * wsi here is always the network connection wsi, not a stream * wsi. Once we unpicked the framing we will find the right @@ -82,28 +81,31 @@ lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len) * ESTABLISHED state for the inner payload, handled in a later * case. */ - while (n < len) { + while (len) { /* * we were accepting input but now we stopped doing so */ if (lws_is_flowcontrolled(wsi)) { - lws_rxflow_cache(wsi, buf, (int)n, (int)len); + lws_rxflow_cache(wsi, buf, 0, (int)len); return 1; } - /* account for what we're using in rxflow buffer */ - if (wsi->rxflow_buffer) { - wsi->rxflow_pos++; - assert(wsi->rxflow_pos <= wsi->rxflow_len); - } - - if (lws_h2_parser(wsi, buf[n++])) { + if (lws_h2_parser(wsi, buf, len, &body_chunk_len)) { lwsl_debug("%s: http2_parser bailed\n", __func__); goto bail; } + + /* account for what we're using in rxflow buffer */ + if (wsi->rxflow_buffer) { + wsi->rxflow_pos += (int)body_chunk_len; + assert(wsi->rxflow_pos <= wsi->rxflow_len); + } + + buf += body_chunk_len; + len -= body_chunk_len; } - lwsl_debug("%s: used up block of %d\n", __func__, (int)len); + lwsl_debug("%s: used up block of %d\n", __func__, (int)inlen); break; #endif @@ -274,7 +276,7 @@ postbody_completion: read_ok: /* Nothing more to do for now */ - lwsl_info("%s: read_ok, used %ld\n", __func__, (long)(buf - oldbuf)); + lwsl_info("%s: %p: read_ok, used %ld (len %d, state %d)\n", __func__, wsi, (long)(buf - oldbuf), (int)len, wsi->state); return lws_ptr_diff(buf, oldbuf); diff --git a/lib/http2/http2.c b/lib/http2/http2.c index 7bc2f1f7..e69bb0d4 100644 --- a/lib/http2/http2.c +++ b/lib/http2/http2.c @@ -1319,19 +1319,25 @@ lws_h2_parse_end_of_frame(struct lws *wsi) } int -lws_h2_parser(struct lws *wsi, unsigned char c) +lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, + lws_filepos_t *inused) { struct lws_h2_netconn *h2n = wsi->h2.h2n; struct lws_h2_protocol_send *pps; + unsigned char c, *oldin = in; int n; if (!h2n) - return 1; + goto fail; + + while (inlen--) { + + c = *in++; switch (wsi->state) { case LWSS_HTTP2_AWAIT_CLIENT_PREFACE: if (preface[h2n->count++] != c) - return 1; + goto fail; if (preface[h2n->count]) break; @@ -1348,7 +1354,7 @@ lws_h2_parser(struct lws *wsi, unsigned char c) */ pps = lws_h2_new_pps(LWS_H2_PPS_MY_SETTINGS); if (!pps) - return 1; + goto fail; lws_pps_schedule(wsi, pps); break; @@ -1421,7 +1427,7 @@ lws_h2_parser(struct lws *wsi, unsigned char c) break; if (lws_hpack_interpret(h2n->swsi, c)) { lwsl_info("%s: hpack failed\n", __func__); - return 1; + goto fail; } break; @@ -1458,8 +1464,11 @@ lws_h2_parser(struct lws *wsi, unsigned char c) if (!h2n->swsi) break; - h2n->swsi->state = LWSS_HTTP_BODY; - h2n->inside++; + if (h2n->swsi->state == LWSS_HTTP2_ESTABLISHED) { + h2n->swsi->state = LWSS_HTTP_BODY; + lwsl_notice("%s: setting swsi %p to LWSS_HTTP_BODY\n", __func__, h2n->swsi); + } + if (lws_hdr_total_length(h2n->swsi, WSI_TOKEN_HTTP_CONTENT_LENGTH) && h2n->swsi->http.rx_content_length && @@ -1470,10 +1479,15 @@ lws_h2_parser(struct lws *wsi, unsigned char c) break; } - n = lws_read(h2n->swsi, &c, 1); + n = lws_read(h2n->swsi, in - 1, inlen + 1); if (n < 0) break; + inlen -= n - 1; + in += n - 1; + h2n->inside += n; + h2n->count += n - 1; + break; case LWS_H2_FRAME_TYPE_PRIORITY: @@ -1520,7 +1534,7 @@ lws_h2_parser(struct lws *wsi, unsigned char c) lwsl_notice("%s: unhandled frame type %d\n", __func__, h2n->type); - return 1; + goto fail; } frame_end: @@ -1531,7 +1545,7 @@ frame_end: * end of frame just happened */ if (lws_h2_parse_end_of_frame(wsi)) - return 1; + goto fail; break; try_frame_start: @@ -1569,11 +1583,20 @@ try_frame_start: } if (h2n->frame_state == LWS_H2_FRAME_HEADER_LENGTH) if (lws_h2_parse_frame_header(wsi)) - return 1; + goto fail; break; } + } + + *inused = in - oldin; + return 0; + +fail: + *inused = in - oldin; + + return 1; } int @@ -1597,7 +1620,7 @@ lws_h2_ws_handshake(struct lws *wsi) wsi->protocol->name && wsi->protocol->name[0]) { if (lws_add_http_header_by_token(wsi, WSI_TOKEN_PROTOCOL, (unsigned char *)wsi->protocol->name, - strlen(wsi->protocol->name), &p, end)) + (int)strlen(wsi->protocol->name), &p, end)) return -1; } diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 20e884af..ed2085ab 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -2246,7 +2246,8 @@ LWS_EXTERN int lws_h2_settings(struct lws *nwsi, struct http2_settings *settings, unsigned char *buf, int len); LWS_EXTERN int -lws_h2_parser(struct lws *wsi, unsigned char c); +lws_h2_parser(struct lws *wsi, unsigned char *in, lws_filepos_t inlen, + lws_filepos_t *inused); LWS_EXTERN int lws_h2_do_pps_send(struct lws *wsi); LWS_EXTERN int lws_h2_frame_write(struct lws *wsi, int type, int flags, unsigned int sid, unsigned int len,