1 /*
2 * nghttp2 - HTTP/2 C Library
3 *
4 * Copyright (c) 2012 Tatsuhiro Tsujikawa
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 #include "nghttp2_test_helper.h"
26
27 #include <stdio.h>
28 #include <assert.h>
29
30 #include <CUnit/CUnit.h>
31
32 #include "nghttp2_helper.h"
33 #include "nghttp2_priority_spec.h"
34
unpack_framebuf(nghttp2_frame * frame,nghttp2_bufs * bufs)35 int unpack_framebuf(nghttp2_frame *frame, nghttp2_bufs *bufs) {
36 nghttp2_buf *buf;
37
38 /* Assuming we have required data in first buffer. We don't decode
39 header block so, we don't mind its space */
40 buf = &bufs->head->buf;
41 return unpack_frame(frame, buf->pos, nghttp2_buf_len(buf));
42 }
43
unpack_frame(nghttp2_frame * frame,const uint8_t * in,size_t len)44 int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len) {
45 int rv = 0;
46 const uint8_t *payload = in + NGHTTP2_FRAME_HDLEN;
47 size_t payloadlen = len - NGHTTP2_FRAME_HDLEN;
48 size_t payloadoff;
49 nghttp2_mem *mem;
50
51 mem = nghttp2_mem_default();
52
53 nghttp2_frame_unpack_frame_hd(&frame->hd, in);
54 switch (frame->hd.type) {
55 case NGHTTP2_HEADERS:
56 payloadoff = ((frame->hd.flags & NGHTTP2_FLAG_PADDED) > 0);
57 nghttp2_frame_unpack_headers_payload(&frame->headers, payload + payloadoff);
58 break;
59 case NGHTTP2_PRIORITY:
60 nghttp2_frame_unpack_priority_payload(&frame->priority, payload);
61 break;
62 case NGHTTP2_RST_STREAM:
63 nghttp2_frame_unpack_rst_stream_payload(&frame->rst_stream, payload);
64 break;
65 case NGHTTP2_SETTINGS:
66 rv = nghttp2_frame_unpack_settings_payload2(
67 &frame->settings.iv, &frame->settings.niv, payload, payloadlen, mem);
68 break;
69 case NGHTTP2_PUSH_PROMISE:
70 nghttp2_frame_unpack_push_promise_payload(&frame->push_promise, payload);
71 break;
72 case NGHTTP2_PING:
73 nghttp2_frame_unpack_ping_payload(&frame->ping, payload);
74 break;
75 case NGHTTP2_GOAWAY:
76 nghttp2_frame_unpack_goaway_payload2(&frame->goaway, payload, payloadlen,
77 mem);
78 break;
79 case NGHTTP2_WINDOW_UPDATE:
80 nghttp2_frame_unpack_window_update_payload(&frame->window_update, payload);
81 break;
82 case NGHTTP2_ALTSVC:
83 assert(payloadlen > 2);
84 nghttp2_frame_unpack_altsvc_payload2(&frame->ext, payload, payloadlen, mem);
85 break;
86 case NGHTTP2_ORIGIN:
87 rv = nghttp2_frame_unpack_origin_payload(&frame->ext, payload, payloadlen,
88 mem);
89 break;
90 case NGHTTP2_PRIORITY_UPDATE:
91 assert(payloadlen >= 4);
92 nghttp2_frame_unpack_priority_update_payload(
93 &frame->ext, (uint8_t *)payload, payloadlen);
94 break;
95 default:
96 /* Must not be reachable */
97 assert(0);
98 }
99 return rv;
100 }
101
strmemeq(const char * a,const uint8_t * b,size_t bn)102 int strmemeq(const char *a, const uint8_t *b, size_t bn) {
103 const uint8_t *c;
104 if (!a || !b) {
105 return 0;
106 }
107 c = b + bn;
108 for (; *a && b != c && *a == *b; ++a, ++b)
109 ;
110 return !*a && b == c;
111 }
112
nvnameeq(const char * a,nghttp2_nv * nv)113 int nvnameeq(const char *a, nghttp2_nv *nv) {
114 return strmemeq(a, nv->name, nv->namelen);
115 }
116
nvvalueeq(const char * a,nghttp2_nv * nv)117 int nvvalueeq(const char *a, nghttp2_nv *nv) {
118 return strmemeq(a, nv->value, nv->valuelen);
119 }
120
nva_out_init(nva_out * out)121 void nva_out_init(nva_out *out) {
122 memset(out->nva, 0, sizeof(out->nva));
123 out->nvlen = 0;
124 }
125
nva_out_reset(nva_out * out,nghttp2_mem * mem)126 void nva_out_reset(nva_out *out, nghttp2_mem *mem) {
127 size_t i;
128 for (i = 0; i < out->nvlen; ++i) {
129 mem->free(out->nva[i].name, NULL);
130 mem->free(out->nva[i].value, NULL);
131 }
132 memset(out->nva, 0, sizeof(out->nva));
133 out->nvlen = 0;
134 }
135
add_out(nva_out * out,nghttp2_nv * nv,nghttp2_mem * mem)136 void add_out(nva_out *out, nghttp2_nv *nv, nghttp2_mem *mem) {
137 nghttp2_nv *onv = &out->nva[out->nvlen];
138 if (nv->namelen) {
139 onv->name = mem->malloc(nv->namelen, NULL);
140 memcpy(onv->name, nv->name, nv->namelen);
141 } else {
142 onv->name = NULL;
143 }
144 if (nv->valuelen) {
145 onv->value = mem->malloc(nv->valuelen, NULL);
146 memcpy(onv->value, nv->value, nv->valuelen);
147 } else {
148 onv->value = NULL;
149 }
150 onv->namelen = nv->namelen;
151 onv->valuelen = nv->valuelen;
152
153 onv->flags = nv->flags;
154
155 ++out->nvlen;
156 }
157
inflate_hd(nghttp2_hd_inflater * inflater,nva_out * out,nghttp2_bufs * bufs,size_t offset,nghttp2_mem * mem)158 ssize_t inflate_hd(nghttp2_hd_inflater *inflater, nva_out *out,
159 nghttp2_bufs *bufs, size_t offset, nghttp2_mem *mem) {
160 ssize_t rv;
161 nghttp2_nv nv;
162 int inflate_flags;
163 nghttp2_buf_chain *ci;
164 nghttp2_buf *buf;
165 nghttp2_buf bp;
166 int fin;
167 size_t processed;
168
169 processed = 0;
170
171 for (ci = bufs->head; ci; ci = ci->next) {
172 buf = &ci->buf;
173 fin = nghttp2_buf_len(buf) == 0 || ci->next == NULL;
174 bp = *buf;
175
176 if (offset) {
177 size_t n;
178
179 n = nghttp2_min(offset, nghttp2_buf_len(&bp));
180 bp.pos += n;
181 offset -= n;
182 }
183
184 for (;;) {
185 inflate_flags = 0;
186 rv = nghttp2_hd_inflate_hd2(inflater, &nv, &inflate_flags, bp.pos,
187 nghttp2_buf_len(&bp), fin);
188
189 if (rv < 0) {
190 return rv;
191 }
192
193 bp.pos += rv;
194 processed += (size_t)rv;
195
196 if (inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
197 if (out) {
198 add_out(out, &nv, mem);
199 }
200 }
201 if (inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
202 break;
203 }
204 if ((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 &&
205 nghttp2_buf_len(&bp) == 0) {
206 break;
207 }
208 }
209 }
210
211 nghttp2_hd_inflate_end_headers(inflater);
212
213 return (ssize_t)processed;
214 }
215
pack_headers(nghttp2_bufs * bufs,nghttp2_hd_deflater * deflater,int32_t stream_id,uint8_t flags,const nghttp2_nv * nva,size_t nvlen,nghttp2_mem * mem)216 int pack_headers(nghttp2_bufs *bufs, nghttp2_hd_deflater *deflater,
217 int32_t stream_id, uint8_t flags, const nghttp2_nv *nva,
218 size_t nvlen, nghttp2_mem *mem) {
219 nghttp2_nv *dnva;
220 nghttp2_frame frame;
221 int rv;
222
223 nghttp2_nv_array_copy(&dnva, nva, nvlen, mem);
224
225 nghttp2_frame_headers_init(&frame.headers, flags, stream_id,
226 NGHTTP2_HCAT_HEADERS, NULL, dnva, nvlen);
227 rv = nghttp2_frame_pack_headers(bufs, &frame.headers, deflater);
228
229 nghttp2_frame_headers_free(&frame.headers, mem);
230
231 return rv;
232 }
233
pack_push_promise(nghttp2_bufs * bufs,nghttp2_hd_deflater * deflater,int32_t stream_id,uint8_t flags,int32_t promised_stream_id,const nghttp2_nv * nva,size_t nvlen,nghttp2_mem * mem)234 int pack_push_promise(nghttp2_bufs *bufs, nghttp2_hd_deflater *deflater,
235 int32_t stream_id, uint8_t flags,
236 int32_t promised_stream_id, const nghttp2_nv *nva,
237 size_t nvlen, nghttp2_mem *mem) {
238 nghttp2_nv *dnva;
239 nghttp2_frame frame;
240 int rv;
241
242 nghttp2_nv_array_copy(&dnva, nva, nvlen, mem);
243
244 nghttp2_frame_push_promise_init(&frame.push_promise, flags, stream_id,
245 promised_stream_id, dnva, nvlen);
246 rv = nghttp2_frame_pack_push_promise(bufs, &frame.push_promise, deflater);
247
248 nghttp2_frame_push_promise_free(&frame.push_promise, mem);
249
250 return rv;
251 }
252
frame_pack_bufs_init(nghttp2_bufs * bufs)253 int frame_pack_bufs_init(nghttp2_bufs *bufs) {
254 /* 1 for Pad Length */
255 return nghttp2_bufs_init2(bufs, 4096, 16, NGHTTP2_FRAME_HDLEN + 1,
256 nghttp2_mem_default());
257 }
258
bufs_large_init(nghttp2_bufs * bufs,size_t chunk_size)259 void bufs_large_init(nghttp2_bufs *bufs, size_t chunk_size) {
260 /* 1 for Pad Length */
261 nghttp2_bufs_init2(bufs, chunk_size, 16, NGHTTP2_FRAME_HDLEN + 1,
262 nghttp2_mem_default());
263 }
264
open_stream_with_all(nghttp2_session * session,int32_t stream_id,int32_t weight,uint8_t exclusive,nghttp2_stream * dep_stream)265 static nghttp2_stream *open_stream_with_all(nghttp2_session *session,
266 int32_t stream_id, int32_t weight,
267 uint8_t exclusive,
268 nghttp2_stream *dep_stream) {
269 nghttp2_priority_spec pri_spec;
270 int32_t dep_stream_id;
271
272 if (dep_stream) {
273 dep_stream_id = dep_stream->stream_id;
274 } else {
275 dep_stream_id = 0;
276 }
277
278 nghttp2_priority_spec_init(&pri_spec, dep_stream_id, weight, exclusive);
279
280 return nghttp2_session_open_stream(session, stream_id,
281 NGHTTP2_STREAM_FLAG_NONE, &pri_spec,
282 NGHTTP2_STREAM_OPENED, NULL);
283 }
284
open_stream(nghttp2_session * session,int32_t stream_id)285 nghttp2_stream *open_stream(nghttp2_session *session, int32_t stream_id) {
286 return open_stream_with_all(session, stream_id, NGHTTP2_DEFAULT_WEIGHT, 0,
287 NULL);
288 }
289
open_stream_with_dep(nghttp2_session * session,int32_t stream_id,nghttp2_stream * dep_stream)290 nghttp2_stream *open_stream_with_dep(nghttp2_session *session,
291 int32_t stream_id,
292 nghttp2_stream *dep_stream) {
293 return open_stream_with_all(session, stream_id, NGHTTP2_DEFAULT_WEIGHT, 0,
294 dep_stream);
295 }
296
open_stream_with_dep_weight(nghttp2_session * session,int32_t stream_id,int32_t weight,nghttp2_stream * dep_stream)297 nghttp2_stream *open_stream_with_dep_weight(nghttp2_session *session,
298 int32_t stream_id, int32_t weight,
299 nghttp2_stream *dep_stream) {
300 return open_stream_with_all(session, stream_id, weight, 0, dep_stream);
301 }
302
open_stream_with_dep_excl(nghttp2_session * session,int32_t stream_id,nghttp2_stream * dep_stream)303 nghttp2_stream *open_stream_with_dep_excl(nghttp2_session *session,
304 int32_t stream_id,
305 nghttp2_stream *dep_stream) {
306 return open_stream_with_all(session, stream_id, NGHTTP2_DEFAULT_WEIGHT, 1,
307 dep_stream);
308 }
309
create_data_ob_item(nghttp2_mem * mem)310 nghttp2_outbound_item *create_data_ob_item(nghttp2_mem *mem) {
311 nghttp2_outbound_item *item;
312
313 item = mem->malloc(sizeof(nghttp2_outbound_item), NULL);
314 memset(item, 0, sizeof(nghttp2_outbound_item));
315
316 return item;
317 }
318
open_sent_stream(nghttp2_session * session,int32_t stream_id)319 nghttp2_stream *open_sent_stream(nghttp2_session *session, int32_t stream_id) {
320 nghttp2_priority_spec pri_spec;
321
322 nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_DEFAULT_WEIGHT, 0);
323 return open_sent_stream3(session, stream_id, NGHTTP2_FLAG_NONE, &pri_spec,
324 NGHTTP2_STREAM_OPENED, NULL);
325 }
326
open_sent_stream2(nghttp2_session * session,int32_t stream_id,nghttp2_stream_state initial_state)327 nghttp2_stream *open_sent_stream2(nghttp2_session *session, int32_t stream_id,
328 nghttp2_stream_state initial_state) {
329 nghttp2_priority_spec pri_spec;
330
331 nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_DEFAULT_WEIGHT, 0);
332 return open_sent_stream3(session, stream_id, NGHTTP2_FLAG_NONE, &pri_spec,
333 initial_state, NULL);
334 }
335
open_sent_stream3(nghttp2_session * session,int32_t stream_id,uint8_t flags,nghttp2_priority_spec * pri_spec_in,nghttp2_stream_state initial_state,void * stream_user_data)336 nghttp2_stream *open_sent_stream3(nghttp2_session *session, int32_t stream_id,
337 uint8_t flags,
338 nghttp2_priority_spec *pri_spec_in,
339 nghttp2_stream_state initial_state,
340 void *stream_user_data) {
341 nghttp2_stream *stream;
342
343 assert(nghttp2_session_is_my_stream_id(session, stream_id));
344
345 stream = nghttp2_session_open_stream(session, stream_id, flags, pri_spec_in,
346 initial_state, stream_user_data);
347 session->last_sent_stream_id =
348 nghttp2_max(session->last_sent_stream_id, stream_id);
349 session->next_stream_id =
350 nghttp2_max(session->next_stream_id, (uint32_t)stream_id + 2);
351
352 return stream;
353 }
354
open_sent_stream_with_dep(nghttp2_session * session,int32_t stream_id,nghttp2_stream * dep_stream)355 nghttp2_stream *open_sent_stream_with_dep(nghttp2_session *session,
356 int32_t stream_id,
357 nghttp2_stream *dep_stream) {
358 return open_sent_stream_with_dep_weight(session, stream_id,
359 NGHTTP2_DEFAULT_WEIGHT, dep_stream);
360 }
361
open_sent_stream_with_dep_weight(nghttp2_session * session,int32_t stream_id,int32_t weight,nghttp2_stream * dep_stream)362 nghttp2_stream *open_sent_stream_with_dep_weight(nghttp2_session *session,
363 int32_t stream_id,
364 int32_t weight,
365 nghttp2_stream *dep_stream) {
366 nghttp2_stream *stream;
367
368 assert(nghttp2_session_is_my_stream_id(session, stream_id));
369
370 stream = open_stream_with_all(session, stream_id, weight, 0, dep_stream);
371
372 session->last_sent_stream_id =
373 nghttp2_max(session->last_sent_stream_id, stream_id);
374 session->next_stream_id =
375 nghttp2_max(session->next_stream_id, (uint32_t)stream_id + 2);
376
377 return stream;
378 }
379
open_recv_stream(nghttp2_session * session,int32_t stream_id)380 nghttp2_stream *open_recv_stream(nghttp2_session *session, int32_t stream_id) {
381 nghttp2_priority_spec pri_spec;
382
383 nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_DEFAULT_WEIGHT, 0);
384 return open_recv_stream3(session, stream_id, NGHTTP2_FLAG_NONE, &pri_spec,
385 NGHTTP2_STREAM_OPENED, NULL);
386 }
387
open_recv_stream2(nghttp2_session * session,int32_t stream_id,nghttp2_stream_state initial_state)388 nghttp2_stream *open_recv_stream2(nghttp2_session *session, int32_t stream_id,
389 nghttp2_stream_state initial_state) {
390 nghttp2_priority_spec pri_spec;
391
392 nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_DEFAULT_WEIGHT, 0);
393 return open_recv_stream3(session, stream_id, NGHTTP2_FLAG_NONE, &pri_spec,
394 initial_state, NULL);
395 }
396
open_recv_stream3(nghttp2_session * session,int32_t stream_id,uint8_t flags,nghttp2_priority_spec * pri_spec_in,nghttp2_stream_state initial_state,void * stream_user_data)397 nghttp2_stream *open_recv_stream3(nghttp2_session *session, int32_t stream_id,
398 uint8_t flags,
399 nghttp2_priority_spec *pri_spec_in,
400 nghttp2_stream_state initial_state,
401 void *stream_user_data) {
402 nghttp2_stream *stream;
403
404 assert(!nghttp2_session_is_my_stream_id(session, stream_id));
405
406 stream = nghttp2_session_open_stream(session, stream_id, flags, pri_spec_in,
407 initial_state, stream_user_data);
408 session->last_recv_stream_id =
409 nghttp2_max(session->last_recv_stream_id, stream_id);
410
411 return stream;
412 }
413
open_recv_stream_with_dep(nghttp2_session * session,int32_t stream_id,nghttp2_stream * dep_stream)414 nghttp2_stream *open_recv_stream_with_dep(nghttp2_session *session,
415 int32_t stream_id,
416 nghttp2_stream *dep_stream) {
417 return open_recv_stream_with_dep_weight(session, stream_id,
418 NGHTTP2_DEFAULT_WEIGHT, dep_stream);
419 }
420
open_recv_stream_with_dep_weight(nghttp2_session * session,int32_t stream_id,int32_t weight,nghttp2_stream * dep_stream)421 nghttp2_stream *open_recv_stream_with_dep_weight(nghttp2_session *session,
422 int32_t stream_id,
423 int32_t weight,
424 nghttp2_stream *dep_stream) {
425 nghttp2_stream *stream;
426
427 assert(!nghttp2_session_is_my_stream_id(session, stream_id));
428
429 stream = open_stream_with_all(session, stream_id, weight, 0, dep_stream);
430
431 session->last_recv_stream_id =
432 nghttp2_max(session->last_recv_stream_id, stream_id);
433
434 return stream;
435 }
436