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