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 <assert.h>
28
29 #include <CUnit/CUnit.h>
30
31 #include "nghttp2_helper.h"
32 #include "nghttp2_priority_spec.h"
33
unpack_framebuf(nghttp2_frame * frame,nghttp2_bufs * bufs)34 int unpack_framebuf(nghttp2_frame *frame, nghttp2_bufs *bufs) {
35 nghttp2_buf *buf;
36
37 /* Assuming we have required data in first buffer. We don't decode
38 header block so, we don't mind its space */
39 buf = &bufs->head->buf;
40 return unpack_frame(frame, buf->pos, nghttp2_buf_len(buf));
41 }
42
unpack_frame(nghttp2_frame * frame,const uint8_t * in,size_t len)43 int unpack_frame(nghttp2_frame *frame, const uint8_t *in, size_t len) {
44 int rv = 0;
45 const uint8_t *payload = in + NGHTTP2_FRAME_HDLEN;
46 size_t payloadlen = len - NGHTTP2_FRAME_HDLEN;
47 size_t payloadoff;
48 nghttp2_mem *mem;
49
50 mem = nghttp2_mem_default();
51
52 nghttp2_frame_unpack_frame_hd(&frame->hd, in);
53 switch (frame->hd.type) {
54 case NGHTTP2_HEADERS:
55 payloadoff = ((frame->hd.flags & NGHTTP2_FLAG_PADDED) > 0);
56 rv = nghttp2_frame_unpack_headers_payload(&frame->headers,
57 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 rv = nghttp2_frame_unpack_push_promise_payload(&frame->push_promise,
71 payload);
72 break;
73 case NGHTTP2_PING:
74 nghttp2_frame_unpack_ping_payload(&frame->ping, payload);
75 break;
76 case NGHTTP2_GOAWAY:
77 nghttp2_frame_unpack_goaway_payload2(&frame->goaway, payload, payloadlen,
78 mem);
79 break;
80 case NGHTTP2_WINDOW_UPDATE:
81 nghttp2_frame_unpack_window_update_payload(&frame->window_update, payload);
82 break;
83 case NGHTTP2_ALTSVC:
84 assert(payloadlen > 2);
85 nghttp2_frame_unpack_altsvc_payload2(&frame->ext, payload, payloadlen, mem);
86 break;
87 case NGHTTP2_ORIGIN:
88 rv = nghttp2_frame_unpack_origin_payload(&frame->ext, payload, payloadlen,
89 mem);
90 break;
91 case NGHTTP2_PRIORITY_UPDATE:
92 assert(payloadlen >= 4);
93 nghttp2_frame_unpack_priority_update_payload(
94 &frame->ext, (uint8_t *)payload, payloadlen);
95 break;
96 default:
97 /* Must not be reachable */
98 assert(0);
99 }
100 return rv;
101 }
102
strmemeq(const char * a,const uint8_t * b,size_t bn)103 int strmemeq(const char *a, const uint8_t *b, size_t bn) {
104 const uint8_t *c;
105 if (!a || !b) {
106 return 0;
107 }
108 c = b + bn;
109 for (; *a && b != c && *a == *b; ++a, ++b)
110 ;
111 return !*a && b == c;
112 }
113
nvnameeq(const char * a,nghttp2_nv * nv)114 int nvnameeq(const char *a, nghttp2_nv *nv) {
115 return strmemeq(a, nv->name, nv->namelen);
116 }
117
nvvalueeq(const char * a,nghttp2_nv * nv)118 int nvvalueeq(const char *a, nghttp2_nv *nv) {
119 return strmemeq(a, nv->value, nv->valuelen);
120 }
121
nva_out_init(nva_out * out)122 void nva_out_init(nva_out *out) {
123 memset(out->nva, 0, sizeof(out->nva));
124 out->nvlen = 0;
125 }
126
nva_out_reset(nva_out * out,nghttp2_mem * mem)127 void nva_out_reset(nva_out *out, nghttp2_mem *mem) {
128 size_t i;
129 for (i = 0; i < out->nvlen; ++i) {
130 mem->free(out->nva[i].name, NULL);
131 mem->free(out->nva[i].value, NULL);
132 }
133 memset(out->nva, 0, sizeof(out->nva));
134 out->nvlen = 0;
135 }
136
add_out(nva_out * out,nghttp2_nv * nv,nghttp2_mem * mem)137 void add_out(nva_out *out, nghttp2_nv *nv, nghttp2_mem *mem) {
138 nghttp2_nv *onv = &out->nva[out->nvlen];
139 if (nv->namelen) {
140 onv->name = mem->malloc(nv->namelen, NULL);
141 memcpy(onv->name, nv->name, nv->namelen);
142 } else {
143 onv->name = NULL;
144 }
145 if (nv->valuelen) {
146 onv->value = mem->malloc(nv->valuelen, NULL);
147 memcpy(onv->value, nv->value, nv->valuelen);
148 } else {
149 onv->value = NULL;
150 }
151 onv->namelen = nv->namelen;
152 onv->valuelen = nv->valuelen;
153
154 onv->flags = nv->flags;
155
156 ++out->nvlen;
157 }
158
inflate_hd(nghttp2_hd_inflater * inflater,nva_out * out,nghttp2_bufs * bufs,size_t offset,nghttp2_mem * mem)159 ssize_t inflate_hd(nghttp2_hd_inflater *inflater, nva_out *out,
160 nghttp2_bufs *bufs, size_t offset, nghttp2_mem *mem) {
161 ssize_t rv;
162 nghttp2_nv nv;
163 int inflate_flags;
164 nghttp2_buf_chain *ci;
165 nghttp2_buf *buf;
166 nghttp2_buf bp;
167 int fin;
168 size_t processed;
169
170 processed = 0;
171
172 for (ci = bufs->head; ci; ci = ci->next) {
173 buf = &ci->buf;
174 fin = nghttp2_buf_len(buf) == 0 || ci->next == NULL;
175 bp = *buf;
176
177 if (offset) {
178 size_t n;
179
180 n = nghttp2_min(offset, nghttp2_buf_len(&bp));
181 bp.pos += n;
182 offset -= n;
183 }
184
185 for (;;) {
186 inflate_flags = 0;
187 rv = nghttp2_hd_inflate_hd2(inflater, &nv, &inflate_flags, bp.pos,
188 nghttp2_buf_len(&bp), fin);
189
190 if (rv < 0) {
191 return rv;
192 }
193
194 bp.pos += rv;
195 processed += (size_t)rv;
196
197 if (inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
198 if (out) {
199 add_out(out, &nv, mem);
200 }
201 }
202 if (inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
203 break;
204 }
205 if ((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 &&
206 nghttp2_buf_len(&bp) == 0) {
207 break;
208 }
209 }
210 }
211
212 nghttp2_hd_inflate_end_headers(inflater);
213
214 return (ssize_t)processed;
215 }
216
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)217 int pack_headers(nghttp2_bufs *bufs, nghttp2_hd_deflater *deflater,
218 int32_t stream_id, uint8_t flags, const nghttp2_nv *nva,
219 size_t nvlen, nghttp2_mem *mem) {
220 nghttp2_nv *dnva;
221 nghttp2_frame frame;
222 int rv;
223
224 nghttp2_nv_array_copy(&dnva, nva, nvlen, mem);
225
226 nghttp2_frame_headers_init(&frame.headers, flags, stream_id,
227 NGHTTP2_HCAT_HEADERS, NULL, dnva, nvlen);
228 rv = nghttp2_frame_pack_headers(bufs, &frame.headers, deflater);
229
230 nghttp2_frame_headers_free(&frame.headers, mem);
231
232 return rv;
233 }
234
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)235 int pack_push_promise(nghttp2_bufs *bufs, nghttp2_hd_deflater *deflater,
236 int32_t stream_id, uint8_t flags,
237 int32_t promised_stream_id, const nghttp2_nv *nva,
238 size_t nvlen, nghttp2_mem *mem) {
239 nghttp2_nv *dnva;
240 nghttp2_frame frame;
241 int rv;
242
243 nghttp2_nv_array_copy(&dnva, nva, nvlen, mem);
244
245 nghttp2_frame_push_promise_init(&frame.push_promise, flags, stream_id,
246 promised_stream_id, dnva, nvlen);
247 rv = nghttp2_frame_pack_push_promise(bufs, &frame.push_promise, deflater);
248
249 nghttp2_frame_push_promise_free(&frame.push_promise, mem);
250
251 return rv;
252 }
253
frame_pack_bufs_init(nghttp2_bufs * bufs)254 int frame_pack_bufs_init(nghttp2_bufs *bufs) {
255 /* 1 for Pad Length */
256 return nghttp2_bufs_init2(bufs, 4096, 16, NGHTTP2_FRAME_HDLEN + 1,
257 nghttp2_mem_default());
258 }
259
bufs_large_init(nghttp2_bufs * bufs,size_t chunk_size)260 void bufs_large_init(nghttp2_bufs *bufs, size_t chunk_size) {
261 /* 1 for Pad Length */
262 nghttp2_bufs_init2(bufs, chunk_size, 16, NGHTTP2_FRAME_HDLEN + 1,
263 nghttp2_mem_default());
264 }
265
open_stream_with_all(nghttp2_session * session,int32_t stream_id,int32_t weight,uint8_t exclusive,nghttp2_stream * dep_stream)266 static nghttp2_stream *open_stream_with_all(nghttp2_session *session,
267 int32_t stream_id, int32_t weight,
268 uint8_t exclusive,
269 nghttp2_stream *dep_stream) {
270 nghttp2_priority_spec pri_spec;
271 int32_t dep_stream_id;
272
273 if (dep_stream) {
274 dep_stream_id = dep_stream->stream_id;
275 } else {
276 dep_stream_id = 0;
277 }
278
279 nghttp2_priority_spec_init(&pri_spec, dep_stream_id, weight, exclusive);
280
281 return nghttp2_session_open_stream(session, stream_id,
282 NGHTTP2_STREAM_FLAG_NONE, &pri_spec,
283 NGHTTP2_STREAM_OPENED, NULL);
284 }
285
open_stream(nghttp2_session * session,int32_t stream_id)286 nghttp2_stream *open_stream(nghttp2_session *session, int32_t stream_id) {
287 return open_stream_with_all(session, stream_id, NGHTTP2_DEFAULT_WEIGHT, 0,
288 NULL);
289 }
290
open_stream_with_dep(nghttp2_session * session,int32_t stream_id,nghttp2_stream * dep_stream)291 nghttp2_stream *open_stream_with_dep(nghttp2_session *session,
292 int32_t stream_id,
293 nghttp2_stream *dep_stream) {
294 return open_stream_with_all(session, stream_id, NGHTTP2_DEFAULT_WEIGHT, 0,
295 dep_stream);
296 }
297
open_stream_with_dep_weight(nghttp2_session * session,int32_t stream_id,int32_t weight,nghttp2_stream * dep_stream)298 nghttp2_stream *open_stream_with_dep_weight(nghttp2_session *session,
299 int32_t stream_id, int32_t weight,
300 nghttp2_stream *dep_stream) {
301 return open_stream_with_all(session, stream_id, weight, 0, dep_stream);
302 }
303
open_stream_with_dep_excl(nghttp2_session * session,int32_t stream_id,nghttp2_stream * dep_stream)304 nghttp2_stream *open_stream_with_dep_excl(nghttp2_session *session,
305 int32_t stream_id,
306 nghttp2_stream *dep_stream) {
307 return open_stream_with_all(session, stream_id, NGHTTP2_DEFAULT_WEIGHT, 1,
308 dep_stream);
309 }
310
create_data_ob_item(nghttp2_mem * mem)311 nghttp2_outbound_item *create_data_ob_item(nghttp2_mem *mem) {
312 nghttp2_outbound_item *item;
313
314 item = mem->malloc(sizeof(nghttp2_outbound_item), NULL);
315 memset(item, 0, sizeof(nghttp2_outbound_item));
316
317 return item;
318 }
319
open_sent_stream(nghttp2_session * session,int32_t stream_id)320 nghttp2_stream *open_sent_stream(nghttp2_session *session, int32_t stream_id) {
321 nghttp2_priority_spec pri_spec;
322
323 nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_DEFAULT_WEIGHT, 0);
324 return open_sent_stream3(session, stream_id, NGHTTP2_FLAG_NONE, &pri_spec,
325 NGHTTP2_STREAM_OPENED, NULL);
326 }
327
open_sent_stream2(nghttp2_session * session,int32_t stream_id,nghttp2_stream_state initial_state)328 nghttp2_stream *open_sent_stream2(nghttp2_session *session, int32_t stream_id,
329 nghttp2_stream_state initial_state) {
330 nghttp2_priority_spec pri_spec;
331
332 nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_DEFAULT_WEIGHT, 0);
333 return open_sent_stream3(session, stream_id, NGHTTP2_FLAG_NONE, &pri_spec,
334 initial_state, NULL);
335 }
336
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)337 nghttp2_stream *open_sent_stream3(nghttp2_session *session, int32_t stream_id,
338 uint8_t flags,
339 nghttp2_priority_spec *pri_spec_in,
340 nghttp2_stream_state initial_state,
341 void *stream_user_data) {
342 nghttp2_stream *stream;
343
344 assert(nghttp2_session_is_my_stream_id(session, stream_id));
345
346 stream = nghttp2_session_open_stream(session, stream_id, flags, pri_spec_in,
347 initial_state, stream_user_data);
348 session->last_sent_stream_id =
349 nghttp2_max(session->last_sent_stream_id, stream_id);
350 session->next_stream_id =
351 nghttp2_max(session->next_stream_id, (uint32_t)stream_id + 2);
352
353 return stream;
354 }
355
open_sent_stream_with_dep(nghttp2_session * session,int32_t stream_id,nghttp2_stream * dep_stream)356 nghttp2_stream *open_sent_stream_with_dep(nghttp2_session *session,
357 int32_t stream_id,
358 nghttp2_stream *dep_stream) {
359 return open_sent_stream_with_dep_weight(session, stream_id,
360 NGHTTP2_DEFAULT_WEIGHT, dep_stream);
361 }
362
open_sent_stream_with_dep_weight(nghttp2_session * session,int32_t stream_id,int32_t weight,nghttp2_stream * dep_stream)363 nghttp2_stream *open_sent_stream_with_dep_weight(nghttp2_session *session,
364 int32_t stream_id,
365 int32_t weight,
366 nghttp2_stream *dep_stream) {
367 nghttp2_stream *stream;
368
369 assert(nghttp2_session_is_my_stream_id(session, stream_id));
370
371 stream = open_stream_with_all(session, stream_id, weight, 0, dep_stream);
372
373 session->last_sent_stream_id =
374 nghttp2_max(session->last_sent_stream_id, stream_id);
375 session->next_stream_id =
376 nghttp2_max(session->next_stream_id, (uint32_t)stream_id + 2);
377
378 return stream;
379 }
380
open_recv_stream(nghttp2_session * session,int32_t stream_id)381 nghttp2_stream *open_recv_stream(nghttp2_session *session, int32_t stream_id) {
382 nghttp2_priority_spec pri_spec;
383
384 nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_DEFAULT_WEIGHT, 0);
385 return open_recv_stream3(session, stream_id, NGHTTP2_FLAG_NONE, &pri_spec,
386 NGHTTP2_STREAM_OPENED, NULL);
387 }
388
open_recv_stream2(nghttp2_session * session,int32_t stream_id,nghttp2_stream_state initial_state)389 nghttp2_stream *open_recv_stream2(nghttp2_session *session, int32_t stream_id,
390 nghttp2_stream_state initial_state) {
391 nghttp2_priority_spec pri_spec;
392
393 nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_DEFAULT_WEIGHT, 0);
394 return open_recv_stream3(session, stream_id, NGHTTP2_FLAG_NONE, &pri_spec,
395 initial_state, NULL);
396 }
397
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)398 nghttp2_stream *open_recv_stream3(nghttp2_session *session, int32_t stream_id,
399 uint8_t flags,
400 nghttp2_priority_spec *pri_spec_in,
401 nghttp2_stream_state initial_state,
402 void *stream_user_data) {
403 nghttp2_stream *stream;
404
405 assert(!nghttp2_session_is_my_stream_id(session, stream_id));
406
407 stream = nghttp2_session_open_stream(session, stream_id, flags, pri_spec_in,
408 initial_state, stream_user_data);
409 session->last_recv_stream_id =
410 nghttp2_max(session->last_recv_stream_id, stream_id);
411
412 return stream;
413 }
414
open_recv_stream_with_dep(nghttp2_session * session,int32_t stream_id,nghttp2_stream * dep_stream)415 nghttp2_stream *open_recv_stream_with_dep(nghttp2_session *session,
416 int32_t stream_id,
417 nghttp2_stream *dep_stream) {
418 return open_recv_stream_with_dep_weight(session, stream_id,
419 NGHTTP2_DEFAULT_WEIGHT, dep_stream);
420 }
421
open_recv_stream_with_dep_weight(nghttp2_session * session,int32_t stream_id,int32_t weight,nghttp2_stream * dep_stream)422 nghttp2_stream *open_recv_stream_with_dep_weight(nghttp2_session *session,
423 int32_t stream_id,
424 int32_t weight,
425 nghttp2_stream *dep_stream) {
426 nghttp2_stream *stream;
427
428 assert(!nghttp2_session_is_my_stream_id(session, stream_id));
429
430 stream = open_stream_with_all(session, stream_id, weight, 0, dep_stream);
431
432 session->last_recv_stream_id =
433 nghttp2_max(session->last_recv_stream_id, stream_id);
434
435 return stream;
436 }
437