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