• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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