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
27 extern int
28 secstream_h1(struct lws *wsi, enum lws_callback_reasons reason, void *user,
29 void *in, size_t len);
30
31 static int
secstream_h2(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)32 secstream_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 int n;
37
38 switch (reason) {
39
40 case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP:
41
42 #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
43 if (h->being_serialized) {
44 /*
45 * We are the proxy-side SS for a remote client... we
46 * need to inform the client about the initial tx credit
47 * to write to it that the remote h2 server set up
48 */
49 lwsl_info("%s: reporting initial tx cr from server %d\n",
50 __func__, wsi->txc.tx_cr);
51 ss_proxy_onward_txcr((void *)&h[1], wsi->txc.tx_cr);
52 }
53 #endif
54
55 n = secstream_h1(wsi, reason, user, in, len);
56
57 if (!n && (h->policy->flags & LWSSSPOLF_LONG_POLL)) {
58 lwsl_notice("%s: h2 client %p entering LONG_POLL\n",
59 __func__, wsi);
60 lws_h2_client_stream_long_poll_rxonly(wsi);
61 }
62 return n;
63
64 case LWS_CALLBACK_COMPLETED_CLIENT_HTTP:
65 // lwsl_err("%s: h2 COMPLETED_CLIENT_HTTP\n", __func__);
66 h->info.rx(ss_to_userobj(h), NULL, 0, LWSSS_FLAG_EOM);
67 h->wsi = NULL;
68 h->txn_ok = 1;
69 //bad = status != 200;
70 lws_cancel_service(lws_get_context(wsi)); /* abort poll wait */
71 break;
72
73 case LWS_CALLBACK_WSI_TX_CREDIT_GET:
74 /*
75 * The peer has sent us additional tx credit...
76 */
77 lwsl_info("%s: LWS_CALLBACK_WSI_TX_CREDIT_GET: %d\n",
78 __func__, (int32_t)len);
79
80 #if defined(LWS_WITH_SECURE_STREAMS_PROXY_API)
81 if (h->being_serialized)
82 /* we are the proxy-side SS for a remote client */
83 ss_proxy_onward_txcr((void *)&h[1], (int)len);
84 #endif
85 break;
86
87 default:
88 break;
89 }
90
91 return secstream_h1(wsi, reason, user, in, len);
92 }
93
94 const struct lws_protocols protocol_secstream_h2 = {
95 "lws-secstream-h2",
96 secstream_h2,
97 0,
98 0,
99 };
100
101 /*
102 * Munge connect info according to protocol-specific considerations... this
103 * usually means interpreting aux in a protocol-specific way and using the
104 * pieces at connection setup time, eg, http url pieces.
105 *
106 * len bytes of buf can be used for things with scope until after the actual
107 * connect.
108 */
109
110 int
secstream_connect_munge_h2(lws_ss_handle_t * h,char * buf,size_t len,struct lws_client_connect_info * i,union lws_ss_contemp * ct)111 secstream_connect_munge_h2(lws_ss_handle_t *h, char *buf, size_t len,
112 struct lws_client_connect_info *i,
113 union lws_ss_contemp *ct)
114 {
115 if (h->policy->flags & LWSSSPOLF_QUIRK_NGHTTP2_END_STREAM)
116 i->ssl_connection |= LCCSCF_H2_QUIRK_NGHTTP2_END_STREAM;
117
118 if (h->policy->flags & LWSSSPOLF_H2_QUIRK_OVERFLOWS_TXCR)
119 i->ssl_connection |= LCCSCF_H2_QUIRK_OVERFLOWS_TXCR;
120
121 if (h->policy->flags & LWSSSPOLF_HTTP_MULTIPART)
122 i->ssl_connection |= LCCSCF_HTTP_MULTIPART_MIME;
123
124 if (h->policy->flags & LWSSSPOLF_HTTP_X_WWW_FORM_URLENCODED)
125 i->ssl_connection |= LCCSCF_HTTP_X_WWW_FORM_URLENCODED;
126
127 i->ssl_connection |= LCCSCF_PIPELINE;
128
129 i->alpn = "h2";
130
131 /* initial peer tx credit */
132
133 if (h->info.manual_initial_tx_credit) {
134 i->ssl_connection |= LCCSCF_H2_MANUAL_RXFLOW;
135 i->manual_initial_tx_credit = h->info.manual_initial_tx_credit;
136 lwsl_info("%s: initial txcr %d\n", __func__,
137 i->manual_initial_tx_credit);
138 }
139
140 if (!h->policy->u.http.url)
141 return 0;
142
143 /* protocol aux is the path part */
144
145 i->path = buf;
146 lws_snprintf(buf, len, "/%s", h->policy->u.http.url);
147
148 return 0;
149 }
150
151 static int
secstream_tx_credit_add_h2(lws_ss_handle_t * h,int add)152 secstream_tx_credit_add_h2(lws_ss_handle_t *h, int add)
153 {
154 lwsl_info("%s: h %p: add %d\n", __func__, h, add);
155 if (h->wsi)
156 return lws_h2_update_peer_txcredit(h->wsi, LWS_H2_STREAM_SID, add);
157
158 return 0;
159 }
160
161 static int
secstream_tx_credit_est_h2(lws_ss_handle_t * h)162 secstream_tx_credit_est_h2(lws_ss_handle_t *h)
163 {
164 if (h->wsi) {
165 lwsl_info("%s: h %p: est %d\n", __func__, h,
166 lws_h2_get_peer_txcredit_estimate(h->wsi));
167
168 return lws_h2_get_peer_txcredit_estimate(h->wsi);
169 }
170
171 lwsl_info("%s: h %p: Unknown (0)\n", __func__, h);
172
173 return 0;
174 }
175
176 const struct ss_pcols ss_pcol_h2 = {
177 "h2",
178 NULL,
179 "lws-secstream-h2",
180 secstream_connect_munge_h2,
181 secstream_tx_credit_add_h2,
182 secstream_tx_credit_est_h2
183 };
184