diff --git a/lib/roles/h1/ops-h1.c b/lib/roles/h1/ops-h1.c index f0ade7f08..1674585ab 100644 --- a/lib/roles/h1/ops-h1.c +++ b/lib/roles/h1/ops-h1.c @@ -181,7 +181,8 @@ http_postbody: if (lwsi_role_h2(wsi) && !wsi->http.content_length_given) { struct lws *w = lws_get_network_wsi(wsi); - lwsl_info("%s: h2: nwsi h2 flags %d\n", __func__, + if (w) + lwsl_info("%s: h2: nwsi h2 flags %d\n", __func__, w->h2.h2n ? w->h2.h2n->flags: -1); if (w && w->h2.h2n && !(w->h2.h2n->flags & 1)) { diff --git a/lib/roles/h2/http2.c b/lib/roles/h2/http2.c index 115b2207a..c244239a8 100644 --- a/lib/roles/h2/http2.c +++ b/lib/roles/h2/http2.c @@ -370,11 +370,14 @@ bail1: } -int lws_h2_issue_preface(struct lws *wsi) +int +lws_h2_issue_preface(struct lws *wsi) { struct lws_h2_netconn *h2n = wsi->h2.h2n; struct lws_h2_protocol_send *pps; + lwsl_notice("%s: wsi %p: fd %d\n", __func__, wsi, (int)wsi->desc.sockfd); + if (lws_issue_raw(wsi, (uint8_t *)preface, strlen(preface)) != (int)strlen(preface)) return 1; @@ -997,9 +1000,14 @@ lws_h2_parse_frame_header(struct lws *wsi) /* ie, IGNORE */ h2n->type = LWS_H2_FRAME_TYPE_COUNT; } else { + lwsl_info("%s: received %d bytes data for unknown sid %d, highest known %d\n", + __func__, (int)h2n->length, (int)h2n->sid, (int)h2n->highest_sid_opened); + +// if (h2n->sid > h2n->highest_sid_opened) { lws_h2_goaway(wsi, H2_ERR_STREAM_CLOSED, "Data for nonexistent sid"); return 0; +// } } } /* if the sid is credible, treat as wsi for it closed */ diff --git a/lib/roles/h2/ops-h2.c b/lib/roles/h2/ops-h2.c index eba2564dc..264ec4b65 100644 --- a/lib/roles/h2/ops-h2.c +++ b/lib/roles/h2/ops-h2.c @@ -963,6 +963,18 @@ rops_perform_user_POLLOUT_h2(struct lws *wsi) lws_h2_bind_for_post_before_action(w); + /* + * Well, we could be getting a POST from the client, it + * may not have any content-length. In that case, we + * will be in LRS_BODY state, we can't actually start + * the action until we had the body and the stream is + * half-closed, indicating that we can reply + */ + + if (lwsi_state(w) == LRS_BODY && + w->h2.h2_state != LWS_H2_STATE_HALF_CLOSED_REMOTE) + goto next_child; + lwsl_info(" h2 action start...\n"); n = lws_http_action(w); if (n < 0) diff --git a/lib/roles/http/client/client-http.c b/lib/roles/http/client/client-http.c index fc50615e3..50a3ad212 100644 --- a/lib/roles/http/client/client-http.c +++ b/lib/roles/http/client/client-http.c @@ -137,6 +137,8 @@ lws_http_client_socket_service(struct lws *wsi, struct lws_pollfd *pollfd) case LRS_H1C_ISSUE_HANDSHAKE: + lwsl_notice("%s: LRS_H1C_ISSUE_HANDSHAKE\n", __func__); + /* * we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE * timeout protection set in client-handshake.c @@ -150,13 +152,37 @@ start_ws_handshake: if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) return -1; +#if defined(LWS_ROLE_H2) || defined(LWS_WITH_TLS) + if ( +#if defined(LWS_WITH_TLS) + !(wsi->tls.use_ssl & LCCSCF_USE_SSL) +#endif +#if defined(LWS_ROLE_H2) && defined(LWS_WITH_TLS) + && +#endif +#if defined(LWS_ROLE_H2) + !(wsi->flags & LCCSCF_H2_PRIOR_KNOWLEDGE) +#endif + ) + goto hs2; +#endif + #if defined(LWS_WITH_TLS) n = lws_client_create_tls(wsi, &cce, 1); - if (n < 0) + if (n == CCTLS_RETURN_ERROR) goto bail3; - if (n == 1) + if (n == CCTLS_RETURN_RETRY) return 0; + /* + * lws_client_create_tls() can already have done the + * whole tls setup and preface send... if so he set our state + * to LRS_H1C_ISSUE_HANDSHAKE2... let's proceed but be prepared + * to notice our state and not resend the preface... + */ + + lwsl_notice("%s: LRS_H1C_ISSUE_HANDSHAKE fallthru\n", __func__); + /* fallthru */ case LRS_WAITING_SSL: @@ -171,7 +197,7 @@ start_ws_handshake: } } else { wsi->tls.ssl = NULL; - if(wsi->flags & LCCSCF_H2_PRIOR_KNOWLEDGE) { + if (wsi->flags & LCCSCF_H2_PRIOR_KNOWLEDGE) { lwsl_info("h2 prior knowledge\n"); lws_role_call_alpn_negotiated(wsi, "h2"); } @@ -187,8 +213,9 @@ start_ws_handshake: lws_det_lat_cb(wsi->a.context, &wsi->detlat); } #endif + #if defined (LWS_WITH_HTTP2) - if (wsi->client_h2_alpn) { + if (wsi->client_h2_alpn && lwsi_state(wsi) != LRS_H1C_ISSUE_HANDSHAKE2) { /* * We connected to the server and set up tls and * negotiated "h2" or connected as clear text @@ -199,9 +226,8 @@ start_ws_handshake: */ #if defined(LWS_WITH_TLS) - if (wsi->tls.use_ssl & LCCSCF_USE_SSL) { + if (wsi->tls.use_ssl & LCCSCF_USE_SSL) lws_tls_server_conn_alpn(wsi); - } #endif /* send the H2 preface to legitimize the connection */ @@ -221,6 +247,9 @@ start_ws_handshake: /* fallthru */ case LRS_H1C_ISSUE_HANDSHAKE2: + +hs2: + p = lws_generate_client_handshake(wsi, p); if (p == NULL) { if (wsi->role_ops == &role_ops_raw_skt @@ -336,6 +365,10 @@ client_http_body_sent: goto bail3; } + if (pollfd->revents & LWS_POLLOUT) + if (lws_change_pollfd(wsi, LWS_POLLOUT, 0)) + return -1; + if (!(pollfd->revents & LWS_POLLIN)) break; diff --git a/lib/roles/ws/ops-ws.c b/lib/roles/ws/ops-ws.c index 8123916c1..de468f831 100644 --- a/lib/roles/ws/ops-ws.c +++ b/lib/roles/ws/ops-ws.c @@ -1192,7 +1192,8 @@ drain: } //lws_buflist_describe(&wsi->buflist, wsi, __func__); //lwsl_notice("%s: consuming %d / %d\n", __func__, n, ebuf.len); - if (lws_buflist_aware_finished_consuming(wsi, &ebuf, n, + if (ebuf.len < 0 || + lws_buflist_aware_finished_consuming(wsi, &ebuf, n, buffered, __func__)) return LWS_HPI_RET_PLEASE_CLOSE_ME; } diff --git a/lib/tls/tls-client.c b/lib/tls/tls-client.c index ed1a46c44..139003964 100644 --- a/lib/tls/tls-client.c +++ b/lib/tls/tls-client.c @@ -199,6 +199,7 @@ lws_client_create_tls(struct lws *wsi, const char **pcce, int do_c1) } else wsi->tls.ssl = NULL; +#if 0 #if defined (LWS_WITH_HTTP2) if (wsi->client_h2_alpn) { /* @@ -217,7 +218,10 @@ lws_client_create_tls(struct lws *wsi, const char **pcce, int do_c1) *pcce = "error sending h2 preface"; return CCTLS_RETURN_ERROR; } + + lwsi_set_state(wsi, LRS_H1C_ISSUE_HANDSHAKE2); } +#endif #endif return CCTLS_RETURN_DONE; /* OK */ diff --git a/minimal-examples/http-client/minimal-http-client-multi/minimal-http-client-multi.c b/minimal-examples/http-client/minimal-http-client-multi/minimal-http-client-multi.c index a97a18cb5..1dfad888d 100644 --- a/minimal-examples/http-client/minimal-http-client-multi/minimal-http-client-multi.c +++ b/minimal-examples/http-client/minimal-http-client-multi/minimal-http-client-multi.c @@ -88,11 +88,11 @@ callback_http(struct lws *wsi, enum lws_callback_reasons reason, * Tell lws we are going to send the body next... */ if (posting && !lws_http_is_redirected_to_get(wsi)) { - lwsl_user("%s: doing POST flow\n", __func__); + lwsl_user("%s: conn %d, doing POST flow\n", __func__, idx); lws_client_http_body_pending(wsi, 1); lws_callback_on_writable(wsi); } else - lwsl_user("%s: doing GET flow\n", __func__); + lwsl_user("%s: conn %d, doing GET flow\n", __func__, idx); break; /* uninterpreted http content */