1/* 2 * libwebsockets - small server side websockets and web server implementation 3 * 4 * Copyright (C) 2019 - 2020 Andy Green <andy@warmcat.com> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to 8 * deal in the Software without restriction, including without limitation the 9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 */ 24 25#include <private-lib-core.h> 26 27extern int 28secstream_h1(struct lws *wsi, enum lws_callback_reasons reason, void *user, 29 void *in, size_t len); 30 31static int 32secstream_h2(struct lws *wsi, enum lws_callback_reasons reason, void *user, 33 void *in, size_t len) 34{ 35 lws_ss_handle_t *h = (lws_ss_handle_t *)lws_get_opaque_user_data(wsi); 36 lws_ss_state_return_t r; 37 int n; 38 39 switch (reason) { 40 41 case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: 42 43 if (!h) 44 return -1; 45 46#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) 47 if (h->being_serialized) { 48 /* 49 * We are the proxy-side SS for a remote client... we 50 * need to inform the client about the initial tx credit 51 * to write to it that the remote h2 server set up 52 */ 53 lwsl_info("%s: reporting initial tx cr from server %d\n", 54 __func__, wsi->txc.tx_cr); 55 ss_proxy_onward_txcr((void *)(h + 1), wsi->txc.tx_cr); 56 } 57#endif 58 59 n = secstream_h1(wsi, reason, user, in, len); 60 61 if (!n && (h->policy->flags & LWSSSPOLF_LONG_POLL)) { 62 lwsl_notice("%s: h2 client %s entering LONG_POLL\n", 63 __func__, lws_wsi_tag(wsi)); 64 lws_h2_client_stream_long_poll_rxonly(wsi); 65 } 66 return n; 67 68 case LWS_CALLBACK_CLOSED_CLIENT_HTTP: 69 /* 70 * Only allow the wsi that the handle believes is representing 71 * him to report closure up to h1 72 */ 73 if (!h || h->wsi != wsi) 74 return 0; 75 76 break; 77 78 case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: 79 80 if (!h) 81 return -1; 82 83 // lwsl_err("%s: h2 COMPLETED_CLIENT_HTTP\n", __func__); 84 r = 0; 85 if (h->hanging_som) 86 r = h->info.rx(ss_to_userobj(h), NULL, 0, LWSSS_FLAG_EOM); 87 88 h->txn_ok = 1; 89 lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */ 90 if (h->hanging_som && r == LWSSSSRET_DESTROY_ME) 91 return _lws_ss_handle_state_ret_CAN_DESTROY_HANDLE(r, wsi, &h); 92 h->hanging_som = 0; 93 break; 94 95 case LWS_CALLBACK_WSI_TX_CREDIT_GET: 96 97 if (!h) 98 return -1; 99 100 /* 101 * The peer has sent us additional tx credit... 102 */ 103 lwsl_info("%s: LWS_CALLBACK_WSI_TX_CREDIT_GET: %d\n", 104 __func__, (int)len); 105 106#if defined(LWS_WITH_SECURE_STREAMS_PROXY_API) 107 if (h->being_serialized) 108 /* we are the proxy-side SS for a remote client */ 109 ss_proxy_onward_txcr((void *)(h + 1), (int)len); 110#endif 111 break; 112 113 default: 114 break; 115 } 116 117 return secstream_h1(wsi, reason, user, in, len); 118} 119 120const struct lws_protocols protocol_secstream_h2 = { 121 "lws-secstream-h2", 122 secstream_h2, 123 0, 0, 0, NULL, 0 124}; 125 126/* 127 * Munge connect info according to protocol-specific considerations... this 128 * usually means interpreting aux in a protocol-specific way and using the 129 * pieces at connection setup time, eg, http url pieces. 130 * 131 * len bytes of buf can be used for things with scope until after the actual 132 * connect. 133 */ 134 135int 136secstream_connect_munge_h2(lws_ss_handle_t *h, char *buf, size_t len, 137 struct lws_client_connect_info *i, 138 union lws_ss_contemp *ct) 139{ 140 const char *pbasis = h->policy->u.http.url; 141 size_t used_in, used_out; 142 lws_strexp_t exp; 143 144 /* i.path on entry is used to override the policy urlpath if not "" */ 145 146 if (i->path[0]) 147 pbasis = i->path; 148 149 if (h->policy->flags & LWSSSPOLF_QUIRK_NGHTTP2_END_STREAM) 150 i->ssl_connection |= LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM; 151 152 if (h->policy->flags & LWSSSPOLF_H2_QUIRK_OVERFLOWS_TXCR) 153 i->ssl_connection |= LCCSCF_H2_QUIRK_OVERFLOWS_TXCR; 154 155 if (h->policy->flags & LWSSSPOLF_HTTP_MULTIPART) 156 i->ssl_connection |= LCCSCF_HTTP_MULTIPART_MIME; 157 158 if (h->policy->flags & LWSSSPOLF_HTTP_X_WWW_FORM_URLENCODED) 159 i->ssl_connection |= LCCSCF_HTTP_X_WWW_FORM_URLENCODED; 160 161 if (h->policy->flags & LWSSSPOLF_HTTP_CACHE_COOKIES) 162 i->ssl_connection |= LCCSCF_CACHE_COOKIES; 163 164 i->ssl_connection |= LCCSCF_PIPELINE; 165 166 i->alpn = "h2"; 167 168 /* initial peer tx credit */ 169 170 if (h->info.manual_initial_tx_credit) { 171 i->ssl_connection |= LCCSCF_H2_MANUAL_RXFLOW; 172 i->manual_initial_tx_credit = h->info.manual_initial_tx_credit; 173 lwsl_info("%s: initial txcr %d\n", __func__, 174 i->manual_initial_tx_credit); 175 } 176 177 if (!pbasis) 178 return 0; 179 180 /* protocol aux is the path part */ 181 182 i->path = buf; 183 buf[0] = '/'; 184 185 lws_strexp_init(&exp, (void *)h, lws_ss_exp_cb_metadata, buf + 1, len - 1); 186 187 if (lws_strexp_expand(&exp, pbasis, strlen(pbasis), 188 &used_in, &used_out) != LSTRX_DONE) 189 return 1; 190 191 return 0; 192} 193 194static int 195secstream_tx_credit_add_h2(lws_ss_handle_t *h, int add) 196{ 197 lwsl_info("%s: %s: add %d\n", __func__, lws_ss_tag(h), add); 198 if (h->wsi) 199 return lws_h2_update_peer_txcredit(h->wsi, (unsigned int)LWS_H2_STREAM_SID, add); 200 201 return 0; 202} 203 204static int 205secstream_tx_credit_est_h2(lws_ss_handle_t *h) 206{ 207 if (h->wsi) { 208 lwsl_info("%s: %s: est %d\n", __func__, lws_ss_tag(h), 209 lws_h2_get_peer_txcredit_estimate(h->wsi)); 210 211 return lws_h2_get_peer_txcredit_estimate(h->wsi); 212 } 213 214 lwsl_info("%s: %s: Unknown (0)\n", __func__, lws_ss_tag(h)); 215 216 return 0; 217} 218 219const struct ss_pcols ss_pcol_h2 = { 220 "h2", 221 "h2", 222 &protocol_secstream_h2, 223 secstream_connect_munge_h2, 224 secstream_tx_credit_add_h2, 225 secstream_tx_credit_est_h2 226}; 227