tizen 2.4 release
[external/nghttp2.git] / tests / nghttp2_session_test.c
1 /*
2  * nghttp2 - HTTP/2 C Library
3  *
4  * Copyright (c) 2013 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_session_test.h"
26
27 #include <stdio.h>
28 #include <assert.h>
29
30 #include <CUnit/CUnit.h>
31
32 #include "nghttp2_session.h"
33 #include "nghttp2_stream.h"
34 #include "nghttp2_net.h"
35 #include "nghttp2_helper.h"
36 #include "nghttp2_test_helper.h"
37 #include "nghttp2_priority_spec.h"
38
39 #define OB_CTRL(ITEM) nghttp2_outbound_item_get_ctrl_frame(ITEM)
40 #define OB_CTRL_TYPE(ITEM) nghttp2_outbound_item_get_ctrl_frame_type(ITEM)
41 #define OB_DATA(ITEM) nghttp2_outbound_item_get_data_frame(ITEM)
42
43 typedef struct {
44   uint8_t buf[65535];
45   size_t length;
46 } accumulator;
47
48 typedef struct {
49   uint8_t data[8192];
50   uint8_t *datamark;
51   uint8_t *datalimit;
52   size_t feedseq[8192];
53   size_t seqidx;
54 } scripted_data_feed;
55
56 typedef struct {
57   accumulator *acc;
58   scripted_data_feed *df;
59   int frame_recv_cb_called, invalid_frame_recv_cb_called;
60   uint8_t recv_frame_type;
61   int frame_send_cb_called;
62   uint8_t sent_frame_type;
63   int frame_not_send_cb_called;
64   uint8_t not_sent_frame_type;
65   int not_sent_error;
66   int stream_close_cb_called;
67   size_t data_source_length;
68   int32_t stream_id;
69   size_t block_count;
70   int data_chunk_recv_cb_called;
71   const nghttp2_frame *frame;
72   size_t fixed_sendlen;
73   int header_cb_called;
74   int begin_headers_cb_called;
75   nghttp2_nv nv;
76   size_t data_chunk_len;
77   size_t padlen;
78   int begin_frame_cb_called;
79 } my_user_data;
80
81 static void scripted_data_feed_init2(scripted_data_feed *df,
82                                      nghttp2_bufs *bufs) {
83   nghttp2_buf_chain *ci;
84   nghttp2_buf *buf;
85   uint8_t *ptr;
86   size_t len;
87
88   memset(df, 0, sizeof(scripted_data_feed));
89   ptr = df->data;
90   len = 0;
91
92   for (ci = bufs->head; ci; ci = ci->next) {
93     buf = &ci->buf;
94     ptr = nghttp2_cpymem(ptr, buf->pos, nghttp2_buf_len(buf));
95     len += nghttp2_buf_len(buf);
96   }
97
98   df->datamark = df->data;
99   df->datalimit = df->data + len;
100   df->feedseq[0] = len;
101 }
102
103 static ssize_t null_send_callback(nghttp2_session *session _U_,
104                                   const uint8_t *data _U_, size_t len,
105                                   int flags _U_, void *user_data _U_) {
106   return len;
107 }
108
109 static ssize_t fail_send_callback(nghttp2_session *session _U_,
110                                   const uint8_t *data _U_, size_t len _U_,
111                                   int flags _U_, void *user_data _U_) {
112   return NGHTTP2_ERR_CALLBACK_FAILURE;
113 }
114
115 static ssize_t fixed_bytes_send_callback(nghttp2_session *session _U_,
116                                          const uint8_t *data _U_, size_t len,
117                                          int flags _U_, void *user_data) {
118   size_t fixed_sendlen = ((my_user_data *)user_data)->fixed_sendlen;
119   return fixed_sendlen < len ? fixed_sendlen : len;
120 }
121
122 static ssize_t scripted_recv_callback(nghttp2_session *session _U_,
123                                       uint8_t *data, size_t len, int flags _U_,
124                                       void *user_data) {
125   scripted_data_feed *df = ((my_user_data *)user_data)->df;
126   size_t wlen = df->feedseq[df->seqidx] > len ? len : df->feedseq[df->seqidx];
127   memcpy(data, df->datamark, wlen);
128   df->datamark += wlen;
129   df->feedseq[df->seqidx] -= wlen;
130   if (df->feedseq[df->seqidx] == 0) {
131     ++df->seqidx;
132   }
133   return wlen;
134 }
135
136 static ssize_t eof_recv_callback(nghttp2_session *session _U_,
137                                  uint8_t *data _U_, size_t len _U_,
138                                  int flags _U_, void *user_data _U_) {
139   return NGHTTP2_ERR_EOF;
140 }
141
142 static ssize_t accumulator_send_callback(nghttp2_session *session _U_,
143                                          const uint8_t *buf, size_t len,
144                                          int flags _U_, void *user_data) {
145   accumulator *acc = ((my_user_data *)user_data)->acc;
146   assert(acc->length + len < sizeof(acc->buf));
147   memcpy(acc->buf + acc->length, buf, len);
148   acc->length += len;
149   return len;
150 }
151
152 static int on_begin_frame_callback(nghttp2_session *session _U_,
153                                    const nghttp2_frame_hd *hd _U_,
154                                    void *user_data) {
155   my_user_data *ud = (my_user_data *)user_data;
156   ++ud->begin_frame_cb_called;
157   return 0;
158 }
159
160 static int on_frame_recv_callback(nghttp2_session *session _U_,
161                                   const nghttp2_frame *frame, void *user_data) {
162   my_user_data *ud = (my_user_data *)user_data;
163   ++ud->frame_recv_cb_called;
164   ud->recv_frame_type = frame->hd.type;
165   return 0;
166 }
167
168 static int on_invalid_frame_recv_callback(nghttp2_session *session _U_,
169                                           const nghttp2_frame *frame _U_,
170                                           nghttp2_error_code error_code _U_,
171                                           void *user_data) {
172   my_user_data *ud = (my_user_data *)user_data;
173   ++ud->invalid_frame_recv_cb_called;
174   return 0;
175 }
176
177 static int on_frame_send_callback(nghttp2_session *session _U_,
178                                   const nghttp2_frame *frame, void *user_data) {
179   my_user_data *ud = (my_user_data *)user_data;
180   ++ud->frame_send_cb_called;
181   ud->sent_frame_type = frame->hd.type;
182   return 0;
183 }
184
185 static int on_frame_not_send_callback(nghttp2_session *session _U_,
186                                       const nghttp2_frame *frame, int lib_error,
187                                       void *user_data) {
188   my_user_data *ud = (my_user_data *)user_data;
189   ++ud->frame_not_send_cb_called;
190   ud->not_sent_frame_type = frame->hd.type;
191   ud->not_sent_error = lib_error;
192   return 0;
193 }
194
195 static int on_data_chunk_recv_callback(nghttp2_session *session _U_,
196                                        uint8_t flags _U_, int32_t stream_id _U_,
197                                        const uint8_t *data _U_, size_t len,
198                                        void *user_data) {
199   my_user_data *ud = (my_user_data *)user_data;
200   ++ud->data_chunk_recv_cb_called;
201   ud->data_chunk_len = len;
202   return 0;
203 }
204
205 static int pause_on_data_chunk_recv_callback(nghttp2_session *session _U_,
206                                              uint8_t flags _U_,
207                                              int32_t stream_id _U_,
208                                              const uint8_t *data _U_,
209                                              size_t len _U_, void *user_data) {
210   my_user_data *ud = (my_user_data *)user_data;
211   ++ud->data_chunk_recv_cb_called;
212   return NGHTTP2_ERR_PAUSE;
213 }
214
215 static ssize_t select_padding_callback(nghttp2_session *session _U_,
216                                        const nghttp2_frame *frame,
217                                        size_t max_payloadlen, void *user_data) {
218   my_user_data *ud = (my_user_data *)user_data;
219   return nghttp2_min(max_payloadlen, frame->hd.length + ud->padlen);
220 }
221
222 static ssize_t too_large_data_source_length_callback(
223     nghttp2_session *session _U_, uint8_t frame_type _U_, int32_t stream_id _U_,
224     int32_t session_remote_window_size _U_,
225     int32_t stream_remote_window_size _U_, uint32_t remote_max_frame_size _U_,
226     void *user_data _U_) {
227   return NGHTTP2_MAX_FRAME_SIZE_MAX + 1;
228 }
229
230 static ssize_t smallest_length_data_source_length_callback(
231     nghttp2_session *session _U_, uint8_t frame_type _U_, int32_t stream_id _U_,
232     int32_t session_remote_window_size _U_,
233     int32_t stream_remote_window_size _U_, uint32_t remote_max_frame_size _U_,
234     void *user_data _U_) {
235   return 1;
236 }
237
238 static ssize_t fixed_length_data_source_read_callback(
239     nghttp2_session *session _U_, int32_t stream_id _U_, uint8_t *buf _U_,
240     size_t len, uint32_t *data_flags, nghttp2_data_source *source _U_,
241     void *user_data) {
242   my_user_data *ud = (my_user_data *)user_data;
243   size_t wlen;
244   if (len < ud->data_source_length) {
245     wlen = len;
246   } else {
247     wlen = ud->data_source_length;
248   }
249   ud->data_source_length -= wlen;
250   if (ud->data_source_length == 0) {
251     *data_flags |= NGHTTP2_DATA_FLAG_EOF;
252   }
253   return wlen;
254 }
255
256 static ssize_t temporal_failure_data_source_read_callback(
257     nghttp2_session *session _U_, int32_t stream_id _U_, uint8_t *buf _U_,
258     size_t len _U_, uint32_t *data_flags _U_, nghttp2_data_source *source _U_,
259     void *user_data _U_) {
260   return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
261 }
262
263 static ssize_t fail_data_source_read_callback(nghttp2_session *session _U_,
264                                               int32_t stream_id _U_,
265                                               uint8_t *buf _U_, size_t len _U_,
266                                               uint32_t *data_flags _U_,
267                                               nghttp2_data_source *source _U_,
268                                               void *user_data _U_) {
269   return NGHTTP2_ERR_CALLBACK_FAILURE;
270 }
271
272 /* static void no_stream_user_data_stream_close_callback */
273 /* (nghttp2_session *session, */
274 /*  int32_t stream_id, */
275 /*  nghttp2_error_code error_code, */
276 /*  void *user_data) */
277 /* { */
278 /*   my_user_data* my_data = (my_user_data*)user_data; */
279 /*   ++my_data->stream_close_cb_called; */
280 /* } */
281
282 static ssize_t block_count_send_callback(nghttp2_session *session _U_,
283                                          const uint8_t *data _U_, size_t len,
284                                          int flags _U_, void *user_data) {
285   my_user_data *ud = (my_user_data *)user_data;
286   ssize_t r;
287   if (ud->block_count == 0) {
288     r = NGHTTP2_ERR_WOULDBLOCK;
289   } else {
290     --ud->block_count;
291     r = len;
292   }
293   return r;
294 }
295
296 static int on_header_callback(nghttp2_session *session _U_,
297                               const nghttp2_frame *frame, const uint8_t *name,
298                               size_t namelen, const uint8_t *value,
299                               size_t valuelen, uint8_t flags _U_,
300                               void *user_data) {
301   my_user_data *ud = (my_user_data *)user_data;
302   ++ud->header_cb_called;
303   ud->nv.name = (uint8_t *)name;
304   ud->nv.namelen = namelen;
305   ud->nv.value = (uint8_t *)value;
306   ud->nv.valuelen = valuelen;
307
308   ud->frame = frame;
309   return 0;
310 }
311
312 static int pause_on_header_callback(nghttp2_session *session,
313                                     const nghttp2_frame *frame,
314                                     const uint8_t *name, size_t namelen,
315                                     const uint8_t *value, size_t valuelen,
316                                     uint8_t flags, void *user_data) {
317   on_header_callback(session, frame, name, namelen, value, valuelen, flags,
318                      user_data);
319   return NGHTTP2_ERR_PAUSE;
320 }
321
322 static int temporal_failure_on_header_callback(
323     nghttp2_session *session, const nghttp2_frame *frame, const uint8_t *name,
324     size_t namelen, const uint8_t *value, size_t valuelen, uint8_t flags,
325     void *user_data) {
326   on_header_callback(session, frame, name, namelen, value, valuelen, flags,
327                      user_data);
328   return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
329 }
330
331 static int on_begin_headers_callback(nghttp2_session *session _U_,
332                                      const nghttp2_frame *frame _U_,
333                                      void *user_data) {
334   my_user_data *ud = (my_user_data *)user_data;
335   ++ud->begin_headers_cb_called;
336   return 0;
337 }
338
339 static ssize_t defer_data_source_read_callback(nghttp2_session *session _U_,
340                                                int32_t stream_id _U_,
341                                                uint8_t *buf _U_, size_t len _U_,
342                                                uint32_t *data_flags _U_,
343                                                nghttp2_data_source *source _U_,
344                                                void *user_data _U_) {
345   return NGHTTP2_ERR_DEFERRED;
346 }
347
348 static int on_stream_close_callback(nghttp2_session *session _U_,
349                                     int32_t stream_id _U_,
350                                     nghttp2_error_code error_code _U_,
351                                     void *user_data) {
352   my_user_data *my_data = (my_user_data *)user_data;
353   ++my_data->stream_close_cb_called;
354
355   return 0;
356 }
357
358 static nghttp2_settings_entry *dup_iv(const nghttp2_settings_entry *iv,
359                                       size_t niv) {
360   return nghttp2_frame_iv_copy(iv, niv, nghttp2_mem_default());
361 }
362
363 static nghttp2_priority_spec pri_spec_default = {0, NGHTTP2_DEFAULT_WEIGHT, 0};
364
365 void test_nghttp2_session_recv(void) {
366   nghttp2_session *session;
367   nghttp2_session_callbacks callbacks;
368   scripted_data_feed df;
369   my_user_data user_data;
370   const nghttp2_nv nv[] = {MAKE_NV("url", "/")};
371   nghttp2_bufs bufs;
372   ssize_t framelen;
373   nghttp2_frame frame;
374   ssize_t i;
375   nghttp2_outbound_item *item;
376   nghttp2_nv *nva;
377   ssize_t nvlen;
378   nghttp2_hd_deflater deflater;
379   int rv;
380   nghttp2_mem *mem;
381
382   mem = nghttp2_mem_default();
383   frame_pack_bufs_init(&bufs);
384
385   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
386   callbacks.send_callback = null_send_callback;
387   callbacks.recv_callback = scripted_recv_callback;
388   callbacks.on_frame_recv_callback = on_frame_recv_callback;
389   callbacks.on_begin_frame_callback = on_begin_frame_callback;
390
391   user_data.df = &df;
392
393   nghttp2_session_server_new(&session, &callbacks, &user_data);
394   nghttp2_hd_deflate_init(&deflater, mem);
395
396   nvlen = ARRLEN(nv);
397   nghttp2_nv_array_copy(&nva, nv, nvlen, mem);
398   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
399                              NGHTTP2_HCAT_HEADERS, NULL, nva, nvlen);
400   rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
401
402   CU_ASSERT(0 == rv);
403
404   scripted_data_feed_init2(&df, &bufs);
405
406   framelen = nghttp2_bufs_len(&bufs);
407
408   /* Send 1 byte per each read */
409   for (i = 0; i < framelen; ++i) {
410     df.feedseq[i] = 1;
411   }
412
413   nghttp2_frame_headers_free(&frame.headers, mem);
414
415   user_data.frame_recv_cb_called = 0;
416   user_data.begin_frame_cb_called = 0;
417
418   while ((ssize_t)df.seqidx < framelen) {
419     CU_ASSERT(0 == nghttp2_session_recv(session));
420   }
421   CU_ASSERT(1 == user_data.frame_recv_cb_called);
422   CU_ASSERT(1 == user_data.begin_frame_cb_called);
423
424   nghttp2_bufs_reset(&bufs);
425
426   /* Received HEADERS without header block, which is valid */
427   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 5,
428                              NGHTTP2_HCAT_HEADERS, NULL, NULL, 0);
429   rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
430
431   CU_ASSERT(0 == rv);
432
433   nghttp2_frame_headers_free(&frame.headers, mem);
434
435   scripted_data_feed_init2(&df, &bufs);
436   user_data.frame_recv_cb_called = 0;
437   user_data.begin_frame_cb_called = 0;
438
439   CU_ASSERT(0 == nghttp2_session_recv(session));
440   CU_ASSERT(1 == user_data.frame_recv_cb_called);
441   CU_ASSERT(1 == user_data.begin_frame_cb_called);
442
443   nghttp2_bufs_reset(&bufs);
444
445   /* Receive PRIORITY */
446   nghttp2_frame_priority_init(&frame.priority, 5, &pri_spec_default);
447
448   rv = nghttp2_frame_pack_priority(&bufs, &frame.priority);
449
450   CU_ASSERT(0 == rv);
451
452   nghttp2_frame_priority_free(&frame.priority);
453
454   scripted_data_feed_init2(&df, &bufs);
455
456   user_data.frame_recv_cb_called = 0;
457   user_data.begin_frame_cb_called = 0;
458
459   CU_ASSERT(0 == nghttp2_session_recv(session));
460   CU_ASSERT(1 == user_data.frame_recv_cb_called);
461   CU_ASSERT(1 == user_data.begin_frame_cb_called);
462
463   nghttp2_bufs_reset(&bufs);
464
465   nghttp2_hd_deflate_free(&deflater);
466   nghttp2_session_del(session);
467
468   /* Some tests for frame too large */
469   nghttp2_session_server_new(&session, &callbacks, &user_data);
470
471   /* Receive PING with too large payload */
472   nghttp2_frame_ping_init(&frame.ping, NGHTTP2_FLAG_NONE, NULL);
473
474   rv = nghttp2_frame_pack_ping(&bufs, &frame.ping);
475
476   CU_ASSERT(0 == rv);
477
478   /* Add extra 16 bytes */
479   nghttp2_bufs_seek_last_present(&bufs);
480   assert(nghttp2_buf_len(&bufs.cur->buf) >= 16);
481
482   bufs.cur->buf.last += 16;
483   nghttp2_put_uint32be(
484       bufs.cur->buf.pos,
485       (uint32_t)(((frame.hd.length + 16) << 8) + bufs.cur->buf.pos[3]));
486
487   nghttp2_frame_ping_free(&frame.ping);
488
489   scripted_data_feed_init2(&df, &bufs);
490   user_data.frame_recv_cb_called = 0;
491   user_data.begin_frame_cb_called = 0;
492
493   CU_ASSERT(0 == nghttp2_session_recv(session));
494   CU_ASSERT(0 == user_data.frame_recv_cb_called);
495   CU_ASSERT(0 == user_data.begin_frame_cb_called);
496
497   item = nghttp2_session_get_next_ob_item(session);
498   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
499   CU_ASSERT(NGHTTP2_FRAME_SIZE_ERROR == item->frame.goaway.error_code);
500   CU_ASSERT(0 == nghttp2_session_send(session));
501
502   nghttp2_bufs_free(&bufs);
503   nghttp2_session_del(session);
504 }
505
506 void test_nghttp2_session_recv_invalid_stream_id(void) {
507   nghttp2_session *session;
508   nghttp2_session_callbacks callbacks;
509   scripted_data_feed df;
510   my_user_data user_data;
511   nghttp2_bufs bufs;
512   nghttp2_frame frame;
513   nghttp2_hd_deflater deflater;
514   int rv;
515   nghttp2_mem *mem;
516
517   mem = nghttp2_mem_default();
518   frame_pack_bufs_init(&bufs);
519
520   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
521   callbacks.recv_callback = scripted_recv_callback;
522   callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
523
524   user_data.df = &df;
525   user_data.invalid_frame_recv_cb_called = 0;
526   nghttp2_session_server_new(&session, &callbacks, &user_data);
527   nghttp2_hd_deflate_init(&deflater, mem);
528
529   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 2,
530                              NGHTTP2_HCAT_HEADERS, NULL, NULL, 0);
531   rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
532
533   CU_ASSERT(0 == rv);
534   CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
535
536   scripted_data_feed_init2(&df, &bufs);
537   nghttp2_frame_headers_free(&frame.headers, mem);
538
539   CU_ASSERT(0 == nghttp2_session_recv(session));
540   CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
541
542   nghttp2_bufs_free(&bufs);
543   nghttp2_hd_deflate_free(&deflater);
544   nghttp2_session_del(session);
545 }
546
547 void test_nghttp2_session_recv_invalid_frame(void) {
548   nghttp2_session *session;
549   nghttp2_session_callbacks callbacks;
550   scripted_data_feed df;
551   my_user_data user_data;
552   const nghttp2_nv nv[] = {MAKE_NV("url", "/")};
553   nghttp2_bufs bufs;
554   nghttp2_frame frame;
555   nghttp2_nv *nva;
556   ssize_t nvlen;
557   nghttp2_hd_deflater deflater;
558   int rv;
559   nghttp2_mem *mem;
560
561   mem = nghttp2_mem_default();
562   frame_pack_bufs_init(&bufs);
563
564   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
565   callbacks.recv_callback = scripted_recv_callback;
566   callbacks.send_callback = null_send_callback;
567   callbacks.on_frame_send_callback = on_frame_send_callback;
568
569   user_data.df = &df;
570   user_data.frame_send_cb_called = 0;
571   nghttp2_session_server_new(&session, &callbacks, &user_data);
572   nghttp2_hd_deflate_init(&deflater, mem);
573   nvlen = ARRLEN(nv);
574   nghttp2_nv_array_copy(&nva, nv, nvlen, mem);
575   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
576                              NGHTTP2_HCAT_HEADERS, NULL, nva, nvlen);
577   rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
578
579   CU_ASSERT(0 == rv);
580   CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
581
582   scripted_data_feed_init2(&df, &bufs);
583
584   CU_ASSERT(0 == nghttp2_session_recv(session));
585   CU_ASSERT(0 == nghttp2_session_send(session));
586   CU_ASSERT(0 == user_data.frame_send_cb_called);
587
588   /* Receive exactly same bytes of HEADERS is treated as subsequent
589      HEADERS (e.g., trailers */
590   scripted_data_feed_init2(&df, &bufs);
591
592   CU_ASSERT(0 == nghttp2_session_recv(session));
593   CU_ASSERT(0 == nghttp2_session_send(session));
594   CU_ASSERT(0 == user_data.frame_send_cb_called);
595
596   nghttp2_bufs_free(&bufs);
597   nghttp2_frame_headers_free(&frame.headers, mem);
598
599   nghttp2_hd_deflate_free(&deflater);
600   nghttp2_session_del(session);
601 }
602
603 void test_nghttp2_session_recv_eof(void) {
604   nghttp2_session *session;
605   nghttp2_session_callbacks callbacks;
606
607   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
608   callbacks.send_callback = null_send_callback;
609   callbacks.recv_callback = eof_recv_callback;
610
611   nghttp2_session_client_new(&session, &callbacks, NULL);
612   CU_ASSERT(NGHTTP2_ERR_EOF == nghttp2_session_recv(session));
613
614   nghttp2_session_del(session);
615 }
616
617 void test_nghttp2_session_recv_data(void) {
618   nghttp2_session *session;
619   nghttp2_session_callbacks callbacks;
620   my_user_data ud;
621   uint8_t data[8092];
622   ssize_t rv;
623   nghttp2_outbound_item *item;
624   nghttp2_stream *stream;
625   nghttp2_frame_hd hd;
626   int i;
627
628   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
629   callbacks.send_callback = null_send_callback;
630   callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
631   callbacks.on_frame_recv_callback = on_frame_recv_callback;
632
633   nghttp2_session_client_new(&session, &callbacks, &ud);
634
635   /* Create DATA frame with length 4KiB */
636   memset(data, 0, sizeof(data));
637   hd.length = 4096;
638   hd.type = NGHTTP2_DATA;
639   hd.flags = NGHTTP2_FLAG_NONE;
640   hd.stream_id = 1;
641   nghttp2_frame_pack_frame_hd(data, &hd);
642
643   /* stream 1 is not opened, so it must be responded with connection
644      error.  This is not mandated by the spec */
645   ud.data_chunk_recv_cb_called = 0;
646   ud.frame_recv_cb_called = 0;
647   rv = nghttp2_session_mem_recv(session, data, NGHTTP2_FRAME_HDLEN + 4096);
648   CU_ASSERT(NGHTTP2_FRAME_HDLEN + 4096 == rv);
649
650   CU_ASSERT(0 == ud.data_chunk_recv_cb_called);
651   CU_ASSERT(0 == ud.frame_recv_cb_called);
652   item = nghttp2_session_get_next_ob_item(session);
653   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
654
655   nghttp2_session_del(session);
656
657   nghttp2_session_client_new(&session, &callbacks, &ud);
658
659   /* Create stream 1 with CLOSING state. DATA is ignored. */
660   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
661                                        &pri_spec_default,
662                                        NGHTTP2_STREAM_CLOSING, NULL);
663   /* Set initial window size 16383 to check stream flow control,
664      isolating it from the conneciton flow control */
665   stream->local_window_size = 16383;
666
667   ud.data_chunk_recv_cb_called = 0;
668   ud.frame_recv_cb_called = 0;
669   rv = nghttp2_session_mem_recv(session, data, NGHTTP2_FRAME_HDLEN + 4096);
670   CU_ASSERT(NGHTTP2_FRAME_HDLEN + 4096 == rv);
671
672   CU_ASSERT(0 == ud.data_chunk_recv_cb_called);
673   CU_ASSERT(0 == ud.frame_recv_cb_called);
674   item = nghttp2_session_get_next_ob_item(session);
675   CU_ASSERT(NULL == item);
676
677   /* This is normal case. DATA is acceptable. */
678   stream->state = NGHTTP2_STREAM_OPENED;
679
680   ud.data_chunk_recv_cb_called = 0;
681   ud.frame_recv_cb_called = 0;
682   rv = nghttp2_session_mem_recv(session, data, NGHTTP2_FRAME_HDLEN + 4096);
683   CU_ASSERT(NGHTTP2_FRAME_HDLEN + 4096 == rv);
684
685   CU_ASSERT(1 == ud.data_chunk_recv_cb_called);
686   CU_ASSERT(1 == ud.frame_recv_cb_called);
687
688   CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
689
690   ud.data_chunk_recv_cb_called = 0;
691   ud.frame_recv_cb_called = 0;
692   rv = nghttp2_session_mem_recv(session, data, NGHTTP2_FRAME_HDLEN + 4096);
693   CU_ASSERT(NGHTTP2_FRAME_HDLEN + 4096 == rv);
694
695   /* Now we got data more than initial-window-size / 2, WINDOW_UPDATE
696      must be queued */
697   CU_ASSERT(1 == ud.data_chunk_recv_cb_called);
698   CU_ASSERT(1 == ud.frame_recv_cb_called);
699   item = nghttp2_session_get_next_ob_item(session);
700   CU_ASSERT(NGHTTP2_WINDOW_UPDATE == item->frame.hd.type);
701   CU_ASSERT(1 == item->frame.window_update.hd.stream_id);
702   CU_ASSERT(0 == nghttp2_session_send(session));
703
704   /* Set initial window size to 1MiB, so that we can check connection
705      flow control individually */
706   stream->local_window_size = 1 << 20;
707   /* Connection flow control takes into account DATA which is received
708      in the error condition. We have received 4096 * 4 bytes of
709      DATA. Additional 4 DATA frames, connection flow control will kick
710      in. */
711   for (i = 0; i < 5; ++i) {
712     rv = nghttp2_session_mem_recv(session, data, NGHTTP2_FRAME_HDLEN + 4096);
713     CU_ASSERT(NGHTTP2_FRAME_HDLEN + 4096 == rv);
714   }
715   item = nghttp2_session_get_next_ob_item(session);
716   CU_ASSERT(NGHTTP2_WINDOW_UPDATE == item->frame.hd.type);
717   CU_ASSERT(0 == item->frame.window_update.hd.stream_id);
718   CU_ASSERT(0 == nghttp2_session_send(session));
719
720   /* Reception of DATA with stream ID = 0 causes connection error */
721   hd.length = 4096;
722   hd.type = NGHTTP2_DATA;
723   hd.flags = NGHTTP2_FLAG_NONE;
724   hd.stream_id = 0;
725   nghttp2_frame_pack_frame_hd(data, &hd);
726
727   ud.data_chunk_recv_cb_called = 0;
728   ud.frame_recv_cb_called = 0;
729   rv = nghttp2_session_mem_recv(session, data, NGHTTP2_FRAME_HDLEN + 4096);
730   CU_ASSERT(NGHTTP2_FRAME_HDLEN + 4096 == rv);
731
732   CU_ASSERT(0 == ud.data_chunk_recv_cb_called);
733   CU_ASSERT(0 == ud.frame_recv_cb_called);
734   item = nghttp2_session_get_next_ob_item(session);
735   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
736   CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == item->frame.goaway.error_code);
737
738   nghttp2_session_del(session);
739 }
740
741 void test_nghttp2_session_recv_continuation(void) {
742   nghttp2_session *session;
743   nghttp2_session_callbacks callbacks;
744   const nghttp2_nv nv1[] = {MAKE_NV("method", "GET"), MAKE_NV("path", "/")};
745   nghttp2_nv *nva;
746   size_t nvlen;
747   nghttp2_frame frame;
748   nghttp2_bufs bufs;
749   nghttp2_buf *buf;
750   ssize_t rv;
751   my_user_data ud;
752   nghttp2_hd_deflater deflater;
753   uint8_t data[1024];
754   size_t datalen;
755   nghttp2_frame_hd cont_hd;
756   nghttp2_priority_spec pri_spec;
757   nghttp2_mem *mem;
758
759   mem = nghttp2_mem_default();
760   frame_pack_bufs_init(&bufs);
761
762   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
763   callbacks.on_header_callback = on_header_callback;
764   callbacks.on_begin_headers_callback = on_begin_headers_callback;
765   callbacks.on_begin_frame_callback = on_begin_frame_callback;
766
767   nghttp2_session_server_new(&session, &callbacks, &ud);
768
769   nghttp2_hd_deflate_init(&deflater, mem);
770
771   /* Make 1 HEADERS and insert CONTINUATION header */
772   nvlen = ARRLEN(nv1);
773   nghttp2_nv_array_copy(&nva, nv1, nvlen, mem);
774   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_NONE, 1,
775                              NGHTTP2_HCAT_HEADERS, NULL, nva, nvlen);
776   rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
777
778   CU_ASSERT(0 == rv);
779   CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
780
781   /* make sure that all data is in the first buf */
782   buf = &bufs.head->buf;
783   assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
784
785   nghttp2_frame_headers_free(&frame.headers, mem);
786
787   /* HEADERS's payload is 1 byte */
788   memcpy(data, buf->pos, NGHTTP2_FRAME_HDLEN + 1);
789   datalen = NGHTTP2_FRAME_HDLEN + 1;
790   buf->pos += NGHTTP2_FRAME_HDLEN + 1;
791
792   nghttp2_put_uint32be(data, (1 << 8) + data[3]);
793
794   /* First CONTINUATION, 2 bytes */
795   nghttp2_frame_hd_init(&cont_hd, 2, NGHTTP2_CONTINUATION, NGHTTP2_FLAG_NONE,
796                         1);
797
798   nghttp2_frame_pack_frame_hd(data + datalen, &cont_hd);
799   datalen += NGHTTP2_FRAME_HDLEN;
800
801   memcpy(data + datalen, buf->pos, cont_hd.length);
802   datalen += cont_hd.length;
803   buf->pos += cont_hd.length;
804
805   /* Second CONTINUATION, rest of the bytes */
806   nghttp2_frame_hd_init(&cont_hd, nghttp2_buf_len(buf), NGHTTP2_CONTINUATION,
807                         NGHTTP2_FLAG_END_HEADERS, 1);
808
809   nghttp2_frame_pack_frame_hd(data + datalen, &cont_hd);
810   datalen += NGHTTP2_FRAME_HDLEN;
811
812   memcpy(data + datalen, buf->pos, cont_hd.length);
813   datalen += cont_hd.length;
814   buf->pos += cont_hd.length;
815
816   CU_ASSERT(0 == nghttp2_buf_len(buf));
817
818   ud.header_cb_called = 0;
819   ud.begin_frame_cb_called = 0;
820
821   rv = nghttp2_session_mem_recv(session, data, datalen);
822   CU_ASSERT((ssize_t)datalen == rv);
823   CU_ASSERT(2 == ud.header_cb_called);
824   CU_ASSERT(3 == ud.begin_frame_cb_called);
825
826   nghttp2_hd_deflate_free(&deflater);
827   nghttp2_session_del(session);
828
829   /* Expecting CONTINUATION, but get the other frame */
830   nghttp2_session_server_new(&session, &callbacks, &ud);
831
832   nghttp2_hd_deflate_init(&deflater, mem);
833
834   /* HEADERS without END_HEADERS flag */
835   nvlen = ARRLEN(nv1);
836   nghttp2_nv_array_copy(&nva, nv1, nvlen, mem);
837   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_NONE, 1,
838                              NGHTTP2_HCAT_HEADERS, NULL, nva, nvlen);
839   nghttp2_bufs_reset(&bufs);
840   rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
841
842   CU_ASSERT(0 == rv);
843   CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
844
845   nghttp2_frame_headers_free(&frame.headers, mem);
846
847   /* make sure that all data is in the first buf */
848   buf = &bufs.head->buf;
849   assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
850
851   memcpy(data, buf->pos, nghttp2_buf_len(buf));
852   datalen = nghttp2_buf_len(buf);
853
854   /* Followed by PRIORITY */
855   nghttp2_priority_spec_default_init(&pri_spec);
856
857   nghttp2_frame_priority_init(&frame.priority, 1, &pri_spec);
858   nghttp2_bufs_reset(&bufs);
859
860   rv = nghttp2_frame_pack_priority(&bufs, &frame.priority);
861
862   CU_ASSERT(0 == rv);
863   CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
864
865   memcpy(data + datalen, buf->pos, nghttp2_buf_len(buf));
866   datalen += nghttp2_buf_len(buf);
867
868   ud.begin_headers_cb_called = 0;
869   rv = nghttp2_session_mem_recv(session, data, datalen);
870   CU_ASSERT((ssize_t)datalen == rv);
871
872   CU_ASSERT(1 == ud.begin_headers_cb_called);
873   CU_ASSERT(NGHTTP2_GOAWAY ==
874             nghttp2_session_get_next_ob_item(session)->frame.hd.type);
875
876   nghttp2_bufs_free(&bufs);
877   nghttp2_hd_deflate_free(&deflater);
878   nghttp2_session_del(session);
879 }
880
881 void test_nghttp2_session_recv_headers_with_priority(void) {
882   nghttp2_session *session;
883   nghttp2_session_callbacks callbacks;
884   const nghttp2_nv nv1[] = {MAKE_NV("method", "GET"), MAKE_NV("path", "/")};
885   nghttp2_nv *nva;
886   size_t nvlen;
887   nghttp2_frame frame;
888   nghttp2_bufs bufs;
889   nghttp2_buf *buf;
890   ssize_t rv;
891   my_user_data ud;
892   nghttp2_hd_deflater deflater;
893   nghttp2_outbound_item *item;
894   nghttp2_priority_spec pri_spec;
895   nghttp2_stream *stream;
896   nghttp2_mem *mem;
897
898   mem = nghttp2_mem_default();
899   frame_pack_bufs_init(&bufs);
900
901   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
902   callbacks.on_frame_recv_callback = on_frame_recv_callback;
903
904   nghttp2_session_server_new(&session, &callbacks, &ud);
905
906   nghttp2_hd_deflate_init(&deflater, mem);
907
908   open_stream(session, 1);
909
910   /* With NGHTTP2_FLAG_PRIORITY without exclusive flag set */
911   nvlen = ARRLEN(nv1);
912   nghttp2_nv_array_copy(&nva, nv1, nvlen, mem);
913
914   nghttp2_priority_spec_init(&pri_spec, 1, 99, 0);
915
916   nghttp2_frame_headers_init(&frame.headers,
917                              NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
918                              3, NGHTTP2_HCAT_HEADERS, &pri_spec, nva, nvlen);
919
920   rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
921
922   CU_ASSERT(0 == rv);
923   CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
924
925   nghttp2_frame_headers_free(&frame.headers, mem);
926
927   buf = &bufs.head->buf;
928   assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
929
930   ud.frame_recv_cb_called = 0;
931
932   rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
933
934   CU_ASSERT(nghttp2_buf_len(buf) == rv);
935   CU_ASSERT(1 == ud.frame_recv_cb_called);
936
937   stream = nghttp2_session_get_stream(session, 3);
938
939   CU_ASSERT(99 == stream->weight);
940   CU_ASSERT(1 == stream->dep_prev->stream_id);
941
942   nghttp2_bufs_reset(&bufs);
943
944   /* With NGHTTP2_FLAG_PRIORITY, but cut last 1 byte to make it
945      invalid. */
946   nvlen = ARRLEN(nv1);
947   nghttp2_nv_array_copy(&nva, nv1, nvlen, mem);
948
949   nghttp2_priority_spec_init(&pri_spec, 0, 99, 0);
950
951   nghttp2_frame_headers_init(&frame.headers,
952                              NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
953                              5, NGHTTP2_HCAT_HEADERS, &pri_spec, nva, nvlen);
954
955   rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
956
957   CU_ASSERT(0 == rv);
958   CU_ASSERT(NGHTTP2_FRAME_HDLEN + 5 + 2 == nghttp2_bufs_len(&bufs));
959
960   nghttp2_frame_headers_free(&frame.headers, mem);
961
962   buf = &bufs.head->buf;
963   /* Make payload shorter than required length to store priroty
964      group */
965   nghttp2_put_uint32be(buf->pos, (4 << 8) + buf->pos[3]);
966
967   ud.frame_recv_cb_called = 0;
968
969   rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
970
971   CU_ASSERT(nghttp2_buf_len(buf) == rv);
972   CU_ASSERT(0 == ud.frame_recv_cb_called);
973
974   stream = nghttp2_session_get_stream(session, 5);
975
976   CU_ASSERT(NULL == stream);
977
978   item = nghttp2_session_get_next_ob_item(session);
979   CU_ASSERT(NULL != item);
980   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
981   CU_ASSERT(NGHTTP2_FRAME_SIZE_ERROR == item->frame.goaway.error_code);
982
983   nghttp2_bufs_reset(&bufs);
984
985   nghttp2_hd_deflate_free(&deflater);
986   nghttp2_session_del(session);
987
988   /* Check dep_stream_id == stream_id */
989   nghttp2_session_server_new(&session, &callbacks, &ud);
990
991   nghttp2_hd_deflate_init(&deflater, mem);
992
993   nvlen = ARRLEN(nv1);
994   nghttp2_nv_array_copy(&nva, nv1, nvlen, mem);
995
996   nghttp2_priority_spec_init(&pri_spec, 1, 0, 0);
997
998   nghttp2_frame_headers_init(&frame.headers,
999                              NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
1000                              1, NGHTTP2_HCAT_HEADERS, &pri_spec, nva, nvlen);
1001
1002   rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
1003
1004   CU_ASSERT(0 == rv);
1005   CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
1006
1007   nghttp2_frame_headers_free(&frame.headers, mem);
1008
1009   buf = &bufs.head->buf;
1010   assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
1011
1012   ud.frame_recv_cb_called = 0;
1013
1014   rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
1015
1016   CU_ASSERT(nghttp2_buf_len(buf) == rv);
1017   CU_ASSERT(0 == ud.frame_recv_cb_called);
1018
1019   stream = nghttp2_session_get_stream(session, 1);
1020
1021   CU_ASSERT(NULL == stream);
1022
1023   item = nghttp2_session_get_next_ob_item(session);
1024   CU_ASSERT(NULL != item);
1025   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
1026   CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == item->frame.goaway.error_code);
1027
1028   nghttp2_bufs_reset(&bufs);
1029
1030   nghttp2_bufs_free(&bufs);
1031   nghttp2_hd_deflate_free(&deflater);
1032   nghttp2_session_del(session);
1033 }
1034
1035 void test_nghttp2_session_recv_premature_headers(void) {
1036   nghttp2_session *session;
1037   nghttp2_session_callbacks callbacks;
1038   const nghttp2_nv nv1[] = {MAKE_NV("method", "GET"), MAKE_NV("path", "/")};
1039   nghttp2_nv *nva;
1040   size_t nvlen;
1041   nghttp2_frame frame;
1042   nghttp2_bufs bufs;
1043   nghttp2_buf *buf;
1044   ssize_t rv;
1045   my_user_data ud;
1046   nghttp2_hd_deflater deflater;
1047   nghttp2_outbound_item *item;
1048   nghttp2_mem *mem;
1049
1050   mem = nghttp2_mem_default();
1051   frame_pack_bufs_init(&bufs);
1052
1053   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
1054
1055   nghttp2_session_server_new(&session, &callbacks, &ud);
1056
1057   nghttp2_hd_deflate_init(&deflater, mem);
1058
1059   nvlen = ARRLEN(nv1);
1060   nghttp2_nv_array_copy(&nva, nv1, nvlen, mem);
1061   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
1062                              NGHTTP2_HCAT_HEADERS, NULL, nva, nvlen);
1063   rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
1064
1065   CU_ASSERT(0 == rv);
1066   CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
1067
1068   nghttp2_frame_headers_free(&frame.headers, mem);
1069
1070   buf = &bufs.head->buf;
1071   assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
1072
1073   /* Intentionally feed payload cutting last 1 byte off */
1074   nghttp2_put_uint32be(buf->pos,
1075                        (uint32_t)(((frame.hd.length - 1) << 8) + buf->pos[3]));
1076   rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf) - 1);
1077
1078   CU_ASSERT((ssize_t)(nghttp2_buf_len(buf) - 1) == rv);
1079
1080   item = nghttp2_session_get_next_ob_item(session);
1081   CU_ASSERT(NULL != item);
1082   CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
1083   CU_ASSERT(NGHTTP2_COMPRESSION_ERROR == item->frame.rst_stream.error_code);
1084
1085   nghttp2_bufs_free(&bufs);
1086   nghttp2_hd_deflate_free(&deflater);
1087   nghttp2_session_del(session);
1088 }
1089
1090 void test_nghttp2_session_recv_unknown_frame(void) {
1091   nghttp2_session *session;
1092   nghttp2_session_callbacks callbacks;
1093   my_user_data ud;
1094   uint8_t data[16384];
1095   size_t datalen;
1096   nghttp2_frame_hd hd;
1097   ssize_t rv;
1098
1099   nghttp2_frame_hd_init(&hd, 16000, 99, NGHTTP2_FLAG_NONE, 0);
1100
1101   nghttp2_frame_pack_frame_hd(data, &hd);
1102   datalen = NGHTTP2_FRAME_HDLEN + hd.length;
1103
1104   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
1105   callbacks.on_frame_recv_callback = on_frame_recv_callback;
1106
1107   nghttp2_session_server_new(&session, &callbacks, &ud);
1108
1109   ud.frame_recv_cb_called = 0;
1110
1111   /* Unknown frame must be ignored */
1112   rv = nghttp2_session_mem_recv(session, data, datalen);
1113
1114   CU_ASSERT(rv == (ssize_t)datalen);
1115   CU_ASSERT(0 == ud.frame_recv_cb_called);
1116   CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
1117
1118   nghttp2_session_del(session);
1119 }
1120
1121 void test_nghttp2_session_recv_unexpected_continuation(void) {
1122   nghttp2_session *session;
1123   nghttp2_session_callbacks callbacks;
1124   my_user_data ud;
1125   uint8_t data[16384];
1126   size_t datalen;
1127   nghttp2_frame_hd hd;
1128   ssize_t rv;
1129   nghttp2_outbound_item *item;
1130
1131   nghttp2_frame_hd_init(&hd, 16000, NGHTTP2_CONTINUATION,
1132                         NGHTTP2_FLAG_END_HEADERS, 1);
1133
1134   nghttp2_frame_pack_frame_hd(data, &hd);
1135   datalen = NGHTTP2_FRAME_HDLEN + hd.length;
1136
1137   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
1138   callbacks.on_frame_recv_callback = on_frame_recv_callback;
1139
1140   nghttp2_session_server_new(&session, &callbacks, &ud);
1141
1142   open_stream(session, 1);
1143
1144   ud.frame_recv_cb_called = 0;
1145
1146   /* unexpected CONTINUATION must be treated as connection error */
1147   rv = nghttp2_session_mem_recv(session, data, datalen);
1148
1149   CU_ASSERT(rv == (ssize_t)datalen);
1150   CU_ASSERT(0 == ud.frame_recv_cb_called);
1151
1152   item = nghttp2_session_get_next_ob_item(session);
1153
1154   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
1155
1156   nghttp2_session_del(session);
1157 }
1158
1159 void test_nghttp2_session_recv_settings_header_table_size(void) {
1160   nghttp2_session *session;
1161   nghttp2_session_callbacks callbacks;
1162   nghttp2_frame frame;
1163   nghttp2_bufs bufs;
1164   nghttp2_buf *buf;
1165   ssize_t rv;
1166   my_user_data ud;
1167   nghttp2_settings_entry iv[3];
1168   nghttp2_nv nv = MAKE_NV(":authority", "example.org");
1169   nghttp2_mem *mem;
1170
1171   mem = nghttp2_mem_default();
1172   frame_pack_bufs_init(&bufs);
1173
1174   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
1175   callbacks.on_frame_recv_callback = on_frame_recv_callback;
1176   callbacks.send_callback = null_send_callback;
1177
1178   nghttp2_session_client_new(&session, &callbacks, &ud);
1179
1180   iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
1181   iv[0].value = 3000;
1182
1183   iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
1184   iv[1].value = 16384;
1185
1186   nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE, dup_iv(iv, 2),
1187                               2);
1188
1189   rv = nghttp2_frame_pack_settings(&bufs, &frame.settings);
1190
1191   CU_ASSERT(0 == rv);
1192   CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
1193
1194   nghttp2_frame_settings_free(&frame.settings, mem);
1195
1196   buf = &bufs.head->buf;
1197   assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
1198
1199   ud.frame_recv_cb_called = 0;
1200
1201   rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
1202
1203   CU_ASSERT(rv == nghttp2_buf_len(buf));
1204   CU_ASSERT(1 == ud.frame_recv_cb_called);
1205
1206   CU_ASSERT(3000 == session->remote_settings.header_table_size);
1207   CU_ASSERT(16384 == session->remote_settings.initial_window_size);
1208
1209   nghttp2_bufs_reset(&bufs);
1210
1211   /* 2 SETTINGS_HEADER_TABLE_SIZE */
1212   iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
1213   iv[0].value = 3001;
1214
1215   iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
1216   iv[1].value = 16383;
1217
1218   iv[2].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
1219   iv[2].value = 3001;
1220
1221   nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE, dup_iv(iv, 3),
1222                               3);
1223
1224   rv = nghttp2_frame_pack_settings(&bufs, &frame.settings);
1225
1226   CU_ASSERT(0 == rv);
1227   CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
1228
1229   nghttp2_frame_settings_free(&frame.settings, mem);
1230
1231   buf = &bufs.head->buf;
1232   assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
1233
1234   ud.frame_recv_cb_called = 0;
1235
1236   rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
1237
1238   CU_ASSERT(rv == nghttp2_buf_len(buf));
1239   CU_ASSERT(1 == ud.frame_recv_cb_called);
1240
1241   CU_ASSERT(3001 == session->remote_settings.header_table_size);
1242   CU_ASSERT(16383 == session->remote_settings.initial_window_size);
1243
1244   nghttp2_bufs_reset(&bufs);
1245
1246   /* 2 SETTINGS_HEADER_TABLE_SIZE; first entry clears dynamic header
1247      table. */
1248
1249   nghttp2_submit_request(session, NULL, &nv, 1, NULL, NULL);
1250   nghttp2_session_send(session);
1251
1252   CU_ASSERT(0 < session->hd_deflater.ctx.hd_table.len);
1253
1254   iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
1255   iv[0].value = 0;
1256
1257   iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
1258   iv[1].value = 16382;
1259
1260   iv[2].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
1261   iv[2].value = 4096;
1262
1263   nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE, dup_iv(iv, 3),
1264                               3);
1265
1266   rv = nghttp2_frame_pack_settings(&bufs, &frame.settings);
1267
1268   CU_ASSERT(0 == rv);
1269   CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
1270
1271   nghttp2_frame_settings_free(&frame.settings, mem);
1272
1273   buf = &bufs.head->buf;
1274   assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
1275
1276   ud.frame_recv_cb_called = 0;
1277
1278   rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
1279
1280   CU_ASSERT(rv == nghttp2_buf_len(buf));
1281   CU_ASSERT(1 == ud.frame_recv_cb_called);
1282
1283   CU_ASSERT(4096 == session->remote_settings.header_table_size);
1284   CU_ASSERT(16382 == session->remote_settings.initial_window_size);
1285   CU_ASSERT(0 == session->hd_deflater.ctx.hd_table.len);
1286
1287   nghttp2_bufs_reset(&bufs);
1288
1289   /* 2 SETTINGS_HEADER_TABLE_SIZE; second entry clears dynamic header
1290      table. */
1291
1292   nghttp2_submit_request(session, NULL, &nv, 1, NULL, NULL);
1293   nghttp2_session_send(session);
1294
1295   CU_ASSERT(0 < session->hd_deflater.ctx.hd_table.len);
1296
1297   iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
1298   iv[0].value = 3000;
1299
1300   iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
1301   iv[1].value = 16381;
1302
1303   iv[2].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
1304   iv[2].value = 0;
1305
1306   nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE, dup_iv(iv, 3),
1307                               3);
1308
1309   rv = nghttp2_frame_pack_settings(&bufs, &frame.settings);
1310
1311   CU_ASSERT(0 == rv);
1312   CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
1313
1314   nghttp2_frame_settings_free(&frame.settings, mem);
1315
1316   buf = &bufs.head->buf;
1317   assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
1318
1319   ud.frame_recv_cb_called = 0;
1320
1321   rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_buf_len(buf));
1322
1323   CU_ASSERT(rv == nghttp2_buf_len(buf));
1324   CU_ASSERT(1 == ud.frame_recv_cb_called);
1325
1326   CU_ASSERT(0 == session->remote_settings.header_table_size);
1327   CU_ASSERT(16381 == session->remote_settings.initial_window_size);
1328   CU_ASSERT(0 == session->hd_deflater.ctx.hd_table.len);
1329
1330   nghttp2_bufs_reset(&bufs);
1331
1332   nghttp2_bufs_free(&bufs);
1333   nghttp2_session_del(session);
1334 }
1335
1336 void test_nghttp2_session_recv_too_large_frame_length(void) {
1337   nghttp2_session *session;
1338   nghttp2_session_callbacks callbacks;
1339   uint8_t buf[NGHTTP2_FRAME_HDLEN];
1340   nghttp2_outbound_item *item;
1341   nghttp2_frame_hd hd;
1342
1343   /* Initial max frame size is NGHTTP2_MAX_FRAME_SIZE_MIN */
1344   nghttp2_frame_hd_init(&hd, NGHTTP2_MAX_FRAME_SIZE_MIN + 1, NGHTTP2_HEADERS,
1345                         NGHTTP2_FLAG_NONE, 1);
1346
1347   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
1348
1349   nghttp2_session_server_new(&session, &callbacks, NULL);
1350
1351   nghttp2_frame_pack_frame_hd(buf, &hd);
1352
1353   CU_ASSERT(sizeof(buf) == nghttp2_session_mem_recv(session, buf, sizeof(buf)));
1354
1355   item = nghttp2_session_get_next_ob_item(session);
1356
1357   CU_ASSERT(item != NULL);
1358   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
1359
1360   nghttp2_session_del(session);
1361 }
1362
1363 void test_nghttp2_session_continue(void) {
1364   nghttp2_session *session;
1365   nghttp2_session_callbacks callbacks;
1366   my_user_data user_data;
1367   const nghttp2_nv nv1[] = {MAKE_NV(":method", "GET"), MAKE_NV(":path", "/")};
1368   const nghttp2_nv nv2[] = {MAKE_NV("user-agent", "nghttp2/1.0.0"),
1369                             MAKE_NV("alpha", "bravo")};
1370   nghttp2_bufs bufs;
1371   nghttp2_buf *buf;
1372   size_t framelen1, framelen2;
1373   ssize_t rv;
1374   uint8_t buffer[4096];
1375   nghttp2_buf databuf;
1376   nghttp2_frame frame;
1377   nghttp2_nv *nva;
1378   ssize_t nvlen;
1379   const nghttp2_frame *recv_frame;
1380   nghttp2_frame_hd data_hd;
1381   nghttp2_hd_deflater deflater;
1382   nghttp2_mem *mem;
1383
1384   mem = nghttp2_mem_default();
1385   frame_pack_bufs_init(&bufs);
1386   nghttp2_buf_wrap_init(&databuf, buffer, sizeof(buffer));
1387
1388   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
1389   callbacks.send_callback = null_send_callback;
1390   callbacks.on_frame_recv_callback = on_frame_recv_callback;
1391   callbacks.on_data_chunk_recv_callback = pause_on_data_chunk_recv_callback;
1392   callbacks.on_header_callback = pause_on_header_callback;
1393   callbacks.on_begin_headers_callback = on_begin_headers_callback;
1394
1395   nghttp2_session_server_new(&session, &callbacks, &user_data);
1396
1397   nghttp2_hd_deflate_init(&deflater, mem);
1398
1399   /* Make 2 HEADERS frames */
1400   nvlen = ARRLEN(nv1);
1401   nghttp2_nv_array_copy(&nva, nv1, nvlen, mem);
1402   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
1403                              NGHTTP2_HCAT_HEADERS, NULL, nva, nvlen);
1404   rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
1405
1406   CU_ASSERT(0 == rv);
1407   CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
1408
1409   nghttp2_frame_headers_free(&frame.headers, mem);
1410
1411   buf = &bufs.head->buf;
1412   assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
1413
1414   framelen1 = nghttp2_buf_len(buf);
1415   databuf.last = nghttp2_cpymem(databuf.last, buf->pos, nghttp2_buf_len(buf));
1416
1417   nvlen = ARRLEN(nv2);
1418   nghttp2_nv_array_copy(&nva, nv2, nvlen, mem);
1419   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 3,
1420                              NGHTTP2_HCAT_HEADERS, NULL, nva, nvlen);
1421   nghttp2_bufs_reset(&bufs);
1422   rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
1423
1424   CU_ASSERT(0 == rv);
1425   CU_ASSERT(nghttp2_bufs_len(&bufs) > 0);
1426
1427   nghttp2_frame_headers_free(&frame.headers, mem);
1428
1429   assert(nghttp2_bufs_len(&bufs) == nghttp2_buf_len(buf));
1430
1431   framelen2 = nghttp2_buf_len(buf);
1432   databuf.last = nghttp2_cpymem(databuf.last, buf->pos, nghttp2_buf_len(buf));
1433
1434   /* Receive 1st HEADERS and pause */
1435   user_data.begin_headers_cb_called = 0;
1436   user_data.header_cb_called = 0;
1437   rv =
1438       nghttp2_session_mem_recv(session, databuf.pos, nghttp2_buf_len(&databuf));
1439
1440   CU_ASSERT(rv >= 0);
1441   databuf.pos += rv;
1442
1443   recv_frame = user_data.frame;
1444   CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type);
1445   CU_ASSERT(framelen1 - NGHTTP2_FRAME_HDLEN == recv_frame->hd.length);
1446
1447   CU_ASSERT(1 == user_data.begin_headers_cb_called);
1448   CU_ASSERT(1 == user_data.header_cb_called);
1449
1450   CU_ASSERT(nghttp2_nv_equal(&nv1[0], &user_data.nv));
1451
1452   /* get 2nd header field */
1453   user_data.begin_headers_cb_called = 0;
1454   user_data.header_cb_called = 0;
1455   rv =
1456       nghttp2_session_mem_recv(session, databuf.pos, nghttp2_buf_len(&databuf));
1457
1458   CU_ASSERT(rv >= 0);
1459   databuf.pos += rv;
1460
1461   CU_ASSERT(0 == user_data.begin_headers_cb_called);
1462   CU_ASSERT(1 == user_data.header_cb_called);
1463
1464   CU_ASSERT(nghttp2_nv_equal(&nv1[1], &user_data.nv));
1465
1466   /* will call end_headers_callback and receive 2nd HEADERS and pause */
1467   user_data.begin_headers_cb_called = 0;
1468   user_data.header_cb_called = 0;
1469   rv =
1470       nghttp2_session_mem_recv(session, databuf.pos, nghttp2_buf_len(&databuf));
1471
1472   CU_ASSERT(rv >= 0);
1473   databuf.pos += rv;
1474
1475   recv_frame = user_data.frame;
1476   CU_ASSERT(NGHTTP2_HEADERS == recv_frame->hd.type);
1477   CU_ASSERT(framelen2 - NGHTTP2_FRAME_HDLEN == recv_frame->hd.length);
1478
1479   CU_ASSERT(1 == user_data.begin_headers_cb_called);
1480   CU_ASSERT(1 == user_data.header_cb_called);
1481
1482   CU_ASSERT(nghttp2_nv_equal(&nv2[0], &user_data.nv));
1483
1484   /* get 2nd header field */
1485   user_data.begin_headers_cb_called = 0;
1486   user_data.header_cb_called = 0;
1487   rv =
1488       nghttp2_session_mem_recv(session, databuf.pos, nghttp2_buf_len(&databuf));
1489
1490   CU_ASSERT(rv >= 0);
1491   databuf.pos += rv;
1492
1493   CU_ASSERT(0 == user_data.begin_headers_cb_called);
1494   CU_ASSERT(1 == user_data.header_cb_called);
1495
1496   CU_ASSERT(nghttp2_nv_equal(&nv2[1], &user_data.nv));
1497
1498   /* No input data, frame_recv_callback is called */
1499   user_data.begin_headers_cb_called = 0;
1500   user_data.header_cb_called = 0;
1501   user_data.frame_recv_cb_called = 0;
1502   rv =
1503       nghttp2_session_mem_recv(session, databuf.pos, nghttp2_buf_len(&databuf));
1504
1505   CU_ASSERT(rv >= 0);
1506   databuf.pos += rv;
1507
1508   CU_ASSERT(0 == user_data.begin_headers_cb_called);
1509   CU_ASSERT(0 == user_data.header_cb_called);
1510   CU_ASSERT(1 == user_data.frame_recv_cb_called);
1511
1512   /* Receive DATA */
1513   nghttp2_frame_hd_init(&data_hd, 16, NGHTTP2_DATA, NGHTTP2_FLAG_NONE, 1);
1514
1515   nghttp2_buf_reset(&databuf);
1516   nghttp2_frame_pack_frame_hd(databuf.pos, &data_hd);
1517
1518   /* Intentionally specify larger buffer size to see pause is kicked
1519      in. */
1520   databuf.last = databuf.end;
1521
1522   user_data.frame_recv_cb_called = 0;
1523   rv =
1524       nghttp2_session_mem_recv(session, databuf.pos, nghttp2_buf_len(&databuf));
1525
1526   CU_ASSERT(16 + NGHTTP2_FRAME_HDLEN == rv);
1527   CU_ASSERT(0 == user_data.frame_recv_cb_called);
1528
1529   /* Next nghttp2_session_mem_recv invokes on_frame_recv_callback and
1530      pause again in on_data_chunk_recv_callback since we pass same
1531      DATA frame. */
1532   user_data.frame_recv_cb_called = 0;
1533   rv =
1534       nghttp2_session_mem_recv(session, databuf.pos, nghttp2_buf_len(&databuf));
1535   CU_ASSERT(16 + NGHTTP2_FRAME_HDLEN == rv);
1536   CU_ASSERT(1 == user_data.frame_recv_cb_called);
1537
1538   /* And finally call on_frame_recv_callback with 0 size input */
1539   user_data.frame_recv_cb_called = 0;
1540   rv = nghttp2_session_mem_recv(session, NULL, 0);
1541   CU_ASSERT(0 == rv);
1542   CU_ASSERT(1 == user_data.frame_recv_cb_called);
1543
1544   nghttp2_bufs_free(&bufs);
1545   nghttp2_hd_deflate_free(&deflater);
1546   nghttp2_session_del(session);
1547 }
1548
1549 void test_nghttp2_session_add_frame(void) {
1550   nghttp2_session *session;
1551   nghttp2_session_callbacks callbacks;
1552   accumulator acc;
1553   my_user_data user_data;
1554   const nghttp2_nv nv[] = {MAKE_NV("method", "GET"), MAKE_NV("scheme", "https"),
1555                            MAKE_NV("url", "/"), MAKE_NV("version", "HTTP/1.1")};
1556   nghttp2_outbound_item *item;
1557   nghttp2_frame *frame;
1558   nghttp2_nv *nva;
1559   ssize_t nvlen;
1560   nghttp2_mem *mem;
1561
1562   mem = nghttp2_mem_default();
1563   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
1564   callbacks.send_callback = accumulator_send_callback;
1565
1566   acc.length = 0;
1567   user_data.acc = &acc;
1568
1569   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &user_data));
1570
1571   item = malloc(sizeof(nghttp2_outbound_item));
1572
1573   nghttp2_session_outbound_item_init(session, item);
1574
1575   frame = &item->frame;
1576
1577   nvlen = ARRLEN(nv);
1578   nghttp2_nv_array_copy(&nva, nv, nvlen, mem);
1579
1580   nghttp2_frame_headers_init(
1581       &frame->headers, NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
1582       session->next_stream_id, NGHTTP2_HCAT_REQUEST, NULL, nva, nvlen);
1583
1584   session->next_stream_id += 2;
1585
1586   CU_ASSERT(0 == nghttp2_session_add_item(session, item));
1587   CU_ASSERT(0 == nghttp2_pq_empty(&session->ob_ss_pq));
1588   CU_ASSERT(0 == nghttp2_session_send(session));
1589   CU_ASSERT(NGHTTP2_HEADERS == acc.buf[3]);
1590   CU_ASSERT((NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY) == acc.buf[4]);
1591   /* check stream id */
1592   CU_ASSERT(1 == nghttp2_get_uint32(&acc.buf[5]));
1593
1594   nghttp2_session_del(session);
1595 }
1596
1597 void test_nghttp2_session_on_request_headers_received(void) {
1598   nghttp2_session *session;
1599   nghttp2_session_callbacks callbacks;
1600   my_user_data user_data;
1601   nghttp2_frame frame;
1602   nghttp2_stream *stream;
1603   int32_t stream_id = 1;
1604   nghttp2_nv malformed_nva[] = {MAKE_NV(":path", "\x01")};
1605   nghttp2_nv *nva;
1606   size_t nvlen;
1607   nghttp2_priority_spec pri_spec;
1608   nghttp2_mem *mem;
1609
1610   mem = nghttp2_mem_default();
1611   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
1612   callbacks.on_begin_headers_callback = on_begin_headers_callback;
1613   callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
1614
1615   nghttp2_session_server_new(&session, &callbacks, &user_data);
1616
1617   nghttp2_priority_spec_init(&pri_spec, 0, 255, 0);
1618
1619   nghttp2_frame_headers_init(
1620       &frame.headers, NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
1621       stream_id, NGHTTP2_HCAT_REQUEST, &pri_spec, NULL, 0);
1622
1623   user_data.begin_headers_cb_called = 0;
1624   user_data.invalid_frame_recv_cb_called = 0;
1625
1626   CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame));
1627   CU_ASSERT(1 == user_data.begin_headers_cb_called);
1628   stream = nghttp2_session_get_stream(session, stream_id);
1629   CU_ASSERT(NGHTTP2_STREAM_OPENING == stream->state);
1630   CU_ASSERT(255 == stream->weight);
1631
1632   nghttp2_frame_headers_free(&frame.headers, mem);
1633
1634   /* More than un-ACKed max concurrent streams leads REFUSED_STREAM */
1635   session->pending_local_max_concurrent_stream = 1;
1636   nghttp2_frame_headers_init(&frame.headers,
1637                              NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
1638                              3, NGHTTP2_HCAT_HEADERS, NULL, NULL, 0);
1639   user_data.invalid_frame_recv_cb_called = 0;
1640   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
1641             nghttp2_session_on_request_headers_received(session, &frame));
1642   CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
1643   CU_ASSERT(0 == (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND));
1644
1645   nghttp2_frame_headers_free(&frame.headers, mem);
1646   session->local_settings.max_concurrent_streams =
1647       NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS;
1648
1649   /* Stream ID less than or equal to the previouly received request
1650      HEADERS is just ignored due to race condition */
1651   nghttp2_frame_headers_init(&frame.headers,
1652                              NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
1653                              3, NGHTTP2_HCAT_HEADERS, NULL, NULL, 0);
1654   user_data.invalid_frame_recv_cb_called = 0;
1655   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
1656             nghttp2_session_on_request_headers_received(session, &frame));
1657   CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called);
1658   CU_ASSERT(0 == (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND));
1659
1660   nghttp2_frame_headers_free(&frame.headers, mem);
1661
1662   /* Stream ID is our side and it is idle stream ID, then treat it as
1663      connection error */
1664   nghttp2_frame_headers_init(&frame.headers,
1665                              NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
1666                              2, NGHTTP2_HCAT_HEADERS, NULL, NULL, 0);
1667   user_data.invalid_frame_recv_cb_called = 0;
1668   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
1669             nghttp2_session_on_request_headers_received(session, &frame));
1670   CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
1671   CU_ASSERT(session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND);
1672
1673   nghttp2_frame_headers_free(&frame.headers, mem);
1674
1675   nghttp2_session_del(session);
1676
1677   /* Check malformed headers. The library accept it. */
1678   nghttp2_session_server_new(&session, &callbacks, &user_data);
1679
1680   nvlen = ARRLEN(malformed_nva);
1681   nghttp2_nv_array_copy(&nva, malformed_nva, nvlen, mem);
1682   nghttp2_frame_headers_init(&frame.headers,
1683                              NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_PRIORITY,
1684                              1, NGHTTP2_HCAT_HEADERS, NULL, nva, nvlen);
1685   user_data.begin_headers_cb_called = 0;
1686   user_data.invalid_frame_recv_cb_called = 0;
1687   CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame));
1688   CU_ASSERT(1 == user_data.begin_headers_cb_called);
1689   CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called);
1690
1691   nghttp2_frame_headers_free(&frame.headers, mem);
1692
1693   nghttp2_session_del(session);
1694
1695   /* Check client side */
1696   nghttp2_session_client_new(&session, &callbacks, &user_data);
1697
1698   /* Receiving peer's idle stream ID is subject to connection error */
1699   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 2,
1700                              NGHTTP2_HCAT_REQUEST, NULL, NULL, 0);
1701
1702   user_data.invalid_frame_recv_cb_called = 0;
1703   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
1704             nghttp2_session_on_request_headers_received(session, &frame));
1705   CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
1706   CU_ASSERT(session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND);
1707
1708   nghttp2_frame_headers_free(&frame.headers, mem);
1709
1710   nghttp2_session_del(session);
1711
1712   nghttp2_session_client_new(&session, &callbacks, &user_data);
1713
1714   /* Receiving our's idle stream ID is subject to connection error */
1715   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
1716                              NGHTTP2_HCAT_REQUEST, NULL, NULL, 0);
1717
1718   user_data.invalid_frame_recv_cb_called = 0;
1719   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
1720             nghttp2_session_on_request_headers_received(session, &frame));
1721   CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
1722   CU_ASSERT(session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND);
1723
1724   nghttp2_frame_headers_free(&frame.headers, mem);
1725
1726   nghttp2_session_del(session);
1727
1728   nghttp2_session_client_new(&session, &callbacks, &user_data);
1729
1730   session->next_stream_id = 5;
1731
1732   /* Stream ID which is not idle and not in stream map is just
1733      ignored */
1734   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 3,
1735                              NGHTTP2_HCAT_REQUEST, NULL, NULL, 0);
1736
1737   user_data.invalid_frame_recv_cb_called = 0;
1738   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
1739             nghttp2_session_on_request_headers_received(session, &frame));
1740   CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called);
1741   CU_ASSERT(0 == (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND));
1742
1743   nghttp2_frame_headers_free(&frame.headers, mem);
1744
1745   nghttp2_session_del(session);
1746
1747   nghttp2_session_server_new(&session, &callbacks, &user_data);
1748
1749   /* Stream ID which is equal to local_last_stream_id is ok. */
1750   session->local_last_stream_id = 3;
1751
1752   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 3,
1753                              NGHTTP2_HCAT_REQUEST, NULL, NULL, 0);
1754
1755   CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session, &frame));
1756
1757   nghttp2_frame_headers_free(&frame.headers, mem);
1758
1759   /* If GOAWAY has been sent, new stream is ignored */
1760   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 5,
1761                              NGHTTP2_HCAT_REQUEST, NULL, NULL, 0);
1762
1763   session->goaway_flags |= NGHTTP2_GOAWAY_SENT;
1764   user_data.invalid_frame_recv_cb_called = 0;
1765   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
1766             nghttp2_session_on_request_headers_received(session, &frame));
1767   CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called);
1768   CU_ASSERT(0 == (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND));
1769
1770   nghttp2_frame_headers_free(&frame.headers, mem);
1771
1772   nghttp2_session_del(session);
1773 }
1774
1775 void test_nghttp2_session_on_response_headers_received(void) {
1776   nghttp2_session *session;
1777   nghttp2_session_callbacks callbacks;
1778   my_user_data user_data;
1779   nghttp2_frame frame;
1780   nghttp2_stream *stream;
1781   nghttp2_mem *mem;
1782
1783   mem = nghttp2_mem_default();
1784   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
1785   callbacks.on_begin_headers_callback = on_begin_headers_callback;
1786   callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
1787
1788   nghttp2_session_client_new(&session, &callbacks, &user_data);
1789   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
1790                                        &pri_spec_default,
1791                                        NGHTTP2_STREAM_OPENING, NULL);
1792   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
1793                              NGHTTP2_HCAT_HEADERS, NULL, NULL, 0);
1794
1795   user_data.begin_headers_cb_called = 0;
1796   user_data.invalid_frame_recv_cb_called = 0;
1797
1798   CU_ASSERT(0 == nghttp2_session_on_response_headers_received(session, &frame,
1799                                                               stream));
1800   CU_ASSERT(1 == user_data.begin_headers_cb_called);
1801   CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
1802
1803   nghttp2_frame_headers_free(&frame.headers, mem);
1804   nghttp2_session_del(session);
1805 }
1806
1807 void test_nghttp2_session_on_headers_received(void) {
1808   nghttp2_session *session;
1809   nghttp2_session_callbacks callbacks;
1810   my_user_data user_data;
1811   nghttp2_frame frame;
1812   nghttp2_stream *stream;
1813   nghttp2_mem *mem;
1814
1815   mem = nghttp2_mem_default();
1816   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
1817   callbacks.on_begin_headers_callback = on_begin_headers_callback;
1818   callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
1819
1820   nghttp2_session_client_new(&session, &callbacks, &user_data);
1821   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
1822                                        &pri_spec_default, NGHTTP2_STREAM_OPENED,
1823                                        NULL);
1824   nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR);
1825   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
1826                              NGHTTP2_HCAT_HEADERS, NULL, NULL, 0);
1827
1828   user_data.begin_headers_cb_called = 0;
1829   user_data.invalid_frame_recv_cb_called = 0;
1830
1831   CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream));
1832   CU_ASSERT(1 == user_data.begin_headers_cb_called);
1833   CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
1834
1835   /* stream closed */
1836   frame.hd.flags |= NGHTTP2_FLAG_END_STREAM;
1837
1838   CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream));
1839   CU_ASSERT(2 == user_data.begin_headers_cb_called);
1840
1841   /* Check to see when NGHTTP2_STREAM_CLOSING, incoming HEADERS is
1842      discarded. */
1843   stream = nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE,
1844                                        &pri_spec_default,
1845                                        NGHTTP2_STREAM_CLOSING, NULL);
1846   frame.hd.stream_id = 3;
1847   frame.hd.flags = NGHTTP2_FLAG_END_HEADERS;
1848   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
1849             nghttp2_session_on_headers_received(session, &frame, stream));
1850   /* See no counters are updated */
1851   CU_ASSERT(2 == user_data.begin_headers_cb_called);
1852   CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called);
1853
1854   /* Server initiated stream */
1855   stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
1856                                        &pri_spec_default,
1857                                        NGHTTP2_STREAM_OPENING, NULL);
1858
1859   /* half closed (remote) */
1860   frame.hd.flags = NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_END_STREAM;
1861   frame.hd.stream_id = 2;
1862
1863   CU_ASSERT(0 == nghttp2_session_on_headers_received(session, &frame, stream));
1864   CU_ASSERT(3 == user_data.begin_headers_cb_called);
1865   CU_ASSERT(NGHTTP2_STREAM_OPENING == stream->state);
1866
1867   nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
1868
1869   /* Further reception of HEADERS is subject to stream error */
1870   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
1871             nghttp2_session_on_headers_received(session, &frame, stream));
1872   CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
1873
1874   nghttp2_frame_headers_free(&frame.headers, mem);
1875
1876   nghttp2_session_del(session);
1877 }
1878
1879 void test_nghttp2_session_on_push_response_headers_received(void) {
1880   nghttp2_session *session;
1881   nghttp2_session_callbacks callbacks;
1882   my_user_data user_data;
1883   nghttp2_frame frame;
1884   nghttp2_stream *stream;
1885   nghttp2_outbound_item *item;
1886   nghttp2_mem *mem;
1887
1888   mem = nghttp2_mem_default();
1889   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
1890   callbacks.send_callback = null_send_callback;
1891   callbacks.on_begin_headers_callback = on_begin_headers_callback;
1892   callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
1893
1894   nghttp2_session_client_new(&session, &callbacks, &user_data);
1895   stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
1896                                        &pri_spec_default,
1897                                        NGHTTP2_STREAM_RESERVED, NULL);
1898   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 2,
1899                              NGHTTP2_HCAT_HEADERS, NULL, NULL, 0);
1900   /* nghttp2_session_on_push_response_headers_received assumes
1901      stream's state is NGHTTP2_STREAM_RESERVED and session->server is
1902      0. */
1903
1904   user_data.begin_headers_cb_called = 0;
1905   user_data.invalid_frame_recv_cb_called = 0;
1906
1907   CU_ASSERT(0 == nghttp2_session_on_push_response_headers_received(
1908                      session, &frame, stream));
1909   CU_ASSERT(1 == user_data.begin_headers_cb_called);
1910   CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
1911   CU_ASSERT(1 == session->num_incoming_streams);
1912
1913   /* If un-ACKed max concurrent streams limit is exceeded,
1914      RST_STREAMed */
1915   session->pending_local_max_concurrent_stream = 1;
1916   stream = nghttp2_session_open_stream(session, 4, NGHTTP2_STREAM_FLAG_NONE,
1917                                        &pri_spec_default,
1918                                        NGHTTP2_STREAM_RESERVED, NULL);
1919   frame.hd.stream_id = 4;
1920   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
1921             nghttp2_session_on_push_response_headers_received(session, &frame,
1922                                                               stream));
1923   item = nghttp2_session_get_next_ob_item(session);
1924   CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
1925   CU_ASSERT(NGHTTP2_REFUSED_STREAM == item->frame.rst_stream.error_code);
1926   CU_ASSERT(1 == session->num_incoming_streams);
1927
1928   CU_ASSERT(0 == nghttp2_session_send(session));
1929   CU_ASSERT(1 == session->num_incoming_streams);
1930
1931   /* If ACKed max concurrent streams limit is exceeded, GOAWAY is
1932      issued */
1933   session->local_settings.max_concurrent_streams = 1;
1934
1935   stream = nghttp2_session_open_stream(session, 6, NGHTTP2_STREAM_FLAG_NONE,
1936                                        &pri_spec_default,
1937                                        NGHTTP2_STREAM_RESERVED, NULL);
1938   frame.hd.stream_id = 6;
1939
1940   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
1941             nghttp2_session_on_push_response_headers_received(session, &frame,
1942                                                               stream));
1943   item = nghttp2_session_get_next_ob_item(session);
1944   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
1945   CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == item->frame.goaway.error_code);
1946   CU_ASSERT(1 == session->num_incoming_streams);
1947
1948   nghttp2_frame_headers_free(&frame.headers, mem);
1949   nghttp2_session_del(session);
1950 }
1951
1952 void test_nghttp2_session_on_priority_received(void) {
1953   nghttp2_session *session;
1954   nghttp2_session_callbacks callbacks;
1955   my_user_data user_data;
1956   nghttp2_frame frame;
1957   nghttp2_stream *stream, *dep_stream;
1958   nghttp2_priority_spec pri_spec;
1959   nghttp2_outbound_item *item;
1960
1961   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
1962   callbacks.on_frame_recv_callback = on_frame_recv_callback;
1963   callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
1964
1965   nghttp2_session_server_new(&session, &callbacks, &user_data);
1966   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
1967                                        &pri_spec_default,
1968                                        NGHTTP2_STREAM_OPENING, NULL);
1969
1970   nghttp2_priority_spec_init(&pri_spec, 0, 2, 0);
1971
1972   nghttp2_frame_priority_init(&frame.priority, 1, &pri_spec);
1973
1974   /* depend on stream 0 */
1975   CU_ASSERT(0 == nghttp2_session_on_priority_received(session, &frame));
1976
1977   CU_ASSERT(2 == stream->weight);
1978
1979   stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
1980                                        &pri_spec_default,
1981                                        NGHTTP2_STREAM_OPENING, NULL);
1982
1983   dep_stream = nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE,
1984                                            &pri_spec_default,
1985                                            NGHTTP2_STREAM_OPENING, NULL);
1986
1987   frame.hd.stream_id = 2;
1988
1989   /* using dependency stream */
1990   nghttp2_priority_spec_init(&frame.priority.pri_spec, 3, 1, 0);
1991
1992   CU_ASSERT(0 == nghttp2_session_on_priority_received(session, &frame));
1993   CU_ASSERT(dep_stream == stream->dep_prev);
1994
1995   /* PRIORITY against idle stream */
1996
1997   frame.hd.stream_id = 100;
1998
1999   CU_ASSERT(0 == nghttp2_session_on_priority_received(session, &frame));
2000
2001   stream = nghttp2_session_get_stream_raw(session, frame.hd.stream_id);
2002
2003   CU_ASSERT(NGHTTP2_STREAM_IDLE == stream->state);
2004   CU_ASSERT(dep_stream == stream->dep_prev);
2005
2006   nghttp2_frame_priority_free(&frame.priority);
2007   nghttp2_session_del(session);
2008
2009   /* Check dep_stream_id == stream_id case */
2010   nghttp2_session_server_new(&session, &callbacks, &user_data);
2011   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
2012                               &pri_spec_default, NGHTTP2_STREAM_OPENED, NULL);
2013
2014   nghttp2_priority_spec_init(&pri_spec, 1, 0, 0);
2015
2016   nghttp2_frame_priority_init(&frame.priority, 1, &pri_spec);
2017
2018   CU_ASSERT(0 == nghttp2_session_on_priority_received(session, &frame));
2019
2020   item = nghttp2_session_get_next_ob_item(session);
2021
2022   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
2023
2024   nghttp2_frame_priority_free(&frame.priority);
2025   nghttp2_session_del(session);
2026 }
2027
2028 void test_nghttp2_session_on_rst_stream_received(void) {
2029   nghttp2_session *session;
2030   nghttp2_session_callbacks callbacks;
2031   my_user_data user_data;
2032   nghttp2_frame frame;
2033   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2034   nghttp2_session_server_new(&session, &callbacks, &user_data);
2035   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
2036                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
2037
2038   nghttp2_frame_rst_stream_init(&frame.rst_stream, 1, NGHTTP2_PROTOCOL_ERROR);
2039
2040   CU_ASSERT(0 == nghttp2_session_on_rst_stream_received(session, &frame));
2041   CU_ASSERT(NULL == nghttp2_session_get_stream(session, 1));
2042
2043   nghttp2_frame_rst_stream_free(&frame.rst_stream);
2044   nghttp2_session_del(session);
2045 }
2046
2047 void test_nghttp2_session_on_settings_received(void) {
2048   nghttp2_session *session;
2049   nghttp2_session_callbacks callbacks;
2050   my_user_data user_data;
2051   nghttp2_stream *stream1, *stream2;
2052   nghttp2_frame frame;
2053   const size_t niv = 5;
2054   nghttp2_settings_entry iv[255];
2055   nghttp2_outbound_item *item;
2056   nghttp2_nv nv = MAKE_NV(":authority", "example.org");
2057   nghttp2_mem *mem;
2058
2059   mem = nghttp2_mem_default();
2060
2061   iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
2062   iv[0].value = 50;
2063
2064   iv[1].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
2065   iv[1].value = 1000000009;
2066
2067   iv[2].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
2068   iv[2].value = 64 * 1024;
2069
2070   iv[3].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
2071   iv[3].value = 1024;
2072
2073   iv[4].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
2074   iv[4].value = 0;
2075
2076   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2077   callbacks.send_callback = null_send_callback;
2078
2079   nghttp2_session_client_new(&session, &callbacks, &user_data);
2080   session->remote_settings.initial_window_size = 16 * 1024;
2081
2082   stream1 = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
2083                                         &pri_spec_default,
2084                                         NGHTTP2_STREAM_OPENING, NULL);
2085   stream2 = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
2086                                         &pri_spec_default,
2087                                         NGHTTP2_STREAM_OPENING, NULL);
2088   /* Set window size for each streams and will see how settings
2089      updates these values */
2090   stream1->remote_window_size = 16 * 1024;
2091   stream2->remote_window_size = -48 * 1024;
2092
2093   nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE,
2094                               dup_iv(iv, niv), niv);
2095
2096   CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &frame, 0));
2097   CU_ASSERT(1000000009 == session->remote_settings.max_concurrent_streams);
2098   CU_ASSERT(64 * 1024 == session->remote_settings.initial_window_size);
2099   CU_ASSERT(1024 == session->remote_settings.header_table_size);
2100   CU_ASSERT(0 == session->remote_settings.enable_push);
2101
2102   CU_ASSERT(64 * 1024 == stream1->remote_window_size);
2103   CU_ASSERT(0 == stream2->remote_window_size);
2104
2105   frame.settings.iv[2].value = 16 * 1024;
2106
2107   CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &frame, 0));
2108
2109   CU_ASSERT(16 * 1024 == stream1->remote_window_size);
2110   CU_ASSERT(-48 * 1024 == stream2->remote_window_size);
2111
2112   CU_ASSERT(16 * 1024 == nghttp2_session_get_stream_remote_window_size(
2113                              session, stream1->stream_id));
2114   CU_ASSERT(0 == nghttp2_session_get_stream_remote_window_size(
2115                      session, stream2->stream_id));
2116
2117   nghttp2_frame_settings_free(&frame.settings, mem);
2118
2119   nghttp2_session_del(session);
2120
2121   /* Check ACK with niv > 0 */
2122   nghttp2_session_server_new(&session, &callbacks, NULL);
2123   nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_ACK, dup_iv(iv, 1),
2124                               1);
2125   /* Specify inflight_iv deliberately */
2126   session->inflight_iv = frame.settings.iv;
2127   session->inflight_niv = frame.settings.niv;
2128
2129   CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &frame, 0));
2130   item = nghttp2_session_get_next_ob_item(session);
2131   CU_ASSERT(item != NULL);
2132   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
2133
2134   session->inflight_iv = NULL;
2135   session->inflight_niv = -1;
2136
2137   nghttp2_frame_settings_free(&frame.settings, mem);
2138   nghttp2_session_del(session);
2139
2140   /* Check ACK against no inflight SETTINGS */
2141   nghttp2_session_server_new(&session, &callbacks, NULL);
2142   nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_ACK, NULL, 0);
2143
2144   CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &frame, 0));
2145   item = nghttp2_session_get_next_ob_item(session);
2146   CU_ASSERT(item != NULL);
2147   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
2148
2149   nghttp2_frame_settings_free(&frame.settings, mem);
2150   nghttp2_session_del(session);
2151
2152   /* Check that 2 SETTINGS_HEADER_TABLE_SIZE 0 and 4096 are included
2153      and header table size is once cleared to 0. */
2154   nghttp2_session_client_new(&session, &callbacks, NULL);
2155
2156   nghttp2_submit_request(session, NULL, &nv, 1, NULL, NULL);
2157
2158   nghttp2_session_send(session);
2159
2160   CU_ASSERT(session->hd_deflater.ctx.hd_table.len > 0);
2161
2162   iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
2163   iv[0].value = 0;
2164
2165   iv[1].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
2166   iv[1].value = 2048;
2167
2168   nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE, dup_iv(iv, 2),
2169                               2);
2170
2171   CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &frame, 0));
2172
2173   CU_ASSERT(0 == session->hd_deflater.ctx.hd_table.len);
2174   CU_ASSERT(2048 == session->hd_deflater.ctx.hd_table_bufsize_max);
2175   CU_ASSERT(2048 == session->remote_settings.header_table_size);
2176
2177   nghttp2_frame_settings_free(&frame.settings, mem);
2178   nghttp2_session_del(session);
2179
2180   /* Check too large SETTINGS_MAX_FRAME_SIZE */
2181   nghttp2_session_server_new(&session, &callbacks, NULL);
2182
2183   iv[0].settings_id = NGHTTP2_SETTINGS_MAX_FRAME_SIZE;
2184   iv[0].value = NGHTTP2_MAX_FRAME_SIZE_MAX + 1;
2185
2186   nghttp2_frame_settings_init(&frame.settings, NGHTTP2_FLAG_NONE, dup_iv(iv, 1),
2187                               1);
2188
2189   CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &frame, 0));
2190
2191   item = nghttp2_session_get_next_ob_item(session);
2192
2193   CU_ASSERT(item != NULL);
2194   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
2195
2196   nghttp2_frame_settings_free(&frame.settings, mem);
2197   nghttp2_session_del(session);
2198 }
2199
2200 void test_nghttp2_session_on_push_promise_received(void) {
2201   nghttp2_session *session;
2202   nghttp2_session_callbacks callbacks;
2203   my_user_data user_data;
2204   nghttp2_frame frame;
2205   nghttp2_stream *stream, *promised_stream;
2206   nghttp2_outbound_item *item;
2207   nghttp2_nv malformed_nva[] = {MAKE_NV(":path", "\x01")};
2208   nghttp2_nv *nva;
2209   size_t nvlen;
2210   nghttp2_mem *mem;
2211
2212   mem = nghttp2_mem_default();
2213   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2214   callbacks.send_callback = null_send_callback;
2215   callbacks.on_begin_headers_callback = on_begin_headers_callback;
2216   callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
2217
2218   nghttp2_session_client_new(&session, &callbacks, &user_data);
2219
2220   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
2221                                        &pri_spec_default,
2222                                        NGHTTP2_STREAM_OPENING, NULL);
2223   nghttp2_frame_push_promise_init(&frame.push_promise, NGHTTP2_FLAG_END_HEADERS,
2224                                   1, 2, NULL, 0);
2225
2226   user_data.begin_headers_cb_called = 0;
2227   user_data.invalid_frame_recv_cb_called = 0;
2228
2229   CU_ASSERT(0 == nghttp2_session_on_push_promise_received(session, &frame));
2230
2231   CU_ASSERT(1 == user_data.begin_headers_cb_called);
2232   promised_stream = nghttp2_session_get_stream(session, 2);
2233   CU_ASSERT(NGHTTP2_STREAM_RESERVED == promised_stream->state);
2234   CU_ASSERT(2 == session->last_recv_stream_id);
2235
2236   /* Attempt to PUSH_PROMISE against half close (remote) */
2237   nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_RD);
2238   frame.push_promise.promised_stream_id = 4;
2239
2240   user_data.begin_headers_cb_called = 0;
2241   user_data.invalid_frame_recv_cb_called = 0;
2242   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
2243             nghttp2_session_on_push_promise_received(session, &frame));
2244
2245   CU_ASSERT(0 == user_data.begin_headers_cb_called);
2246   CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
2247   CU_ASSERT(NULL == nghttp2_session_get_stream(session, 4));
2248   item = nghttp2_session_get_next_ob_item(session);
2249   CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
2250   CU_ASSERT(4 == item->frame.hd.stream_id);
2251   CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == item->frame.rst_stream.error_code);
2252   CU_ASSERT(0 == nghttp2_session_send(session));
2253   CU_ASSERT(4 == session->last_recv_stream_id);
2254
2255   /* Attempt to PUSH_PROMISE against stream in closing state */
2256   stream->shut_flags = NGHTTP2_SHUT_NONE;
2257   stream->state = NGHTTP2_STREAM_CLOSING;
2258   frame.push_promise.promised_stream_id = 6;
2259
2260   user_data.begin_headers_cb_called = 0;
2261   user_data.invalid_frame_recv_cb_called = 0;
2262   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
2263             nghttp2_session_on_push_promise_received(session, &frame));
2264
2265   CU_ASSERT(0 == user_data.begin_headers_cb_called);
2266   CU_ASSERT(NULL == nghttp2_session_get_stream(session, 6));
2267   item = nghttp2_session_get_next_ob_item(session);
2268   CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
2269   CU_ASSERT(6 == item->frame.hd.stream_id);
2270   CU_ASSERT(NGHTTP2_REFUSED_STREAM == item->frame.rst_stream.error_code);
2271   CU_ASSERT(0 == nghttp2_session_send(session));
2272
2273   /* Attempt to PUSH_PROMISE against non-existent stream */
2274   frame.hd.stream_id = 3;
2275   frame.push_promise.promised_stream_id = 8;
2276
2277   user_data.begin_headers_cb_called = 0;
2278   user_data.invalid_frame_recv_cb_called = 0;
2279   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
2280             nghttp2_session_on_push_promise_received(session, &frame));
2281
2282   CU_ASSERT(0 == user_data.begin_headers_cb_called);
2283   CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8));
2284   item = nghttp2_session_get_next_ob_item(session);
2285   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
2286   CU_ASSERT(0 == item->frame.hd.stream_id);
2287   CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == item->frame.goaway.error_code);
2288   CU_ASSERT(0 == nghttp2_session_send(session));
2289
2290   nghttp2_session_del(session);
2291
2292   nghttp2_session_client_new(&session, &callbacks, &user_data);
2293
2294   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
2295                                        &pri_spec_default,
2296                                        NGHTTP2_STREAM_OPENING, NULL);
2297
2298   /* Same ID twice */
2299   stream->state = NGHTTP2_STREAM_OPENING;
2300
2301   user_data.begin_headers_cb_called = 0;
2302   user_data.invalid_frame_recv_cb_called = 0;
2303   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
2304             nghttp2_session_on_push_promise_received(session, &frame));
2305
2306   CU_ASSERT(0 == user_data.begin_headers_cb_called);
2307   CU_ASSERT(NULL == nghttp2_session_get_stream(session, 8));
2308   item = nghttp2_session_get_next_ob_item(session);
2309   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
2310   CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == item->frame.goaway.error_code);
2311   CU_ASSERT(0 == nghttp2_session_send(session));
2312
2313   /* After GOAWAY, PUSH_PROMISE will be discarded */
2314   frame.push_promise.promised_stream_id = 10;
2315
2316   user_data.begin_headers_cb_called = 0;
2317   user_data.invalid_frame_recv_cb_called = 0;
2318   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
2319             nghttp2_session_on_push_promise_received(session, &frame));
2320
2321   CU_ASSERT(0 == user_data.begin_headers_cb_called);
2322   CU_ASSERT(NULL == nghttp2_session_get_stream(session, 10));
2323   CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
2324
2325   nghttp2_frame_push_promise_free(&frame.push_promise, mem);
2326   nghttp2_session_del(session);
2327
2328   nghttp2_session_client_new(&session, &callbacks, &user_data);
2329
2330   stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
2331                                        &pri_spec_default,
2332                                        NGHTTP2_STREAM_RESERVED, NULL);
2333   /* Attempt to PUSH_PROMISE against reserved (remote) stream */
2334   nghttp2_frame_push_promise_init(&frame.push_promise, NGHTTP2_FLAG_END_HEADERS,
2335                                   2, 4, NULL, 0);
2336
2337   user_data.begin_headers_cb_called = 0;
2338   user_data.invalid_frame_recv_cb_called = 0;
2339   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
2340             nghttp2_session_on_push_promise_received(session, &frame));
2341
2342   CU_ASSERT(0 == user_data.begin_headers_cb_called);
2343   CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
2344
2345   nghttp2_frame_push_promise_free(&frame.push_promise, mem);
2346   nghttp2_session_del(session);
2347
2348   /* Disable PUSH */
2349   nghttp2_session_client_new(&session, &callbacks, &user_data);
2350
2351   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
2352                                        &pri_spec_default,
2353                                        NGHTTP2_STREAM_OPENING, NULL);
2354
2355   session->local_settings.enable_push = 0;
2356
2357   nghttp2_frame_push_promise_init(&frame.push_promise, NGHTTP2_FLAG_END_HEADERS,
2358                                   1, 2, NULL, 0);
2359
2360   user_data.begin_headers_cb_called = 0;
2361   user_data.invalid_frame_recv_cb_called = 0;
2362   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
2363             nghttp2_session_on_push_promise_received(session, &frame));
2364
2365   CU_ASSERT(0 == user_data.begin_headers_cb_called);
2366   CU_ASSERT(1 == user_data.invalid_frame_recv_cb_called);
2367
2368   nghttp2_frame_push_promise_free(&frame.push_promise, mem);
2369   nghttp2_session_del(session);
2370
2371   /* Check malformed headers. We accept malformed headers */
2372   nghttp2_session_client_new(&session, &callbacks, &user_data);
2373
2374   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
2375                                        &pri_spec_default,
2376                                        NGHTTP2_STREAM_OPENING, NULL);
2377   nvlen = ARRLEN(malformed_nva);
2378   nghttp2_nv_array_copy(&nva, malformed_nva, nvlen, mem);
2379   nghttp2_frame_push_promise_init(&frame.push_promise, NGHTTP2_FLAG_END_HEADERS,
2380                                   1, 2, nva, nvlen);
2381   user_data.begin_headers_cb_called = 0;
2382   user_data.invalid_frame_recv_cb_called = 0;
2383   CU_ASSERT(0 == nghttp2_session_on_push_promise_received(session, &frame));
2384
2385   CU_ASSERT(1 == user_data.begin_headers_cb_called);
2386   CU_ASSERT(0 == user_data.invalid_frame_recv_cb_called);
2387
2388   nghttp2_frame_push_promise_free(&frame.push_promise, mem);
2389   nghttp2_session_del(session);
2390 }
2391
2392 void test_nghttp2_session_on_ping_received(void) {
2393   nghttp2_session *session;
2394   nghttp2_session_callbacks callbacks;
2395   my_user_data user_data;
2396   nghttp2_frame frame;
2397   nghttp2_outbound_item *top;
2398   const uint8_t opaque_data[] = "01234567";
2399
2400   user_data.frame_recv_cb_called = 0;
2401   user_data.invalid_frame_recv_cb_called = 0;
2402
2403   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2404   callbacks.on_frame_recv_callback = on_frame_recv_callback;
2405   callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
2406
2407   nghttp2_session_client_new(&session, &callbacks, &user_data);
2408   nghttp2_frame_ping_init(&frame.ping, NGHTTP2_FLAG_ACK, opaque_data);
2409
2410   CU_ASSERT(0 == nghttp2_session_on_ping_received(session, &frame));
2411   CU_ASSERT(1 == user_data.frame_recv_cb_called);
2412
2413   /* Since this ping frame has PONG flag set, no further action is
2414      performed. */
2415   CU_ASSERT(NULL == nghttp2_session_get_ob_pq_top(session));
2416
2417   /* Clear the flag, and receive it again */
2418   frame.hd.flags = NGHTTP2_FLAG_NONE;
2419
2420   CU_ASSERT(0 == nghttp2_session_on_ping_received(session, &frame));
2421   CU_ASSERT(2 == user_data.frame_recv_cb_called);
2422   top = nghttp2_session_get_ob_pq_top(session);
2423   CU_ASSERT(NGHTTP2_PING == top->frame.hd.type);
2424   CU_ASSERT(NGHTTP2_FLAG_ACK == top->frame.hd.flags);
2425   CU_ASSERT(memcmp(opaque_data, top->frame.ping.opaque_data, 8) == 0);
2426
2427   nghttp2_frame_ping_free(&frame.ping);
2428   nghttp2_session_del(session);
2429 }
2430
2431 void test_nghttp2_session_on_goaway_received(void) {
2432   nghttp2_session *session;
2433   nghttp2_session_callbacks callbacks;
2434   my_user_data user_data;
2435   nghttp2_frame frame;
2436   int i;
2437   nghttp2_mem *mem;
2438
2439   mem = nghttp2_mem_default();
2440   user_data.frame_recv_cb_called = 0;
2441   user_data.invalid_frame_recv_cb_called = 0;
2442
2443   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2444   callbacks.on_frame_recv_callback = on_frame_recv_callback;
2445   callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
2446   callbacks.on_stream_close_callback = on_stream_close_callback;
2447
2448   nghttp2_session_client_new(&session, &callbacks, &user_data);
2449
2450   for (i = 1; i <= 7; ++i) {
2451     open_stream(session, i);
2452   }
2453
2454   nghttp2_frame_goaway_init(&frame.goaway, 3, NGHTTP2_PROTOCOL_ERROR, NULL, 0);
2455
2456   user_data.stream_close_cb_called = 0;
2457
2458   CU_ASSERT(0 == nghttp2_session_on_goaway_received(session, &frame));
2459
2460   CU_ASSERT(1 == user_data.frame_recv_cb_called);
2461   CU_ASSERT(3 == session->remote_last_stream_id);
2462   /* on_stream_close should be callsed for 2 times (stream 5 and 7) */
2463   CU_ASSERT(2 == user_data.stream_close_cb_called);
2464
2465   CU_ASSERT(NULL != nghttp2_session_get_stream(session, 1));
2466   CU_ASSERT(NULL != nghttp2_session_get_stream(session, 2));
2467   CU_ASSERT(NULL != nghttp2_session_get_stream(session, 3));
2468   CU_ASSERT(NULL != nghttp2_session_get_stream(session, 4));
2469   CU_ASSERT(NULL == nghttp2_session_get_stream(session, 5));
2470   CU_ASSERT(NULL != nghttp2_session_get_stream(session, 6));
2471   CU_ASSERT(NULL == nghttp2_session_get_stream(session, 7));
2472
2473   nghttp2_frame_goaway_free(&frame.goaway, mem);
2474   nghttp2_session_del(session);
2475 }
2476
2477 void test_nghttp2_session_on_window_update_received(void) {
2478   nghttp2_session *session;
2479   nghttp2_session_callbacks callbacks;
2480   my_user_data user_data;
2481   nghttp2_frame frame;
2482   nghttp2_stream *stream;
2483   nghttp2_outbound_item *data_item;
2484   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2485   callbacks.on_frame_recv_callback = on_frame_recv_callback;
2486   callbacks.on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
2487   user_data.frame_recv_cb_called = 0;
2488   user_data.invalid_frame_recv_cb_called = 0;
2489
2490   nghttp2_session_client_new(&session, &callbacks, &user_data);
2491
2492   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
2493                                        &pri_spec_default, NGHTTP2_STREAM_OPENED,
2494                                        NULL);
2495
2496   data_item = create_data_ob_item();
2497
2498   CU_ASSERT(0 == nghttp2_stream_attach_item(stream, data_item, session));
2499
2500   nghttp2_frame_window_update_init(&frame.window_update, NGHTTP2_FLAG_NONE, 1,
2501                                    16 * 1024);
2502
2503   CU_ASSERT(0 == nghttp2_session_on_window_update_received(session, &frame));
2504   CU_ASSERT(1 == user_data.frame_recv_cb_called);
2505   CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE + 16 * 1024 ==
2506             stream->remote_window_size);
2507
2508   CU_ASSERT(0 ==
2509             nghttp2_stream_defer_item(
2510                 stream, NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL, session));
2511
2512   CU_ASSERT(0 == nghttp2_session_on_window_update_received(session, &frame));
2513   CU_ASSERT(2 == user_data.frame_recv_cb_called);
2514   CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE + 16 * 1024 * 2 ==
2515             stream->remote_window_size);
2516   CU_ASSERT(0 == (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL));
2517
2518   nghttp2_frame_window_update_free(&frame.window_update);
2519
2520   /* Receiving WINDOW_UPDATE on reserved (remote) stream is a
2521      connection error */
2522   stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
2523                                        &pri_spec_default,
2524                                        NGHTTP2_STREAM_RESERVED, NULL);
2525
2526   nghttp2_frame_window_update_init(&frame.window_update, NGHTTP2_FLAG_NONE, 2,
2527                                    4096);
2528
2529   CU_ASSERT(!(session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND));
2530   CU_ASSERT(0 == nghttp2_session_on_window_update_received(session, &frame));
2531   CU_ASSERT(session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND);
2532
2533   nghttp2_frame_window_update_free(&frame.window_update);
2534
2535   nghttp2_session_del(session);
2536
2537   /* Receiving WINDOW_UPDATE on reserved (local) stream is allowed */
2538   nghttp2_session_server_new(&session, &callbacks, &user_data);
2539
2540   stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
2541                                        &pri_spec_default,
2542                                        NGHTTP2_STREAM_RESERVED, NULL);
2543
2544   nghttp2_frame_window_update_init(&frame.window_update, NGHTTP2_FLAG_NONE, 2,
2545                                    4096);
2546
2547   CU_ASSERT(0 == nghttp2_session_on_window_update_received(session, &frame));
2548   CU_ASSERT(!(session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND));
2549
2550   CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE + 4096 == stream->remote_window_size);
2551
2552   nghttp2_frame_window_update_free(&frame.window_update);
2553
2554   nghttp2_session_del(session);
2555 }
2556
2557 void test_nghttp2_session_on_data_received(void) {
2558   nghttp2_session *session;
2559   nghttp2_session_callbacks callbacks;
2560   my_user_data user_data;
2561   nghttp2_outbound_item *top;
2562   nghttp2_stream *stream;
2563   nghttp2_frame frame;
2564
2565   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2566
2567   nghttp2_session_client_new(&session, &callbacks, &user_data);
2568   stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
2569                                        &pri_spec_default,
2570                                        NGHTTP2_STREAM_OPENING, NULL);
2571
2572   nghttp2_frame_hd_init(&frame.hd, 4096, NGHTTP2_DATA, NGHTTP2_FLAG_NONE, 2);
2573
2574   CU_ASSERT(0 == nghttp2_session_on_data_received(session, &frame));
2575   CU_ASSERT(0 == stream->shut_flags);
2576
2577   frame.hd.flags = NGHTTP2_FLAG_END_STREAM;
2578
2579   CU_ASSERT(0 == nghttp2_session_on_data_received(session, &frame));
2580   CU_ASSERT(NGHTTP2_SHUT_RD == stream->shut_flags);
2581
2582   /* If NGHTTP2_STREAM_CLOSING state, DATA frame is discarded. */
2583   stream = nghttp2_session_open_stream(session, 4, NGHTTP2_STREAM_FLAG_NONE,
2584                                        &pri_spec_default,
2585                                        NGHTTP2_STREAM_CLOSING, NULL);
2586
2587   frame.hd.flags = NGHTTP2_FLAG_NONE;
2588   frame.hd.stream_id = 4;
2589
2590   CU_ASSERT(0 == nghttp2_session_on_data_received(session, &frame));
2591   CU_ASSERT(NULL == nghttp2_session_get_ob_pq_top(session));
2592
2593   /* Check INVALID_STREAM case: DATA frame with stream ID which does
2594      not exist. */
2595
2596   frame.hd.stream_id = 6;
2597
2598   CU_ASSERT(0 == nghttp2_session_on_data_received(session, &frame));
2599   top = nghttp2_session_get_ob_pq_top(session);
2600   /* DATA against nonexistent stream is just ignored for now */
2601   CU_ASSERT(top == NULL);
2602   /* CU_ASSERT(NGHTTP2_RST_STREAM == top->frame.hd.type); */
2603   /* CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == top->frame.rst_stream.error_code); */
2604
2605   nghttp2_session_del(session);
2606 }
2607
2608 void test_nghttp2_session_send_headers_start_stream(void) {
2609   nghttp2_session *session;
2610   nghttp2_session_callbacks callbacks;
2611   nghttp2_outbound_item *item;
2612   nghttp2_frame *frame;
2613   nghttp2_stream *stream;
2614
2615   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2616   callbacks.send_callback = null_send_callback;
2617
2618   nghttp2_session_client_new(&session, &callbacks, NULL);
2619
2620   item = malloc(sizeof(nghttp2_outbound_item));
2621
2622   nghttp2_session_outbound_item_init(session, item);
2623
2624   frame = &item->frame;
2625
2626   nghttp2_frame_headers_init(&frame->headers, NGHTTP2_FLAG_END_HEADERS,
2627                              session->next_stream_id, NGHTTP2_HCAT_REQUEST,
2628                              NULL, NULL, 0);
2629   session->next_stream_id += 2;
2630
2631   nghttp2_session_add_item(session, item);
2632   CU_ASSERT(0 == nghttp2_session_send(session));
2633   stream = nghttp2_session_get_stream(session, 1);
2634   CU_ASSERT(NGHTTP2_STREAM_OPENING == stream->state);
2635
2636   nghttp2_session_del(session);
2637 }
2638
2639 void test_nghttp2_session_send_headers_reply(void) {
2640   nghttp2_session *session;
2641   nghttp2_session_callbacks callbacks;
2642   nghttp2_outbound_item *item;
2643   nghttp2_frame *frame;
2644   nghttp2_stream *stream;
2645
2646   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2647   callbacks.send_callback = null_send_callback;
2648
2649   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, NULL));
2650   nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
2651                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
2652
2653   item = malloc(sizeof(nghttp2_outbound_item));
2654
2655   nghttp2_session_outbound_item_init(session, item);
2656
2657   frame = &item->frame;
2658
2659   nghttp2_frame_headers_init(&frame->headers, NGHTTP2_FLAG_END_HEADERS, 2,
2660                              NGHTTP2_HCAT_HEADERS, NULL, NULL, 0);
2661   nghttp2_session_add_item(session, item);
2662   CU_ASSERT(0 == nghttp2_session_send(session));
2663   stream = nghttp2_session_get_stream(session, 2);
2664   CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
2665
2666   nghttp2_session_del(session);
2667 }
2668
2669 void test_nghttp2_session_send_headers_frame_size_error(void) {
2670   nghttp2_session *session;
2671   nghttp2_session_callbacks callbacks;
2672   nghttp2_outbound_item *item;
2673   nghttp2_frame *frame;
2674   nghttp2_nv *nva;
2675   ssize_t nvlen;
2676   size_t vallen = NGHTTP2_HD_MAX_NV;
2677   nghttp2_nv nv[28];
2678   size_t nnv = ARRLEN(nv);
2679   size_t i;
2680   my_user_data ud;
2681   nghttp2_mem *mem;
2682
2683   mem = nghttp2_mem_default();
2684
2685   for (i = 0; i < nnv; ++i) {
2686     nv[i].name = (uint8_t *)"header";
2687     nv[i].namelen = strlen((const char *)nv[i].name);
2688     nv[i].value = malloc(vallen + 1);
2689     memset(nv[i].value, '0' + (int)i, vallen);
2690     nv[i].value[vallen] = '\0';
2691     nv[i].valuelen = vallen;
2692     nv[i].flags = NGHTTP2_NV_FLAG_NONE;
2693   }
2694
2695   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2696   callbacks.send_callback = null_send_callback;
2697   callbacks.on_frame_not_send_callback = on_frame_not_send_callback;
2698
2699   nghttp2_session_client_new(&session, &callbacks, &ud);
2700   nvlen = nnv;
2701   nghttp2_nv_array_copy(&nva, nv, nvlen, mem);
2702
2703   item = malloc(sizeof(nghttp2_outbound_item));
2704
2705   nghttp2_session_outbound_item_init(session, item);
2706
2707   frame = &item->frame;
2708
2709   nghttp2_frame_headers_init(&frame->headers, NGHTTP2_FLAG_END_HEADERS,
2710                              session->next_stream_id, NGHTTP2_HCAT_REQUEST,
2711                              NULL, nva, nvlen);
2712
2713   session->next_stream_id += 2;
2714
2715   nghttp2_session_add_item(session, item);
2716
2717   ud.frame_not_send_cb_called = 0;
2718
2719   CU_ASSERT(0 == nghttp2_session_send(session));
2720
2721   CU_ASSERT(1 == ud.frame_not_send_cb_called);
2722   CU_ASSERT(NGHTTP2_HEADERS == ud.not_sent_frame_type);
2723   CU_ASSERT(NGHTTP2_ERR_FRAME_SIZE_ERROR == ud.not_sent_error);
2724
2725   for (i = 0; i < nnv; ++i) {
2726     free(nv[i].value);
2727   }
2728   nghttp2_session_del(session);
2729 }
2730
2731 void test_nghttp2_session_send_headers_push_reply(void) {
2732   nghttp2_session *session;
2733   nghttp2_session_callbacks callbacks;
2734   nghttp2_outbound_item *item;
2735   nghttp2_frame *frame;
2736   nghttp2_stream *stream;
2737
2738   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2739   callbacks.send_callback = null_send_callback;
2740
2741   CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, NULL));
2742   nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
2743                               &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL);
2744
2745   item = malloc(sizeof(nghttp2_outbound_item));
2746
2747   nghttp2_session_outbound_item_init(session, item);
2748
2749   frame = &item->frame;
2750
2751   nghttp2_frame_headers_init(&frame->headers, NGHTTP2_FLAG_END_HEADERS, 2,
2752                              NGHTTP2_HCAT_HEADERS, NULL, NULL, 0);
2753   nghttp2_session_add_item(session, item);
2754   CU_ASSERT(0 == session->num_outgoing_streams);
2755   CU_ASSERT(0 == nghttp2_session_send(session));
2756   CU_ASSERT(1 == session->num_outgoing_streams);
2757   stream = nghttp2_session_get_stream(session, 2);
2758   CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
2759
2760   nghttp2_session_del(session);
2761 }
2762
2763 void test_nghttp2_session_send_rst_stream(void) {
2764   nghttp2_session *session;
2765   nghttp2_session_callbacks callbacks;
2766   my_user_data user_data;
2767   nghttp2_outbound_item *item;
2768   nghttp2_frame *frame;
2769
2770   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2771   callbacks.send_callback = null_send_callback;
2772   nghttp2_session_client_new(&session, &callbacks, &user_data);
2773   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
2774                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
2775
2776   item = malloc(sizeof(nghttp2_outbound_item));
2777
2778   nghttp2_session_outbound_item_init(session, item);
2779
2780   frame = &item->frame;
2781
2782   nghttp2_frame_rst_stream_init(&frame->rst_stream, 1, NGHTTP2_PROTOCOL_ERROR);
2783   nghttp2_session_add_item(session, item);
2784   CU_ASSERT(0 == nghttp2_session_send(session));
2785
2786   CU_ASSERT(NULL == nghttp2_session_get_stream(session, 1));
2787
2788   nghttp2_session_del(session);
2789 }
2790
2791 void test_nghttp2_session_send_push_promise(void) {
2792   nghttp2_session *session;
2793   nghttp2_session_callbacks callbacks;
2794   nghttp2_outbound_item *item;
2795   nghttp2_frame *frame;
2796   nghttp2_stream *stream;
2797   nghttp2_settings_entry iv;
2798   my_user_data ud;
2799   nghttp2_mem *mem;
2800
2801   mem = nghttp2_mem_default();
2802   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2803   callbacks.send_callback = null_send_callback;
2804   callbacks.on_frame_not_send_callback = on_frame_not_send_callback;
2805
2806   nghttp2_session_server_new(&session, &callbacks, &ud);
2807   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
2808                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
2809
2810   item = malloc(sizeof(nghttp2_outbound_item));
2811
2812   nghttp2_session_outbound_item_init(session, item);
2813
2814   frame = &item->frame;
2815
2816   nghttp2_frame_push_promise_init(&frame->push_promise,
2817                                   NGHTTP2_FLAG_END_HEADERS, 1,
2818                                   session->next_stream_id, NULL, 0);
2819
2820   session->next_stream_id += 2;
2821
2822   nghttp2_session_add_item(session, item);
2823
2824   CU_ASSERT(0 == nghttp2_session_send(session));
2825   stream = nghttp2_session_get_stream(session, 2);
2826   CU_ASSERT(NGHTTP2_STREAM_RESERVED == stream->state);
2827
2828   /* Received ENABLE_PUSH = 0 */
2829   iv.settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
2830   iv.value = 0;
2831   frame = malloc(sizeof(nghttp2_frame));
2832   nghttp2_frame_settings_init(&frame->settings, NGHTTP2_FLAG_NONE,
2833                               dup_iv(&iv, 1), 1);
2834   nghttp2_session_on_settings_received(session, frame, 1);
2835   nghttp2_frame_settings_free(&frame->settings, mem);
2836   free(frame);
2837
2838   item = malloc(sizeof(nghttp2_outbound_item));
2839
2840   nghttp2_session_outbound_item_init(session, item);
2841
2842   frame = &item->frame;
2843
2844   nghttp2_frame_push_promise_init(&frame->push_promise,
2845                                   NGHTTP2_FLAG_END_HEADERS, 1, -1, NULL, 0);
2846   nghttp2_session_add_item(session, item);
2847
2848   ud.frame_not_send_cb_called = 0;
2849   CU_ASSERT(0 == nghttp2_session_send(session));
2850
2851   CU_ASSERT(1 == ud.frame_not_send_cb_called);
2852   CU_ASSERT(NGHTTP2_PUSH_PROMISE == ud.not_sent_frame_type);
2853   CU_ASSERT(NGHTTP2_ERR_PUSH_DISABLED == ud.not_sent_error);
2854
2855   nghttp2_session_del(session);
2856
2857   /* PUSH_PROMISE from client is error */
2858   nghttp2_session_client_new(&session, &callbacks, &ud);
2859   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
2860                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
2861   item = malloc(sizeof(nghttp2_outbound_item));
2862
2863   nghttp2_session_outbound_item_init(session, item);
2864
2865   frame = &item->frame;
2866
2867   nghttp2_frame_push_promise_init(&frame->push_promise,
2868                                   NGHTTP2_FLAG_END_HEADERS, 1, -1, NULL, 0);
2869   nghttp2_session_add_item(session, item);
2870
2871   CU_ASSERT(0 == nghttp2_session_send(session));
2872   CU_ASSERT(NULL == nghttp2_session_get_stream(session, 3));
2873
2874   nghttp2_session_del(session);
2875 }
2876
2877 void test_nghttp2_session_is_my_stream_id(void) {
2878   nghttp2_session *session;
2879   nghttp2_session_callbacks callbacks;
2880   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2881   nghttp2_session_server_new(&session, &callbacks, NULL);
2882
2883   CU_ASSERT(0 == nghttp2_session_is_my_stream_id(session, 0));
2884   CU_ASSERT(0 == nghttp2_session_is_my_stream_id(session, 1));
2885   CU_ASSERT(1 == nghttp2_session_is_my_stream_id(session, 2));
2886
2887   nghttp2_session_del(session);
2888
2889   nghttp2_session_client_new(&session, &callbacks, NULL);
2890
2891   CU_ASSERT(0 == nghttp2_session_is_my_stream_id(session, 0));
2892   CU_ASSERT(1 == nghttp2_session_is_my_stream_id(session, 1));
2893   CU_ASSERT(0 == nghttp2_session_is_my_stream_id(session, 2));
2894
2895   nghttp2_session_del(session);
2896 }
2897
2898 void test_nghttp2_session_upgrade(void) {
2899   nghttp2_session *session;
2900   nghttp2_session_callbacks callbacks;
2901   uint8_t settings_payload[128];
2902   size_t settings_payloadlen;
2903   nghttp2_settings_entry iv[16];
2904   nghttp2_stream *stream;
2905   nghttp2_outbound_item *item;
2906
2907   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2908   callbacks.send_callback = null_send_callback;
2909   iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
2910   iv[0].value = 1;
2911   iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
2912   iv[1].value = 4095;
2913   settings_payloadlen = nghttp2_pack_settings_payload(
2914       settings_payload, sizeof(settings_payload), iv, 2);
2915
2916   /* Check client side */
2917   nghttp2_session_client_new(&session, &callbacks, NULL);
2918   CU_ASSERT(0 == nghttp2_session_upgrade(session, settings_payload,
2919                                          settings_payloadlen, &callbacks));
2920   stream = nghttp2_session_get_stream(session, 1);
2921   CU_ASSERT(stream != NULL);
2922   CU_ASSERT(&callbacks == stream->stream_user_data);
2923   CU_ASSERT(NGHTTP2_SHUT_WR == stream->shut_flags);
2924   item = nghttp2_session_get_next_ob_item(session);
2925   CU_ASSERT(NGHTTP2_SETTINGS == item->frame.hd.type);
2926   CU_ASSERT(2 == item->frame.settings.niv);
2927   CU_ASSERT(NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS ==
2928             item->frame.settings.iv[0].settings_id);
2929   CU_ASSERT(1 == item->frame.settings.iv[0].value);
2930   CU_ASSERT(NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE ==
2931             item->frame.settings.iv[1].settings_id);
2932   CU_ASSERT(4095 == item->frame.settings.iv[1].value);
2933
2934   /* Call nghttp2_session_upgrade() again is error */
2935   CU_ASSERT(NGHTTP2_ERR_PROTO ==
2936             nghttp2_session_upgrade(session, settings_payload,
2937                                     settings_payloadlen, &callbacks));
2938   nghttp2_session_del(session);
2939
2940   /* Check server side */
2941   nghttp2_session_server_new(&session, &callbacks, NULL);
2942   CU_ASSERT(0 == nghttp2_session_upgrade(session, settings_payload,
2943                                          settings_payloadlen, &callbacks));
2944   stream = nghttp2_session_get_stream(session, 1);
2945   CU_ASSERT(stream != NULL);
2946   CU_ASSERT(NULL == stream->stream_user_data);
2947   CU_ASSERT(NGHTTP2_SHUT_RD == stream->shut_flags);
2948   CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
2949   CU_ASSERT(1 == session->remote_settings.max_concurrent_streams);
2950   CU_ASSERT(4095 == session->remote_settings.initial_window_size);
2951   /* Call nghttp2_session_upgrade() again is error */
2952   CU_ASSERT(NGHTTP2_ERR_PROTO ==
2953             nghttp2_session_upgrade(session, settings_payload,
2954                                     settings_payloadlen, &callbacks));
2955   nghttp2_session_del(session);
2956
2957   /* Empty SETTINGS is OK */
2958   settings_payloadlen = nghttp2_pack_settings_payload(
2959       settings_payload, sizeof(settings_payload), NULL, 0);
2960
2961   nghttp2_session_client_new(&session, &callbacks, NULL);
2962   CU_ASSERT(0 == nghttp2_session_upgrade(session, settings_payload,
2963                                          settings_payloadlen, NULL));
2964   nghttp2_session_del(session);
2965 }
2966
2967 void test_nghttp2_session_reprioritize_stream(void) {
2968   nghttp2_session *session;
2969   nghttp2_session_callbacks callbacks;
2970   my_user_data ud;
2971   nghttp2_stream *stream;
2972   nghttp2_stream *dep_stream;
2973   nghttp2_priority_spec pri_spec;
2974
2975   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
2976   callbacks.send_callback = block_count_send_callback;
2977
2978   nghttp2_session_server_new(&session, &callbacks, &ud);
2979
2980   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
2981                                        &pri_spec_default,
2982                                        NGHTTP2_STREAM_OPENING, NULL);
2983
2984   nghttp2_priority_spec_init(&pri_spec, 0, 10, 0);
2985
2986   nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
2987
2988   CU_ASSERT(10 == stream->weight);
2989   CU_ASSERT(NULL == stream->dep_prev);
2990
2991   /* If depenency to idle stream which is not in depdenency tree yet */
2992
2993   nghttp2_priority_spec_init(&pri_spec, 3, 99, 0);
2994
2995   nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
2996
2997   CU_ASSERT(99 == stream->weight);
2998   CU_ASSERT(3 == stream->dep_prev->stream_id);
2999
3000   dep_stream = nghttp2_session_get_stream_raw(session, 3);
3001
3002   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == dep_stream->weight);
3003
3004   dep_stream = open_stream(session, 3);
3005
3006   /* Change weight */
3007   pri_spec.weight = 128;
3008
3009   nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
3010
3011   CU_ASSERT(128 == stream->weight);
3012   CU_ASSERT(dep_stream == stream->dep_prev);
3013
3014   /* Test circular dependency; stream 1 is first removed and becomes
3015      root.  Then stream 3 depends on it. */
3016   nghttp2_priority_spec_init(&pri_spec, 1, 1, 0);
3017
3018   nghttp2_session_reprioritize_stream(session, dep_stream, &pri_spec);
3019
3020   CU_ASSERT(1 == dep_stream->weight);
3021   CU_ASSERT(stream == dep_stream->dep_prev);
3022
3023   /* Making priority to closed stream will result in default
3024      priority */
3025   session->last_recv_stream_id = 9;
3026
3027   nghttp2_priority_spec_init(&pri_spec, 5, 5, 0);
3028
3029   nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
3030
3031   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight);
3032
3033   nghttp2_session_del(session);
3034 }
3035
3036 void test_nghttp2_session_reprioritize_stream_with_idle_stream_dep(void) {
3037   nghttp2_session *session;
3038   nghttp2_session_callbacks callbacks;
3039   nghttp2_stream *stream;
3040   nghttp2_priority_spec pri_spec;
3041
3042   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3043   callbacks.send_callback = block_count_send_callback;
3044
3045   nghttp2_session_server_new(&session, &callbacks, NULL);
3046
3047   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
3048                                        &pri_spec_default,
3049                                        NGHTTP2_STREAM_OPENING, NULL);
3050
3051   session->pending_local_max_concurrent_stream = 1;
3052
3053   nghttp2_priority_spec_init(&pri_spec, 101, 10, 0);
3054
3055   nghttp2_session_reprioritize_stream(session, stream, &pri_spec);
3056
3057   /* idle stream is not counteed to max concurrent streams */
3058
3059   CU_ASSERT(10 == stream->weight);
3060   CU_ASSERT(101 == stream->dep_prev->stream_id);
3061
3062   stream = nghttp2_session_get_stream_raw(session, 101);
3063
3064   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight);
3065
3066   nghttp2_session_del(session);
3067 }
3068
3069 void test_nghttp2_submit_data(void) {
3070   nghttp2_session *session;
3071   nghttp2_session_callbacks callbacks;
3072   nghttp2_data_provider data_prd;
3073   my_user_data ud;
3074   nghttp2_frame *frame;
3075   nghttp2_frame_hd hd;
3076   nghttp2_active_outbound_item *aob;
3077   nghttp2_bufs *framebufs;
3078   nghttp2_buf *buf;
3079
3080   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3081   callbacks.send_callback = block_count_send_callback;
3082
3083   data_prd.read_callback = fixed_length_data_source_read_callback;
3084   ud.data_source_length = NGHTTP2_DATA_PAYLOADLEN * 2;
3085   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
3086   aob = &session->aob;
3087   framebufs = &aob->framebufs;
3088
3089   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
3090                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
3091   CU_ASSERT(
3092       0 == nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM, 1, &data_prd));
3093
3094   ud.block_count = 0;
3095   CU_ASSERT(0 == nghttp2_session_send(session));
3096   frame = &aob->item->frame;
3097
3098   buf = &framebufs->head->buf;
3099   nghttp2_frame_unpack_frame_hd(&hd, buf->pos);
3100
3101   CU_ASSERT(NGHTTP2_FLAG_NONE == hd.flags);
3102   CU_ASSERT(NGHTTP2_FLAG_NONE == frame->hd.flags);
3103   /* aux_data.data.flags has these flags */
3104   CU_ASSERT(NGHTTP2_FLAG_END_STREAM == aob->item->aux_data.data.flags);
3105
3106   nghttp2_session_del(session);
3107 }
3108
3109 void test_nghttp2_submit_data_read_length_too_large(void) {
3110   nghttp2_session *session;
3111   nghttp2_session_callbacks callbacks;
3112   nghttp2_data_provider data_prd;
3113   my_user_data ud;
3114   nghttp2_frame *frame;
3115   nghttp2_frame_hd hd;
3116   nghttp2_active_outbound_item *aob;
3117   nghttp2_bufs *framebufs;
3118   nghttp2_buf *buf;
3119   size_t payloadlen;
3120
3121   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3122   callbacks.send_callback = block_count_send_callback;
3123   callbacks.read_length_callback = too_large_data_source_length_callback;
3124
3125   data_prd.read_callback = fixed_length_data_source_read_callback;
3126   ud.data_source_length = NGHTTP2_DATA_PAYLOADLEN * 2;
3127   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
3128   aob = &session->aob;
3129   framebufs = &aob->framebufs;
3130
3131   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
3132                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
3133   CU_ASSERT(
3134       0 == nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM, 1, &data_prd));
3135
3136   ud.block_count = 0;
3137   CU_ASSERT(0 == nghttp2_session_send(session));
3138   frame = &aob->item->frame;
3139
3140   buf = &framebufs->head->buf;
3141   nghttp2_frame_unpack_frame_hd(&hd, buf->pos);
3142
3143   CU_ASSERT(NGHTTP2_FLAG_NONE == hd.flags);
3144   CU_ASSERT(NGHTTP2_FLAG_NONE == frame->hd.flags);
3145   CU_ASSERT(16384 == hd.length)
3146   /* aux_data.data.flags has these flags */
3147   CU_ASSERT(NGHTTP2_FLAG_END_STREAM == aob->item->aux_data.data.flags);
3148
3149   nghttp2_session_del(session);
3150
3151   /* Check that buffers are expanded */
3152   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
3153
3154   ud.data_source_length = NGHTTP2_MAX_FRAME_SIZE_MAX;
3155
3156   session->remote_settings.max_frame_size = NGHTTP2_MAX_FRAME_SIZE_MAX;
3157
3158   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
3159                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
3160   CU_ASSERT(
3161       0 == nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM, 1, &data_prd));
3162
3163   ud.block_count = 0;
3164   CU_ASSERT(0 == nghttp2_session_send(session));
3165
3166   aob = &session->aob;
3167
3168   frame = &aob->item->frame;
3169
3170   framebufs = &aob->framebufs;
3171
3172   buf = &framebufs->head->buf;
3173   nghttp2_frame_unpack_frame_hd(&hd, buf->pos);
3174
3175   payloadlen = nghttp2_min(NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE,
3176                            NGHTTP2_INITIAL_WINDOW_SIZE);
3177
3178   CU_ASSERT(NGHTTP2_FRAME_HDLEN + 1 + payloadlen ==
3179             (size_t)nghttp2_buf_cap(buf));
3180   CU_ASSERT(NGHTTP2_FLAG_NONE == hd.flags);
3181   CU_ASSERT(NGHTTP2_FLAG_NONE == frame->hd.flags);
3182   CU_ASSERT(payloadlen == hd.length);
3183   /* aux_data.data.flags has these flags */
3184   CU_ASSERT(NGHTTP2_FLAG_END_STREAM == aob->item->aux_data.data.flags);
3185
3186   nghttp2_session_del(session);
3187 }
3188
3189 void test_nghttp2_submit_data_read_length_smallest(void) {
3190   nghttp2_session *session;
3191   nghttp2_session_callbacks callbacks;
3192   nghttp2_data_provider data_prd;
3193   my_user_data ud;
3194   nghttp2_frame *frame;
3195   nghttp2_frame_hd hd;
3196   nghttp2_active_outbound_item *aob;
3197   nghttp2_bufs *framebufs;
3198   nghttp2_buf *buf;
3199
3200   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3201   callbacks.send_callback = block_count_send_callback;
3202   callbacks.read_length_callback = smallest_length_data_source_length_callback;
3203
3204   data_prd.read_callback = fixed_length_data_source_read_callback;
3205   ud.data_source_length = NGHTTP2_DATA_PAYLOADLEN * 2;
3206   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
3207   aob = &session->aob;
3208   framebufs = &aob->framebufs;
3209
3210   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
3211                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
3212   CU_ASSERT(
3213       0 == nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM, 1, &data_prd));
3214
3215   ud.block_count = 0;
3216   CU_ASSERT(0 == nghttp2_session_send(session));
3217   frame = &aob->item->frame;
3218
3219   buf = &framebufs->head->buf;
3220   nghttp2_frame_unpack_frame_hd(&hd, buf->pos);
3221
3222   CU_ASSERT(NGHTTP2_FLAG_NONE == hd.flags);
3223   CU_ASSERT(NGHTTP2_FLAG_NONE == frame->hd.flags);
3224   CU_ASSERT(1 == hd.length)
3225   /* aux_data.data.flags has these flags */
3226   CU_ASSERT(NGHTTP2_FLAG_END_STREAM == aob->item->aux_data.data.flags);
3227
3228   nghttp2_session_del(session);
3229 }
3230
3231 static ssize_t submit_data_twice_data_source_read_callback(
3232     nghttp2_session *session _U_, int32_t stream_id _U_, uint8_t *buf _U_,
3233     size_t len, uint32_t *data_flags, nghttp2_data_source *source _U_,
3234     void *user_data _U_) {
3235   *data_flags |= NGHTTP2_DATA_FLAG_EOF;
3236   return nghttp2_min(len, 16);
3237 }
3238
3239 static int submit_data_twice_on_frame_send_callback(nghttp2_session *session,
3240                                                     const nghttp2_frame *frame,
3241                                                     void *user_data _U_) {
3242   static int called = 0;
3243   int rv;
3244   nghttp2_data_provider data_prd;
3245
3246   if (called == 0) {
3247     called = 1;
3248
3249     data_prd.read_callback = submit_data_twice_data_source_read_callback;
3250
3251     rv = nghttp2_submit_data(session, NGHTTP2_FLAG_END_STREAM,
3252                              frame->hd.stream_id, &data_prd);
3253     CU_ASSERT(0 == rv);
3254   }
3255
3256   return 0;
3257 }
3258
3259 void test_nghttp2_submit_data_twice(void) {
3260   nghttp2_session *session;
3261   nghttp2_session_callbacks callbacks;
3262   nghttp2_data_provider data_prd;
3263   my_user_data ud;
3264   accumulator acc;
3265
3266   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3267   callbacks.send_callback = accumulator_send_callback;
3268   callbacks.on_frame_send_callback = submit_data_twice_on_frame_send_callback;
3269
3270   data_prd.read_callback = submit_data_twice_data_source_read_callback;
3271
3272   acc.length = 0;
3273   ud.acc = &acc;
3274
3275   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
3276
3277   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
3278                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
3279
3280   CU_ASSERT(0 == nghttp2_submit_data(session, NGHTTP2_FLAG_NONE, 1, &data_prd));
3281
3282   CU_ASSERT(0 == nghttp2_session_send(session));
3283
3284   /* We should have sent 2 DATA frame with 16 bytes payload each */
3285   CU_ASSERT(NGHTTP2_FRAME_HDLEN * 2 + 16 * 2 == acc.length);
3286
3287   nghttp2_session_del(session);
3288 }
3289
3290 void test_nghttp2_submit_request_with_data(void) {
3291   nghttp2_session *session;
3292   nghttp2_session_callbacks callbacks;
3293   nghttp2_nv nva[] = {MAKE_NV(":version", "HTTP/1.1")};
3294   nghttp2_data_provider data_prd;
3295   my_user_data ud;
3296   nghttp2_outbound_item *item;
3297
3298   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3299   callbacks.send_callback = null_send_callback;
3300
3301   data_prd.read_callback = fixed_length_data_source_read_callback;
3302   ud.data_source_length = 64 * 1024 - 1;
3303   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
3304   CU_ASSERT(1 == nghttp2_submit_request(session, NULL, nva, ARRLEN(nva),
3305                                         &data_prd, NULL));
3306   item = nghttp2_session_get_next_ob_item(session);
3307   CU_ASSERT(nvnameeq(":version", &item->frame.headers.nva[0]));
3308   CU_ASSERT(0 == nghttp2_session_send(session));
3309   CU_ASSERT(0 == ud.data_source_length);
3310
3311   nghttp2_session_del(session);
3312 }
3313
3314 void test_nghttp2_submit_request_without_data(void) {
3315   nghttp2_session *session;
3316   nghttp2_session_callbacks callbacks;
3317   accumulator acc;
3318   nghttp2_nv nva[] = {MAKE_NV(":version", "HTTP/1.1")};
3319   nghttp2_data_provider data_prd = {{-1}, NULL};
3320   nghttp2_outbound_item *item;
3321   my_user_data ud;
3322   nghttp2_frame frame;
3323   nghttp2_hd_inflater inflater;
3324   nva_out out;
3325   nghttp2_bufs bufs;
3326   nghttp2_mem *mem;
3327
3328   mem = nghttp2_mem_default();
3329   frame_pack_bufs_init(&bufs);
3330
3331   nva_out_init(&out);
3332   acc.length = 0;
3333   ud.acc = &acc;
3334   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3335   callbacks.send_callback = accumulator_send_callback;
3336   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
3337
3338   nghttp2_hd_inflate_init(&inflater, mem);
3339   CU_ASSERT(1 == nghttp2_submit_request(session, NULL, nva, ARRLEN(nva),
3340                                         &data_prd, NULL));
3341   item = nghttp2_session_get_next_ob_item(session);
3342   CU_ASSERT(nvnameeq(":version", &item->frame.headers.nva[0]));
3343   CU_ASSERT(item->frame.hd.flags & NGHTTP2_FLAG_END_STREAM);
3344
3345   CU_ASSERT(0 == nghttp2_session_send(session));
3346   CU_ASSERT(0 == unpack_frame(&frame, acc.buf, acc.length));
3347
3348   nghttp2_bufs_add(&bufs, acc.buf, acc.length);
3349   inflate_hd(&inflater, &out, &bufs, NGHTTP2_FRAME_HDLEN);
3350
3351   CU_ASSERT(nvnameeq(":version", &out.nva[0]));
3352   nghttp2_frame_headers_free(&frame.headers, mem);
3353   nva_out_reset(&out);
3354
3355   nghttp2_bufs_free(&bufs);
3356   nghttp2_hd_inflate_free(&inflater);
3357   nghttp2_session_del(session);
3358 }
3359
3360 void test_nghttp2_submit_response_with_data(void) {
3361   nghttp2_session *session;
3362   nghttp2_session_callbacks callbacks;
3363   nghttp2_nv nva[] = {MAKE_NV(":version", "HTTP/1.1")};
3364   nghttp2_data_provider data_prd;
3365   my_user_data ud;
3366   nghttp2_outbound_item *item;
3367
3368   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3369   callbacks.send_callback = null_send_callback;
3370
3371   data_prd.read_callback = fixed_length_data_source_read_callback;
3372   ud.data_source_length = 64 * 1024 - 1;
3373   CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud));
3374   nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_END_STREAM,
3375                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
3376   CU_ASSERT(0 ==
3377             nghttp2_submit_response(session, 1, nva, ARRLEN(nva), &data_prd));
3378   item = nghttp2_session_get_next_ob_item(session);
3379   CU_ASSERT(nvnameeq(":version", &item->frame.headers.nva[0]));
3380   CU_ASSERT(0 == nghttp2_session_send(session));
3381   CU_ASSERT(0 == ud.data_source_length);
3382
3383   nghttp2_session_del(session);
3384 }
3385
3386 void test_nghttp2_submit_response_without_data(void) {
3387   nghttp2_session *session;
3388   nghttp2_session_callbacks callbacks;
3389   accumulator acc;
3390   nghttp2_nv nva[] = {MAKE_NV(":version", "HTTP/1.1")};
3391   nghttp2_data_provider data_prd = {{-1}, NULL};
3392   nghttp2_outbound_item *item;
3393   my_user_data ud;
3394   nghttp2_frame frame;
3395   nghttp2_hd_inflater inflater;
3396   nva_out out;
3397   nghttp2_bufs bufs;
3398   nghttp2_mem *mem;
3399
3400   mem = nghttp2_mem_default();
3401   frame_pack_bufs_init(&bufs);
3402
3403   nva_out_init(&out);
3404   acc.length = 0;
3405   ud.acc = &acc;
3406   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3407   callbacks.send_callback = accumulator_send_callback;
3408   CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud));
3409
3410   nghttp2_hd_inflate_init(&inflater, mem);
3411   nghttp2_session_open_stream(session, 1, NGHTTP2_FLAG_END_STREAM,
3412                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
3413   CU_ASSERT(0 ==
3414             nghttp2_submit_response(session, 1, nva, ARRLEN(nva), &data_prd));
3415   item = nghttp2_session_get_next_ob_item(session);
3416   CU_ASSERT(nvnameeq(":version", &item->frame.headers.nva[0]));
3417   CU_ASSERT(item->frame.hd.flags & NGHTTP2_FLAG_END_STREAM);
3418
3419   CU_ASSERT(0 == nghttp2_session_send(session));
3420   CU_ASSERT(0 == unpack_frame(&frame, acc.buf, acc.length));
3421
3422   nghttp2_bufs_add(&bufs, acc.buf, acc.length);
3423   inflate_hd(&inflater, &out, &bufs, NGHTTP2_FRAME_HDLEN);
3424
3425   CU_ASSERT(nvnameeq(":version", &out.nva[0]));
3426
3427   nva_out_reset(&out);
3428   nghttp2_bufs_free(&bufs);
3429   nghttp2_frame_headers_free(&frame.headers, mem);
3430   nghttp2_hd_inflate_free(&inflater);
3431   nghttp2_session_del(session);
3432 }
3433
3434 void test_nghttp2_submit_headers_start_stream(void) {
3435   nghttp2_session *session;
3436   nghttp2_session_callbacks callbacks;
3437   const nghttp2_nv nv[] = {MAKE_NV(":version", "HTTP/1.1")};
3438   nghttp2_outbound_item *item;
3439
3440   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3441   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, NULL));
3442   CU_ASSERT(1 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, -1,
3443                                         NULL, nv, ARRLEN(nv), NULL));
3444   item = nghttp2_session_get_next_ob_item(session);
3445   CU_ASSERT(nvnameeq(":version", &item->frame.headers.nva[0]));
3446   CU_ASSERT((NGHTTP2_FLAG_END_HEADERS | NGHTTP2_FLAG_END_STREAM) ==
3447             item->frame.hd.flags);
3448   CU_ASSERT(0 == (item->frame.hd.flags & NGHTTP2_FLAG_PRIORITY));
3449
3450   nghttp2_session_del(session);
3451 }
3452
3453 void test_nghttp2_submit_headers_reply(void) {
3454   nghttp2_session *session;
3455   nghttp2_session_callbacks callbacks;
3456   const nghttp2_nv nv[] = {MAKE_NV(":version", "HTTP/1.1")};
3457   my_user_data ud;
3458   nghttp2_outbound_item *item;
3459   nghttp2_stream *stream;
3460
3461   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3462   callbacks.send_callback = null_send_callback;
3463   callbacks.on_frame_send_callback = on_frame_send_callback;
3464
3465   CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud));
3466   CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, 1,
3467                                         NULL, nv, ARRLEN(nv), NULL));
3468   item = nghttp2_session_get_next_ob_item(session);
3469   CU_ASSERT(nvnameeq(":version", &item->frame.headers.nva[0]));
3470   CU_ASSERT((NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS) ==
3471             item->frame.hd.flags);
3472
3473   ud.frame_send_cb_called = 0;
3474   ud.sent_frame_type = 0;
3475   /* The transimission will be canceled because the stream 1 is not
3476      open. */
3477   CU_ASSERT(0 == nghttp2_session_send(session));
3478   CU_ASSERT(0 == ud.frame_send_cb_called);
3479
3480   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
3481                                        &pri_spec_default,
3482                                        NGHTTP2_STREAM_OPENING, NULL);
3483
3484   CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, 1,
3485                                         NULL, nv, ARRLEN(nv), NULL));
3486   CU_ASSERT(0 == nghttp2_session_send(session));
3487   CU_ASSERT(1 == ud.frame_send_cb_called);
3488   CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type);
3489   CU_ASSERT(stream->shut_flags & NGHTTP2_SHUT_WR);
3490
3491   nghttp2_session_del(session);
3492 }
3493
3494 void test_nghttp2_submit_headers_push_reply(void) {
3495   nghttp2_session *session;
3496   nghttp2_session_callbacks callbacks;
3497   const nghttp2_nv nv[] = {MAKE_NV(":version", "HTTP/1.1")};
3498   my_user_data ud;
3499   nghttp2_stream *stream;
3500   int foo;
3501
3502   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3503   callbacks.send_callback = null_send_callback;
3504   callbacks.on_frame_send_callback = on_frame_send_callback;
3505
3506   CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud));
3507   stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
3508                                        &pri_spec_default,
3509                                        NGHTTP2_STREAM_RESERVED, NULL);
3510   CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_NONE, 2, NULL, nv,
3511                                         ARRLEN(nv), &foo));
3512
3513   ud.frame_send_cb_called = 0;
3514   ud.sent_frame_type = 0;
3515   CU_ASSERT(0 == nghttp2_session_send(session));
3516   CU_ASSERT(1 == ud.frame_send_cb_called);
3517   CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type);
3518   CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
3519   CU_ASSERT(&foo == stream->stream_user_data);
3520
3521   nghttp2_session_del(session);
3522
3523   /* Sending HEADERS from client against stream in reserved state is
3524      error */
3525   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
3526   stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
3527                                        &pri_spec_default,
3528                                        NGHTTP2_STREAM_RESERVED, NULL);
3529   CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_NONE, 2, NULL, nv,
3530                                         ARRLEN(nv), NULL));
3531
3532   ud.frame_send_cb_called = 0;
3533   ud.sent_frame_type = 0;
3534   CU_ASSERT(0 == nghttp2_session_send(session));
3535   CU_ASSERT(0 == ud.frame_send_cb_called);
3536
3537   nghttp2_session_del(session);
3538 }
3539
3540 void test_nghttp2_submit_headers(void) {
3541   nghttp2_session *session;
3542   nghttp2_session_callbacks callbacks;
3543   const nghttp2_nv nv[] = {MAKE_NV(":version", "HTTP/1.1")};
3544   my_user_data ud;
3545   nghttp2_outbound_item *item;
3546   nghttp2_stream *stream;
3547   accumulator acc;
3548   nghttp2_frame frame;
3549   nghttp2_hd_inflater inflater;
3550   nva_out out;
3551   nghttp2_bufs bufs;
3552   nghttp2_mem *mem;
3553
3554   mem = nghttp2_mem_default();
3555   frame_pack_bufs_init(&bufs);
3556
3557   nva_out_init(&out);
3558   acc.length = 0;
3559   ud.acc = &acc;
3560   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3561   callbacks.send_callback = accumulator_send_callback;
3562   callbacks.on_frame_send_callback = on_frame_send_callback;
3563
3564   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
3565
3566   nghttp2_hd_inflate_init(&inflater, mem);
3567   CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, 1,
3568                                         NULL, nv, ARRLEN(nv), NULL));
3569   item = nghttp2_session_get_next_ob_item(session);
3570   CU_ASSERT(nvnameeq(":version", &item->frame.headers.nva[0]));
3571   CU_ASSERT((NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS) ==
3572             item->frame.hd.flags);
3573
3574   ud.frame_send_cb_called = 0;
3575   ud.sent_frame_type = 0;
3576   /* The transimission will be canceled because the stream 1 is not
3577      open. */
3578   CU_ASSERT(0 == nghttp2_session_send(session));
3579   CU_ASSERT(0 == ud.frame_send_cb_called);
3580
3581   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
3582                                        &pri_spec_default,
3583                                        NGHTTP2_STREAM_OPENING, NULL);
3584
3585   CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, 1,
3586                                         NULL, nv, ARRLEN(nv), NULL));
3587   CU_ASSERT(0 == nghttp2_session_send(session));
3588   CU_ASSERT(1 == ud.frame_send_cb_called);
3589   CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type);
3590   CU_ASSERT(stream->shut_flags & NGHTTP2_SHUT_WR);
3591
3592   CU_ASSERT(0 == unpack_frame(&frame, acc.buf, acc.length));
3593
3594   nghttp2_bufs_add(&bufs, acc.buf, acc.length);
3595   inflate_hd(&inflater, &out, &bufs, NGHTTP2_FRAME_HDLEN);
3596
3597   CU_ASSERT(nvnameeq(":version", &out.nva[0]));
3598
3599   nva_out_reset(&out);
3600   nghttp2_bufs_free(&bufs);
3601   nghttp2_frame_headers_free(&frame.headers, mem);
3602
3603   nghttp2_hd_inflate_free(&inflater);
3604   nghttp2_session_del(session);
3605 }
3606
3607 void test_nghttp2_submit_headers_continuation(void) {
3608   nghttp2_session *session;
3609   nghttp2_session_callbacks callbacks;
3610   nghttp2_nv nv[] = {
3611       MAKE_NV("h1", ""), MAKE_NV("h1", ""), MAKE_NV("h1", ""),
3612       MAKE_NV("h1", ""), MAKE_NV("h1", ""), MAKE_NV("h1", ""),
3613       MAKE_NV("h1", ""),
3614   };
3615   nghttp2_outbound_item *item;
3616   uint8_t data[4096];
3617   size_t i;
3618   my_user_data ud;
3619
3620   memset(data, '0', sizeof(data));
3621   for (i = 0; i < ARRLEN(nv); ++i) {
3622     nv[i].valuelen = sizeof(data);
3623     nv[i].value = data;
3624   }
3625
3626   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3627   callbacks.send_callback = null_send_callback;
3628   callbacks.on_frame_send_callback = on_frame_send_callback;
3629
3630   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, &ud));
3631   CU_ASSERT(1 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, -1,
3632                                         NULL, nv, ARRLEN(nv), NULL));
3633   item = nghttp2_session_get_next_ob_item(session);
3634   CU_ASSERT(NGHTTP2_HEADERS == item->frame.hd.type);
3635   CU_ASSERT((NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_END_HEADERS) ==
3636             item->frame.hd.flags);
3637   CU_ASSERT(0 == (item->frame.hd.flags & NGHTTP2_FLAG_PRIORITY));
3638
3639   ud.frame_send_cb_called = 0;
3640   CU_ASSERT(0 == nghttp2_session_send(session));
3641   CU_ASSERT(1 == ud.frame_send_cb_called);
3642
3643   nghttp2_session_del(session);
3644 }
3645
3646 void test_nghttp2_submit_priority(void) {
3647   nghttp2_session *session;
3648   nghttp2_session_callbacks callbacks;
3649   nghttp2_stream *stream;
3650   my_user_data ud;
3651   nghttp2_priority_spec pri_spec;
3652
3653   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3654   callbacks.send_callback = null_send_callback;
3655   callbacks.on_frame_send_callback = on_frame_send_callback;
3656
3657   nghttp2_session_client_new(&session, &callbacks, &ud);
3658   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
3659                                        &pri_spec_default,
3660                                        NGHTTP2_STREAM_OPENING, NULL);
3661
3662   nghttp2_priority_spec_init(&pri_spec, 0, 3, 0);
3663
3664   /* depends on stream 0 */
3665   CU_ASSERT(0 ==
3666             nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, 1, &pri_spec));
3667   CU_ASSERT(0 == nghttp2_session_send(session));
3668   CU_ASSERT(3 == stream->weight);
3669
3670   /* submit against idle stream */
3671   CU_ASSERT(0 ==
3672             nghttp2_submit_priority(session, NGHTTP2_FLAG_NONE, 3, &pri_spec));
3673
3674   ud.frame_send_cb_called = 0;
3675   CU_ASSERT(0 == nghttp2_session_send(session));
3676   CU_ASSERT(1 == ud.frame_send_cb_called);
3677
3678   nghttp2_session_del(session);
3679 }
3680
3681 void test_nghttp2_submit_settings(void) {
3682   nghttp2_session *session;
3683   nghttp2_session_callbacks callbacks;
3684   my_user_data ud;
3685   nghttp2_outbound_item *item;
3686   nghttp2_frame *frame;
3687   nghttp2_settings_entry iv[7];
3688   nghttp2_frame ack_frame;
3689   const int32_t UNKNOWN_ID = 1000000007;
3690   nghttp2_mem *mem;
3691
3692   mem = nghttp2_mem_default();
3693
3694   iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
3695   iv[0].value = 5;
3696
3697   iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
3698   iv[1].value = 16 * 1024;
3699
3700   iv[2].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
3701   iv[2].value = 50;
3702
3703   iv[3].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
3704   iv[3].value = 0;
3705
3706   iv[4].settings_id = UNKNOWN_ID;
3707   iv[4].value = 999;
3708
3709   iv[5].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
3710   iv[5].value = (uint32_t)NGHTTP2_MAX_WINDOW_SIZE + 1;
3711
3712   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3713   callbacks.send_callback = null_send_callback;
3714   callbacks.on_frame_send_callback = on_frame_send_callback;
3715   nghttp2_session_server_new(&session, &callbacks, &ud);
3716
3717   CU_ASSERT(NGHTTP2_ERR_INVALID_ARGUMENT ==
3718             nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 6));
3719
3720   /* Make sure that local settings are not changed */
3721   CU_ASSERT(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS ==
3722             session->local_settings.max_concurrent_streams);
3723   CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE ==
3724             session->local_settings.initial_window_size);
3725
3726   /* Now sends without 6th one */
3727   CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 5));
3728
3729   item = nghttp2_session_get_next_ob_item(session);
3730
3731   CU_ASSERT(NGHTTP2_SETTINGS == item->frame.hd.type);
3732
3733   frame = &item->frame;
3734   CU_ASSERT(5 == frame->settings.niv);
3735   CU_ASSERT(5 == frame->settings.iv[0].value);
3736   CU_ASSERT(NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS ==
3737             frame->settings.iv[0].settings_id);
3738
3739   CU_ASSERT(16 * 1024 == frame->settings.iv[1].value);
3740   CU_ASSERT(NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE ==
3741             frame->settings.iv[1].settings_id);
3742
3743   CU_ASSERT(UNKNOWN_ID == frame->settings.iv[4].settings_id);
3744   CU_ASSERT(999 == frame->settings.iv[4].value);
3745
3746   ud.frame_send_cb_called = 0;
3747   CU_ASSERT(0 == nghttp2_session_send(session));
3748   CU_ASSERT(1 == ud.frame_send_cb_called);
3749
3750   CU_ASSERT(50 == session->pending_local_max_concurrent_stream);
3751
3752   nghttp2_frame_settings_init(&ack_frame.settings, NGHTTP2_FLAG_ACK, NULL, 0);
3753   CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &ack_frame, 0));
3754   nghttp2_frame_settings_free(&ack_frame.settings, mem);
3755
3756   CU_ASSERT(16 * 1024 == session->local_settings.initial_window_size);
3757   CU_ASSERT(0 == session->hd_inflater.ctx.hd_table_bufsize_max);
3758   CU_ASSERT(50 == session->local_settings.max_concurrent_streams);
3759   CU_ASSERT(NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS ==
3760             session->pending_local_max_concurrent_stream);
3761
3762   nghttp2_session_del(session);
3763 }
3764
3765 void test_nghttp2_submit_settings_update_local_window_size(void) {
3766   nghttp2_session *session;
3767   nghttp2_session_callbacks callbacks;
3768   nghttp2_outbound_item *item;
3769   nghttp2_settings_entry iv[4];
3770   nghttp2_stream *stream;
3771   nghttp2_frame ack_frame;
3772   nghttp2_mem *mem;
3773
3774   mem = nghttp2_mem_default();
3775   nghttp2_frame_settings_init(&ack_frame.settings, NGHTTP2_FLAG_ACK, NULL, 0);
3776
3777   iv[0].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
3778   iv[0].value = 16 * 1024;
3779
3780   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3781   callbacks.send_callback = null_send_callback;
3782
3783   nghttp2_session_server_new(&session, &callbacks, NULL);
3784
3785   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
3786                                        &pri_spec_default, NGHTTP2_STREAM_OPENED,
3787                                        NULL);
3788   stream->local_window_size = NGHTTP2_INITIAL_WINDOW_SIZE + 100;
3789   stream->recv_window_size = 32768;
3790
3791   stream = nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE,
3792                                        &pri_spec_default, NGHTTP2_STREAM_OPENED,
3793                                        NULL);
3794
3795   CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 1));
3796   CU_ASSERT(0 == nghttp2_session_send(session));
3797   CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &ack_frame, 0));
3798
3799   stream = nghttp2_session_get_stream(session, 1);
3800   CU_ASSERT(0 == stream->recv_window_size);
3801   CU_ASSERT(16 * 1024 + 100 == stream->local_window_size);
3802
3803   stream = nghttp2_session_get_stream(session, 3);
3804   CU_ASSERT(16 * 1024 == stream->local_window_size);
3805
3806   item = nghttp2_session_get_next_ob_item(session);
3807   CU_ASSERT(NGHTTP2_WINDOW_UPDATE == item->frame.hd.type);
3808   CU_ASSERT(32768 == item->frame.window_update.window_size_increment);
3809
3810   nghttp2_session_del(session);
3811
3812   /* Check overflow case */
3813   iv[0].value = 128 * 1024;
3814   nghttp2_session_server_new(&session, &callbacks, NULL);
3815   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
3816                                        &pri_spec_default, NGHTTP2_STREAM_OPENED,
3817                                        NULL);
3818   stream->local_window_size = NGHTTP2_MAX_WINDOW_SIZE;
3819
3820   CU_ASSERT(0 == nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 1));
3821   CU_ASSERT(0 == nghttp2_session_send(session));
3822   CU_ASSERT(0 == nghttp2_session_on_settings_received(session, &ack_frame, 0));
3823
3824   item = nghttp2_session_get_next_ob_item(session);
3825   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
3826   CU_ASSERT(NGHTTP2_FLOW_CONTROL_ERROR == item->frame.goaway.error_code);
3827
3828   nghttp2_session_del(session);
3829   nghttp2_frame_settings_free(&ack_frame.settings, mem);
3830 }
3831
3832 void test_nghttp2_submit_push_promise(void) {
3833   nghttp2_session *session;
3834   nghttp2_session_callbacks callbacks;
3835   const nghttp2_nv nv[] = {MAKE_NV(":version", "HTTP/1.1")};
3836   my_user_data ud;
3837   nghttp2_stream *stream;
3838
3839   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3840   callbacks.send_callback = null_send_callback;
3841   callbacks.on_frame_send_callback = on_frame_send_callback;
3842
3843   CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud));
3844   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
3845                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
3846   CU_ASSERT(2 == nghttp2_submit_push_promise(session, NGHTTP2_FLAG_NONE, 1, nv,
3847                                              ARRLEN(nv), &ud));
3848
3849   ud.frame_send_cb_called = 0;
3850   ud.sent_frame_type = 0;
3851   CU_ASSERT(0 == nghttp2_session_send(session));
3852   CU_ASSERT(1 == ud.frame_send_cb_called);
3853   CU_ASSERT(NGHTTP2_PUSH_PROMISE == ud.sent_frame_type);
3854   stream = nghttp2_session_get_stream(session, 2);
3855   CU_ASSERT(NGHTTP2_STREAM_RESERVED == stream->state);
3856   CU_ASSERT(&ud == nghttp2_session_get_stream_user_data(session, 2));
3857
3858   nghttp2_session_del(session);
3859 }
3860
3861 void test_nghttp2_submit_window_update(void) {
3862   nghttp2_session *session;
3863   nghttp2_session_callbacks callbacks;
3864   my_user_data ud;
3865   nghttp2_outbound_item *item;
3866   nghttp2_stream *stream;
3867
3868   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3869   callbacks.send_callback = null_send_callback;
3870
3871   nghttp2_session_client_new(&session, &callbacks, &ud);
3872   stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
3873                                        &pri_spec_default, NGHTTP2_STREAM_OPENED,
3874                                        NULL);
3875   stream->recv_window_size = 4096;
3876
3877   CU_ASSERT(0 ==
3878             nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 2, 1024));
3879   item = nghttp2_session_get_next_ob_item(session);
3880   CU_ASSERT(NGHTTP2_WINDOW_UPDATE == item->frame.hd.type);
3881   CU_ASSERT(1024 == item->frame.window_update.window_size_increment);
3882   CU_ASSERT(0 == nghttp2_session_send(session));
3883   CU_ASSERT(3072 == stream->recv_window_size);
3884
3885   CU_ASSERT(0 ==
3886             nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 2, 4096));
3887   item = nghttp2_session_get_next_ob_item(session);
3888   CU_ASSERT(NGHTTP2_WINDOW_UPDATE == item->frame.hd.type);
3889   CU_ASSERT(4096 == item->frame.window_update.window_size_increment);
3890   CU_ASSERT(0 == nghttp2_session_send(session));
3891   CU_ASSERT(0 == stream->recv_window_size);
3892
3893   CU_ASSERT(0 ==
3894             nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 2, 4096));
3895   item = nghttp2_session_get_next_ob_item(session);
3896   CU_ASSERT(NGHTTP2_WINDOW_UPDATE == item->frame.hd.type);
3897   CU_ASSERT(4096 == item->frame.window_update.window_size_increment);
3898   CU_ASSERT(0 == nghttp2_session_send(session));
3899   CU_ASSERT(0 == stream->recv_window_size);
3900
3901   CU_ASSERT(0 ==
3902             nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 2, 0));
3903   /* It is ok if stream is closed or does not exist at the call
3904      time */
3905   CU_ASSERT(0 ==
3906             nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 4, 4096));
3907
3908   nghttp2_session_del(session);
3909 }
3910
3911 void test_nghttp2_submit_window_update_local_window_size(void) {
3912   nghttp2_session *session;
3913   nghttp2_session_callbacks callbacks;
3914   nghttp2_outbound_item *item;
3915   nghttp2_stream *stream;
3916
3917   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
3918   callbacks.send_callback = null_send_callback;
3919
3920   nghttp2_session_client_new(&session, &callbacks, NULL);
3921   stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
3922                                        &pri_spec_default, NGHTTP2_STREAM_OPENED,
3923                                        NULL);
3924   stream->recv_window_size = 4096;
3925
3926   CU_ASSERT(0 == nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 2,
3927                                               stream->recv_window_size + 1));
3928   CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE + 1 == stream->local_window_size);
3929   CU_ASSERT(0 == stream->recv_window_size);
3930   item = nghttp2_session_get_next_ob_item(session);
3931   CU_ASSERT(NGHTTP2_WINDOW_UPDATE == item->frame.hd.type);
3932   CU_ASSERT(4097 == item->frame.window_update.window_size_increment);
3933
3934   CU_ASSERT(0 == nghttp2_session_send(session));
3935
3936   /* Let's decrement local window size */
3937   stream->recv_window_size = 4096;
3938   CU_ASSERT(0 == nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 2,
3939                                               -stream->local_window_size / 2));
3940   CU_ASSERT(32768 == stream->local_window_size);
3941   CU_ASSERT(-28672 == stream->recv_window_size);
3942   CU_ASSERT(32768 == stream->recv_reduction);
3943
3944   item = nghttp2_session_get_next_ob_item(session);
3945   CU_ASSERT(item == NULL);
3946
3947   /* Increase local window size */
3948   CU_ASSERT(0 ==
3949             nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 2, 16384));
3950   CU_ASSERT(49152 == stream->local_window_size);
3951   CU_ASSERT(-12288 == stream->recv_window_size);
3952   CU_ASSERT(16384 == stream->recv_reduction);
3953   CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
3954
3955   CU_ASSERT(NGHTTP2_ERR_FLOW_CONTROL ==
3956             nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 2,
3957                                          NGHTTP2_MAX_WINDOW_SIZE));
3958
3959   CU_ASSERT(0 == nghttp2_session_send(session));
3960
3961   /* Check connection-level flow control */
3962   session->recv_window_size = 4096;
3963   CU_ASSERT(0 == nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 0,
3964                                               session->recv_window_size + 1));
3965   CU_ASSERT(NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE + 1 ==
3966             session->local_window_size);
3967   CU_ASSERT(0 == session->recv_window_size);
3968   item = nghttp2_session_get_next_ob_item(session);
3969   CU_ASSERT(NGHTTP2_WINDOW_UPDATE == item->frame.hd.type);
3970   CU_ASSERT(4097 == item->frame.window_update.window_size_increment);
3971
3972   CU_ASSERT(0 == nghttp2_session_send(session));
3973
3974   /* Go decrement part */
3975   session->recv_window_size = 4096;
3976   CU_ASSERT(0 == nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 0,
3977                                               -session->local_window_size / 2));
3978   CU_ASSERT(32768 == session->local_window_size);
3979   CU_ASSERT(-28672 == session->recv_window_size);
3980   CU_ASSERT(32768 == session->recv_reduction);
3981   item = nghttp2_session_get_next_ob_item(session);
3982   CU_ASSERT(item == NULL);
3983
3984   /* Increase local window size */
3985   CU_ASSERT(0 ==
3986             nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 0, 16384));
3987   CU_ASSERT(49152 == session->local_window_size);
3988   CU_ASSERT(-12288 == session->recv_window_size);
3989   CU_ASSERT(16384 == session->recv_reduction);
3990   CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
3991
3992   CU_ASSERT(NGHTTP2_ERR_FLOW_CONTROL ==
3993             nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 0,
3994                                          NGHTTP2_MAX_WINDOW_SIZE));
3995
3996   nghttp2_session_del(session);
3997 }
3998
3999 void test_nghttp2_submit_shutdown_notice(void) {
4000   nghttp2_session *session;
4001   nghttp2_session_callbacks callbacks;
4002   my_user_data ud;
4003
4004   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4005   callbacks.send_callback = null_send_callback;
4006   callbacks.on_frame_send_callback = on_frame_send_callback;
4007   callbacks.on_frame_not_send_callback = on_frame_not_send_callback;
4008
4009   nghttp2_session_server_new(&session, &callbacks, &ud);
4010
4011   CU_ASSERT(0 == nghttp2_submit_shutdown_notice(session));
4012
4013   ud.frame_send_cb_called = 0;
4014
4015   nghttp2_session_send(session);
4016
4017   CU_ASSERT(1 == ud.frame_send_cb_called);
4018   CU_ASSERT(NGHTTP2_GOAWAY == ud.sent_frame_type);
4019   CU_ASSERT((1u << 31) - 1 == session->local_last_stream_id);
4020
4021   /* After another GOAWAY, nghttp2_submit_shutdown_notice() is
4022      noop. */
4023   CU_ASSERT(0 == nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR));
4024
4025   ud.frame_send_cb_called = 0;
4026
4027   nghttp2_session_send(session);
4028
4029   CU_ASSERT(1 == ud.frame_send_cb_called);
4030   CU_ASSERT(NGHTTP2_GOAWAY == ud.sent_frame_type);
4031   CU_ASSERT(0 == session->local_last_stream_id);
4032
4033   CU_ASSERT(0 == nghttp2_submit_shutdown_notice(session));
4034
4035   ud.frame_send_cb_called = 0;
4036   ud.frame_not_send_cb_called = 0;
4037
4038   nghttp2_session_send(session);
4039
4040   CU_ASSERT(0 == ud.frame_send_cb_called);
4041   CU_ASSERT(0 == ud.frame_not_send_cb_called);
4042
4043   nghttp2_session_del(session);
4044
4045   /* Using nghttp2_submit_shutdown_notice() with client side session
4046      is error */
4047   nghttp2_session_client_new(&session, &callbacks, NULL);
4048
4049   CU_ASSERT(NGHTTP2_ERR_INVALID_STATE ==
4050             nghttp2_submit_shutdown_notice(session));
4051
4052   nghttp2_session_del(session);
4053 }
4054
4055 void test_nghttp2_submit_invalid_nv(void) {
4056   nghttp2_session *session;
4057   nghttp2_session_callbacks callbacks;
4058   nghttp2_nv empty_name_nv[] = {MAKE_NV("Version", "HTTP/1.1"),
4059                                 MAKE_NV("", "empty name")};
4060
4061   /* Now invalid header name/value pair in HTTP/1.1 is accepted in
4062      nghttp2 */
4063
4064   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4065
4066   CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, NULL));
4067
4068   /* nghttp2_submit_request */
4069   CU_ASSERT(0 < nghttp2_submit_request(session, NULL, empty_name_nv,
4070                                        ARRLEN(empty_name_nv), NULL, NULL));
4071
4072   /* nghttp2_submit_response */
4073   CU_ASSERT(0 == nghttp2_submit_response(session, 2, empty_name_nv,
4074                                          ARRLEN(empty_name_nv), NULL));
4075
4076   /* nghttp2_submit_headers */
4077   CU_ASSERT(0 < nghttp2_submit_headers(session, NGHTTP2_FLAG_NONE, -1, NULL,
4078                                        empty_name_nv, ARRLEN(empty_name_nv),
4079                                        NULL));
4080
4081   /* nghttp2_submit_push_promise */
4082   open_stream(session, 1);
4083
4084   CU_ASSERT(0 < nghttp2_submit_push_promise(session, NGHTTP2_FLAG_NONE, 1,
4085                                             empty_name_nv,
4086                                             ARRLEN(empty_name_nv), NULL));
4087
4088   nghttp2_session_del(session);
4089 }
4090
4091 void test_nghttp2_session_open_stream(void) {
4092   nghttp2_session *session;
4093   nghttp2_session_callbacks callbacks;
4094   nghttp2_stream *stream;
4095   nghttp2_priority_spec pri_spec;
4096
4097   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4098   nghttp2_session_server_new(&session, &callbacks, NULL);
4099
4100   nghttp2_priority_spec_init(&pri_spec, 0, 245, 0);
4101
4102   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
4103                                        &pri_spec, NGHTTP2_STREAM_OPENED, NULL);
4104   CU_ASSERT(1 == session->num_incoming_streams);
4105   CU_ASSERT(0 == session->num_outgoing_streams);
4106   CU_ASSERT(NGHTTP2_STREAM_OPENED == stream->state);
4107   CU_ASSERT(245 == stream->weight);
4108   CU_ASSERT(NULL == stream->dep_prev);
4109   CU_ASSERT(NGHTTP2_SHUT_NONE == stream->shut_flags);
4110
4111   stream = nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
4112                                        &pri_spec_default,
4113                                        NGHTTP2_STREAM_OPENING, NULL);
4114   CU_ASSERT(1 == session->num_incoming_streams);
4115   CU_ASSERT(1 == session->num_outgoing_streams);
4116   CU_ASSERT(NULL == stream->dep_prev);
4117   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight);
4118   CU_ASSERT(NGHTTP2_SHUT_NONE == stream->shut_flags);
4119
4120   stream = nghttp2_session_open_stream(session, 4, NGHTTP2_STREAM_FLAG_NONE,
4121                                        &pri_spec_default,
4122                                        NGHTTP2_STREAM_RESERVED, NULL);
4123   CU_ASSERT(1 == session->num_incoming_streams);
4124   CU_ASSERT(1 == session->num_outgoing_streams);
4125   CU_ASSERT(NULL == stream->dep_prev);
4126   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight);
4127   CU_ASSERT(NGHTTP2_SHUT_RD == stream->shut_flags);
4128
4129   nghttp2_priority_spec_init(&pri_spec, 1, 17, 1);
4130
4131   stream = nghttp2_session_open_stream(session, 3, NGHTTP2_STREAM_FLAG_NONE,
4132                                        &pri_spec, NGHTTP2_STREAM_OPENED, NULL);
4133   CU_ASSERT(17 == stream->weight);
4134   CU_ASSERT(1 == stream->dep_prev->stream_id);
4135
4136   /* Dependency to idle stream */
4137   nghttp2_priority_spec_init(&pri_spec, 1000000007, 240, 1);
4138
4139   stream = nghttp2_session_open_stream(session, 5, NGHTTP2_STREAM_FLAG_NONE,
4140                                        &pri_spec, NGHTTP2_STREAM_OPENED, NULL);
4141   CU_ASSERT(240 == stream->weight);
4142   CU_ASSERT(1000000007 == stream->dep_prev->stream_id);
4143
4144   stream = nghttp2_session_get_stream_raw(session, 1000000007);
4145
4146   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight);
4147   CU_ASSERT(NULL != stream->root_next);
4148
4149   /* Dependency to closed stream which is not in dependency tree */
4150   session->last_recv_stream_id = 7;
4151
4152   nghttp2_priority_spec_init(&pri_spec, 7, 10, 0);
4153
4154   stream = nghttp2_session_open_stream(session, 9, NGHTTP2_FLAG_NONE, &pri_spec,
4155                                        NGHTTP2_STREAM_OPENED, NULL);
4156
4157   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight);
4158
4159   nghttp2_session_del(session);
4160
4161   nghttp2_session_client_new(&session, &callbacks, NULL);
4162   stream = nghttp2_session_open_stream(session, 4, NGHTTP2_STREAM_FLAG_NONE,
4163                                        &pri_spec_default,
4164                                        NGHTTP2_STREAM_RESERVED, NULL);
4165   CU_ASSERT(0 == session->num_incoming_streams);
4166   CU_ASSERT(0 == session->num_outgoing_streams);
4167   CU_ASSERT(NULL == stream->dep_prev);
4168   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight);
4169   CU_ASSERT(NGHTTP2_SHUT_WR == stream->shut_flags);
4170
4171   nghttp2_session_del(session);
4172 }
4173
4174 void test_nghttp2_session_open_stream_with_idle_stream_dep(void) {
4175   nghttp2_session *session;
4176   nghttp2_session_callbacks callbacks;
4177   nghttp2_stream *stream;
4178   nghttp2_priority_spec pri_spec;
4179
4180   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4181   nghttp2_session_server_new(&session, &callbacks, NULL);
4182
4183   /* Dependency to idle stream */
4184   nghttp2_priority_spec_init(&pri_spec, 101, 245, 0);
4185
4186   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
4187                                        &pri_spec, NGHTTP2_STREAM_OPENED, NULL);
4188
4189   CU_ASSERT(245 == stream->weight);
4190   CU_ASSERT(101 == stream->dep_prev->stream_id);
4191
4192   stream = nghttp2_session_get_stream_raw(session, 101);
4193
4194   CU_ASSERT(NGHTTP2_STREAM_IDLE == stream->state);
4195   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight);
4196
4197   nghttp2_priority_spec_init(&pri_spec, 211, 1, 0);
4198
4199   /* stream 101 was already created as idle. */
4200   stream = nghttp2_session_open_stream(session, 101, NGHTTP2_STREAM_FLAG_NONE,
4201                                        &pri_spec, NGHTTP2_STREAM_OPENED, NULL);
4202
4203   CU_ASSERT(1 == stream->weight);
4204   CU_ASSERT(211 == stream->dep_prev->stream_id);
4205
4206   stream = nghttp2_session_get_stream_raw(session, 211);
4207
4208   CU_ASSERT(NGHTTP2_STREAM_IDLE == stream->state);
4209   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == stream->weight);
4210
4211   nghttp2_session_del(session);
4212 }
4213
4214 void test_nghttp2_session_get_next_ob_item(void) {
4215   nghttp2_session *session;
4216   nghttp2_session_callbacks callbacks;
4217   nghttp2_priority_spec pri_spec;
4218
4219   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4220   callbacks.send_callback = null_send_callback;
4221
4222   nghttp2_session_server_new(&session, &callbacks, NULL);
4223   session->remote_settings.max_concurrent_streams = 2;
4224
4225   CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
4226   nghttp2_submit_ping(session, NGHTTP2_FLAG_NONE, NULL);
4227   CU_ASSERT(NGHTTP2_PING ==
4228             nghttp2_session_get_next_ob_item(session)->frame.hd.type);
4229
4230   nghttp2_submit_request(session, NULL, NULL, 0, NULL, NULL);
4231   CU_ASSERT(NGHTTP2_PING ==
4232             nghttp2_session_get_next_ob_item(session)->frame.hd.type);
4233
4234   CU_ASSERT(0 == nghttp2_session_send(session));
4235   CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
4236
4237   /* Incoming stream does not affect the number of outgoing max
4238      concurrent streams. */
4239   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
4240                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
4241
4242   nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_MAX_WEIGHT, 0);
4243
4244   nghttp2_submit_request(session, &pri_spec, NULL, 0, NULL, NULL);
4245   CU_ASSERT(NGHTTP2_HEADERS ==
4246             nghttp2_session_get_next_ob_item(session)->frame.hd.type);
4247   CU_ASSERT(0 == nghttp2_session_send(session));
4248
4249   nghttp2_submit_request(session, &pri_spec, NULL, 0, NULL, NULL);
4250   CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(session));
4251
4252   session->remote_settings.max_concurrent_streams = 3;
4253
4254   CU_ASSERT(NGHTTP2_HEADERS ==
4255             nghttp2_session_get_next_ob_item(session)->frame.hd.type);
4256
4257   nghttp2_session_del(session);
4258 }
4259
4260 void test_nghttp2_session_pop_next_ob_item(void) {
4261   nghttp2_session *session;
4262   nghttp2_session_callbacks callbacks;
4263   nghttp2_outbound_item *item;
4264   nghttp2_priority_spec pri_spec;
4265   nghttp2_stream *stream;
4266   nghttp2_mem *mem;
4267
4268   mem = nghttp2_mem_default();
4269   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4270   callbacks.send_callback = null_send_callback;
4271
4272   nghttp2_session_server_new(&session, &callbacks, NULL);
4273   session->remote_settings.max_concurrent_streams = 1;
4274
4275   CU_ASSERT(NULL == nghttp2_session_pop_next_ob_item(session));
4276
4277   nghttp2_submit_ping(session, NGHTTP2_FLAG_NONE, NULL);
4278
4279   nghttp2_priority_spec_init(&pri_spec, 0, 254, 0);
4280
4281   nghttp2_submit_request(session, &pri_spec, NULL, 0, NULL, NULL);
4282
4283   item = nghttp2_session_pop_next_ob_item(session);
4284   CU_ASSERT(NGHTTP2_PING == item->frame.hd.type);
4285   nghttp2_outbound_item_free(item, mem);
4286   free(item);
4287
4288   item = nghttp2_session_pop_next_ob_item(session);
4289   CU_ASSERT(NGHTTP2_HEADERS == item->frame.hd.type);
4290   nghttp2_outbound_item_free(item, mem);
4291   free(item);
4292
4293   CU_ASSERT(NULL == nghttp2_session_pop_next_ob_item(session));
4294
4295   /* Incoming stream does not affect the number of outgoing max
4296      concurrent streams. */
4297   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
4298                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
4299   /* In-flight outgoing stream */
4300   nghttp2_session_open_stream(session, 4, NGHTTP2_STREAM_FLAG_NONE,
4301                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
4302
4303   nghttp2_priority_spec_init(&pri_spec, 0, NGHTTP2_MAX_WEIGHT, 0);
4304
4305   nghttp2_submit_request(session, &pri_spec, NULL, 0, NULL, NULL);
4306   nghttp2_submit_response(session, 1, NULL, 0, NULL);
4307
4308   item = nghttp2_session_pop_next_ob_item(session);
4309   CU_ASSERT(NGHTTP2_HEADERS == item->frame.hd.type);
4310   CU_ASSERT(1 == item->frame.hd.stream_id);
4311
4312   stream = nghttp2_session_get_stream(session, 1);
4313
4314   nghttp2_stream_detach_item(stream, session);
4315
4316   nghttp2_outbound_item_free(item, mem);
4317   free(item);
4318
4319   CU_ASSERT(NULL == nghttp2_session_pop_next_ob_item(session));
4320
4321   session->remote_settings.max_concurrent_streams = 2;
4322
4323   item = nghttp2_session_pop_next_ob_item(session);
4324   CU_ASSERT(NGHTTP2_HEADERS == item->frame.hd.type);
4325   nghttp2_outbound_item_free(item, mem);
4326   free(item);
4327
4328   nghttp2_session_del(session);
4329
4330   /* Check that push reply HEADERS are queued into ob_ss_pq */
4331   nghttp2_session_server_new(&session, &callbacks, NULL);
4332   session->remote_settings.max_concurrent_streams = 0;
4333   nghttp2_session_open_stream(session, 2, NGHTTP2_STREAM_FLAG_NONE,
4334                               &pri_spec_default, NGHTTP2_STREAM_RESERVED, NULL);
4335   CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, 2,
4336                                         NULL, NULL, 0, NULL));
4337   CU_ASSERT(NULL == nghttp2_session_pop_next_ob_item(session));
4338   CU_ASSERT(1 == nghttp2_pq_size(&session->ob_ss_pq));
4339   nghttp2_session_del(session);
4340 }
4341
4342 void test_nghttp2_session_reply_fail(void) {
4343   nghttp2_session *session;
4344   nghttp2_session_callbacks callbacks;
4345   nghttp2_data_provider data_prd;
4346   my_user_data ud;
4347
4348   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4349   callbacks.send_callback = fail_send_callback;
4350
4351   data_prd.read_callback = fixed_length_data_source_read_callback;
4352   ud.data_source_length = 4 * 1024;
4353   CU_ASSERT(0 == nghttp2_session_server_new(&session, &callbacks, &ud));
4354   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
4355                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
4356   CU_ASSERT(0 == nghttp2_submit_response(session, 1, NULL, 0, &data_prd));
4357   CU_ASSERT(NGHTTP2_ERR_CALLBACK_FAILURE == nghttp2_session_send(session));
4358   nghttp2_session_del(session);
4359 }
4360
4361 void test_nghttp2_session_max_concurrent_streams(void) {
4362   nghttp2_session *session;
4363   nghttp2_session_callbacks callbacks;
4364   nghttp2_frame frame;
4365   nghttp2_outbound_item *item;
4366   nghttp2_mem *mem;
4367
4368   mem = nghttp2_mem_default();
4369   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4370   callbacks.send_callback = null_send_callback;
4371
4372   nghttp2_session_server_new(&session, &callbacks, NULL);
4373   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
4374                               &pri_spec_default, NGHTTP2_STREAM_OPENED, NULL);
4375
4376   /* Check un-ACKed SETTINGS_MAX_CONCURRENT_STREAMS */
4377   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 3,
4378                              NGHTTP2_HCAT_HEADERS, NULL, NULL, 0);
4379   session->pending_local_max_concurrent_stream = 1;
4380
4381   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
4382             nghttp2_session_on_request_headers_received(session, &frame));
4383
4384   item = nghttp2_session_get_ob_pq_top(session);
4385   CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
4386   CU_ASSERT(NGHTTP2_REFUSED_STREAM == item->frame.rst_stream.error_code);
4387
4388   CU_ASSERT(0 == nghttp2_session_send(session));
4389
4390   /* Check ACKed SETTINGS_MAX_CONCURRENT_STREAMS */
4391   session->local_settings.max_concurrent_streams = 1;
4392   frame.hd.stream_id = 5;
4393
4394   CU_ASSERT(NGHTTP2_ERR_IGN_HEADER_BLOCK ==
4395             nghttp2_session_on_request_headers_received(session, &frame));
4396
4397   item = nghttp2_session_get_ob_pq_top(session);
4398   CU_ASSERT(NGHTTP2_GOAWAY == item->frame.hd.type);
4399   CU_ASSERT(NGHTTP2_PROTOCOL_ERROR == item->frame.goaway.error_code);
4400
4401   nghttp2_frame_headers_free(&frame.headers, mem);
4402   nghttp2_session_del(session);
4403 }
4404
4405 /*
4406  * Check that on_stream_close_callback is called when server pushed
4407  * HEADERS have NGHTTP2_FLAG_END_STREAM.
4408  */
4409 void test_nghttp2_session_stream_close_on_headers_push(void) {
4410   /* nghttp2_session *session; */
4411   /* nghttp2_session_callbacks callbacks; */
4412   /* const char *nv[] = { NULL }; */
4413   /* my_user_data ud; */
4414   /* nghttp2_frame frame; */
4415
4416   /* memset(&callbacks, 0, sizeof(nghttp2_session_callbacks)); */
4417   /* callbacks.on_stream_close_callback = */
4418   /*   no_stream_user_data_stream_close_callback; */
4419   /* ud.stream_close_cb_called = 0; */
4420
4421   /* nghttp2_session_client_new(&session, NGHTTP2_PROTO_SPDY2, &callbacks, &ud);
4422    */
4423   /* nghttp2_session_open_stream(session, 1, NGHTTP2_CTRL_FLAG_NONE, 3, */
4424   /*                             NGHTTP2_STREAM_OPENING, NULL); */
4425   /* nghttp2_frame_syn_stream_init(&frame.syn_stream, NGHTTP2_PROTO_SPDY2, */
4426   /*                               NGHTTP2_CTRL_FLAG_FIN | */
4427   /*                               NGHTTP2_CTRL_FLAG_UNIDIRECTIONAL, */
4428   /*                               2, 1, 3, dup_nv(nv)); */
4429
4430   /* CU_ASSERT(0 == nghttp2_session_on_request_headers_received(session,
4431    * &frame)); */
4432
4433   /* nghttp2_frame_syn_stream_free(&frame.syn_stream); */
4434   /* nghttp2_session_del(session); */
4435 }
4436
4437 void test_nghttp2_session_stop_data_with_rst_stream(void) {
4438   nghttp2_session *session;
4439   nghttp2_session_callbacks callbacks;
4440   my_user_data ud;
4441   nghttp2_data_provider data_prd;
4442   nghttp2_frame frame;
4443
4444   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4445   callbacks.on_frame_send_callback = on_frame_send_callback;
4446   callbacks.send_callback = block_count_send_callback;
4447   data_prd.read_callback = fixed_length_data_source_read_callback;
4448
4449   ud.frame_send_cb_called = 0;
4450   ud.data_source_length = NGHTTP2_DATA_PAYLOADLEN * 4;
4451
4452   nghttp2_session_server_new(&session, &callbacks, &ud);
4453   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
4454                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
4455   nghttp2_submit_response(session, 1, NULL, 0, &data_prd);
4456
4457   ud.block_count = 2;
4458   /* Sends response HEADERS + DATA[0] */
4459   CU_ASSERT(0 == nghttp2_session_send(session));
4460   CU_ASSERT(NGHTTP2_DATA == ud.sent_frame_type);
4461   /* data for DATA[1] is read from data_prd but it is not sent */
4462   CU_ASSERT(ud.data_source_length == NGHTTP2_DATA_PAYLOADLEN * 2);
4463
4464   nghttp2_frame_rst_stream_init(&frame.rst_stream, 1, NGHTTP2_CANCEL);
4465   CU_ASSERT(0 == nghttp2_session_on_rst_stream_received(session, &frame));
4466   nghttp2_frame_rst_stream_free(&frame.rst_stream);
4467
4468   /* Big enough number to send all DATA frames potentially. */
4469   ud.block_count = 100;
4470   /* Nothing will be sent in the following call. */
4471   CU_ASSERT(0 == nghttp2_session_send(session));
4472   /* With RST_STREAM, stream is canceled and further DATA on that
4473      stream are not sent. */
4474   CU_ASSERT(ud.data_source_length == NGHTTP2_DATA_PAYLOADLEN * 2);
4475
4476   CU_ASSERT(NULL == nghttp2_session_get_stream(session, 1));
4477
4478   nghttp2_session_del(session);
4479 }
4480
4481 void test_nghttp2_session_defer_data(void) {
4482   nghttp2_session *session;
4483   nghttp2_session_callbacks callbacks;
4484   my_user_data ud;
4485   nghttp2_data_provider data_prd;
4486   nghttp2_outbound_item *item;
4487
4488   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4489   callbacks.on_frame_send_callback = on_frame_send_callback;
4490   callbacks.send_callback = block_count_send_callback;
4491   data_prd.read_callback = defer_data_source_read_callback;
4492
4493   ud.frame_send_cb_called = 0;
4494   ud.data_source_length = NGHTTP2_DATA_PAYLOADLEN * 4;
4495
4496   nghttp2_session_server_new(&session, &callbacks, &ud);
4497   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
4498                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
4499   nghttp2_submit_response(session, 1, NULL, 0, &data_prd);
4500
4501   ud.block_count = 1;
4502   /* Sends HEADERS reply */
4503   CU_ASSERT(0 == nghttp2_session_send(session));
4504   CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type);
4505   /* No data is read */
4506   CU_ASSERT(ud.data_source_length == NGHTTP2_DATA_PAYLOADLEN * 4);
4507
4508   ud.block_count = 1;
4509   nghttp2_submit_ping(session, NGHTTP2_FLAG_NONE, NULL);
4510   /* Sends PING */
4511   CU_ASSERT(0 == nghttp2_session_send(session));
4512   CU_ASSERT(NGHTTP2_PING == ud.sent_frame_type);
4513
4514   /* Resume deferred DATA */
4515   CU_ASSERT(0 == nghttp2_session_resume_data(session, 1));
4516   item = (nghttp2_outbound_item *)nghttp2_pq_top(&session->ob_da_pq);
4517   item->aux_data.data.data_prd.read_callback =
4518       fixed_length_data_source_read_callback;
4519   ud.block_count = 1;
4520   /* Reads 2 DATA chunks */
4521   CU_ASSERT(0 == nghttp2_session_send(session));
4522   CU_ASSERT(ud.data_source_length == NGHTTP2_DATA_PAYLOADLEN * 2);
4523
4524   /* Deferred again */
4525   item->aux_data.data.data_prd.read_callback = defer_data_source_read_callback;
4526   /* This is needed since 4KiB block is already read and waiting to be
4527      sent. No read_callback invocation. */
4528   ud.block_count = 1;
4529   CU_ASSERT(0 == nghttp2_session_send(session));
4530   CU_ASSERT(ud.data_source_length == NGHTTP2_DATA_PAYLOADLEN * 2);
4531
4532   /* Resume deferred DATA */
4533   CU_ASSERT(0 == nghttp2_session_resume_data(session, 1));
4534   item = (nghttp2_outbound_item *)nghttp2_pq_top(&session->ob_da_pq);
4535   item->aux_data.data.data_prd.read_callback =
4536       fixed_length_data_source_read_callback;
4537   ud.block_count = 1;
4538   /* Reads 2 4KiB blocks */
4539   CU_ASSERT(0 == nghttp2_session_send(session));
4540   CU_ASSERT(ud.data_source_length == 0);
4541
4542   nghttp2_session_del(session);
4543 }
4544
4545 void test_nghttp2_session_flow_control(void) {
4546   nghttp2_session *session;
4547   nghttp2_session_callbacks callbacks;
4548   my_user_data ud;
4549   nghttp2_data_provider data_prd;
4550   nghttp2_frame frame;
4551   nghttp2_stream *stream;
4552   int32_t new_initial_window_size;
4553   nghttp2_settings_entry iv[1];
4554   nghttp2_frame settings_frame;
4555   nghttp2_mem *mem;
4556
4557   mem = nghttp2_mem_default();
4558   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4559   callbacks.send_callback = fixed_bytes_send_callback;
4560   callbacks.on_frame_send_callback = on_frame_send_callback;
4561   data_prd.read_callback = fixed_length_data_source_read_callback;
4562
4563   ud.frame_send_cb_called = 0;
4564   ud.data_source_length = 128 * 1024;
4565   /* Use smaller emission count so that we can check outbound flow
4566      control window calculation is correct. */
4567   ud.fixed_sendlen = 2 * 1024;
4568
4569   /* Initial window size to 64KiB - 1*/
4570   nghttp2_session_client_new(&session, &callbacks, &ud);
4571   /* Change it to 64KiB for easy calculation */
4572   session->remote_window_size = 64 * 1024;
4573   session->remote_settings.initial_window_size = 64 * 1024;
4574
4575   nghttp2_submit_request(session, NULL, NULL, 0, &data_prd, NULL);
4576
4577   /* Sends 64KiB - 1 data */
4578   CU_ASSERT(0 == nghttp2_session_send(session));
4579   CU_ASSERT(64 * 1024 == ud.data_source_length);
4580
4581   /* Back 32KiB in stream window */
4582   nghttp2_frame_window_update_init(&frame.window_update, NGHTTP2_FLAG_NONE, 1,
4583                                    32 * 1024);
4584   nghttp2_session_on_window_update_received(session, &frame);
4585
4586   /* Send nothing because of connection-level window */
4587   CU_ASSERT(0 == nghttp2_session_send(session));
4588   CU_ASSERT(64 * 1024 == ud.data_source_length);
4589
4590   /* Back 32KiB in connection-level window */
4591   frame.hd.stream_id = 0;
4592   nghttp2_session_on_window_update_received(session, &frame);
4593
4594   /* Sends another 32KiB data */
4595   CU_ASSERT(0 == nghttp2_session_send(session));
4596   CU_ASSERT(32 * 1024 == ud.data_source_length);
4597
4598   stream = nghttp2_session_get_stream(session, 1);
4599   /* Change initial window size to 16KiB. The window_size becomes
4600      negative. */
4601   new_initial_window_size = 16 * 1024;
4602   stream->remote_window_size =
4603       new_initial_window_size - (session->remote_settings.initial_window_size -
4604                                  stream->remote_window_size);
4605   session->remote_settings.initial_window_size = new_initial_window_size;
4606   CU_ASSERT(-48 * 1024 == stream->remote_window_size);
4607
4608   /* Back 48KiB to stream window */
4609   frame.hd.stream_id = 1;
4610   frame.window_update.window_size_increment = 48 * 1024;
4611   nghttp2_session_on_window_update_received(session, &frame);
4612
4613   /* Nothing is sent because window_size is 0 */
4614   CU_ASSERT(0 == nghttp2_session_send(session));
4615   CU_ASSERT(32 * 1024 == ud.data_source_length);
4616
4617   /* Back 16KiB in stream window */
4618   frame.hd.stream_id = 1;
4619   frame.window_update.window_size_increment = 16 * 1024;
4620   nghttp2_session_on_window_update_received(session, &frame);
4621
4622   /* Back 24KiB in connection-level window */
4623   frame.hd.stream_id = 0;
4624   frame.window_update.window_size_increment = 24 * 1024;
4625   nghttp2_session_on_window_update_received(session, &frame);
4626
4627   /* Sends another 16KiB data */
4628   CU_ASSERT(0 == nghttp2_session_send(session));
4629   CU_ASSERT(16 * 1024 == ud.data_source_length);
4630
4631   /* Increase initial window size to 32KiB */
4632   iv[0].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
4633   iv[0].value = 32 * 1024;
4634
4635   nghttp2_frame_settings_init(&settings_frame.settings, NGHTTP2_FLAG_NONE,
4636                               dup_iv(iv, 1), 1);
4637   nghttp2_session_on_settings_received(session, &settings_frame, 1);
4638   nghttp2_frame_settings_free(&settings_frame.settings, mem);
4639
4640   /* Sends another 8KiB data */
4641   CU_ASSERT(0 == nghttp2_session_send(session));
4642   CU_ASSERT(8 * 1024 == ud.data_source_length);
4643
4644   /* Back 8KiB in connection-level window */
4645   frame.hd.stream_id = 0;
4646   frame.window_update.window_size_increment = 8 * 1024;
4647   nghttp2_session_on_window_update_received(session, &frame);
4648
4649   /* Sends last 8KiB data */
4650   CU_ASSERT(0 == nghttp2_session_send(session));
4651   CU_ASSERT(0 == ud.data_source_length);
4652   CU_ASSERT(nghttp2_session_get_stream(session, 1)->shut_flags &
4653             NGHTTP2_SHUT_WR);
4654
4655   nghttp2_frame_window_update_free(&frame.window_update);
4656   nghttp2_session_del(session);
4657 }
4658
4659 void test_nghttp2_session_flow_control_data_recv(void) {
4660   nghttp2_session *session;
4661   nghttp2_session_callbacks callbacks;
4662   uint8_t data[64 * 1024 + 16];
4663   nghttp2_frame_hd hd;
4664   nghttp2_outbound_item *item;
4665   nghttp2_stream *stream;
4666
4667   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4668   callbacks.send_callback = null_send_callback;
4669
4670   /* Initial window size to 64KiB - 1*/
4671   nghttp2_session_client_new(&session, &callbacks, NULL);
4672
4673   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
4674                                        &pri_spec_default, NGHTTP2_STREAM_OPENED,
4675                                        NULL);
4676
4677   session->next_stream_id = 3;
4678
4679   nghttp2_stream_shutdown(stream, NGHTTP2_SHUT_WR);
4680
4681   session->local_window_size = NGHTTP2_MAX_PAYLOADLEN;
4682   stream->local_window_size = NGHTTP2_MAX_PAYLOADLEN;
4683
4684   /* Create DATA frame */
4685   memset(data, 0, sizeof(data));
4686   nghttp2_frame_hd_init(&hd, NGHTTP2_MAX_PAYLOADLEN, NGHTTP2_DATA,
4687                         NGHTTP2_FLAG_END_STREAM, 1);
4688
4689   nghttp2_frame_pack_frame_hd(data, &hd);
4690   CU_ASSERT(NGHTTP2_MAX_PAYLOADLEN + NGHTTP2_FRAME_HDLEN ==
4691             nghttp2_session_mem_recv(session, data, NGHTTP2_MAX_PAYLOADLEN +
4692                                                         NGHTTP2_FRAME_HDLEN));
4693
4694   item = nghttp2_session_get_next_ob_item(session);
4695   /* Since this is the last frame, stream-level WINDOW_UPDATE is not
4696      issued, but connection-level is. */
4697   CU_ASSERT(NGHTTP2_WINDOW_UPDATE == item->frame.hd.type);
4698   CU_ASSERT(0 == item->frame.hd.stream_id);
4699   CU_ASSERT(NGHTTP2_MAX_PAYLOADLEN ==
4700             item->frame.window_update.window_size_increment);
4701
4702   CU_ASSERT(0 == nghttp2_session_send(session));
4703
4704   /* Receive DATA for closed stream. They are still subject to under
4705      connection-level flow control, since this situation arises when
4706      RST_STREAM is issued by the remote, but the local side keeps
4707      sending DATA frames. Without calculating connection-level window,
4708      the subsequent flow control gets confused. */
4709   CU_ASSERT(NGHTTP2_MAX_PAYLOADLEN + NGHTTP2_FRAME_HDLEN ==
4710             nghttp2_session_mem_recv(session, data, NGHTTP2_MAX_PAYLOADLEN +
4711                                                         NGHTTP2_FRAME_HDLEN));
4712
4713   item = nghttp2_session_get_next_ob_item(session);
4714   CU_ASSERT(NGHTTP2_WINDOW_UPDATE == item->frame.hd.type);
4715   CU_ASSERT(0 == item->frame.hd.stream_id);
4716   CU_ASSERT(NGHTTP2_MAX_PAYLOADLEN ==
4717             item->frame.window_update.window_size_increment);
4718
4719   nghttp2_session_del(session);
4720 }
4721
4722 void test_nghttp2_session_flow_control_data_with_padding_recv(void) {
4723   nghttp2_session *session;
4724   nghttp2_session_callbacks callbacks;
4725   uint8_t data[1024];
4726   nghttp2_frame_hd hd;
4727   nghttp2_stream *stream;
4728   nghttp2_option *option;
4729
4730   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4731   callbacks.send_callback = null_send_callback;
4732
4733   nghttp2_option_new(&option);
4734   /* Disable auto window update so that we can check padding is
4735      consumed automatically */
4736   nghttp2_option_set_no_auto_window_update(option, 1);
4737
4738   /* Initial window size to 64KiB - 1*/
4739   nghttp2_session_client_new2(&session, &callbacks, NULL, option);
4740
4741   nghttp2_option_del(option);
4742
4743   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
4744                                        &pri_spec_default, NGHTTP2_STREAM_OPENED,
4745                                        NULL);
4746
4747   /* Create DATA frame */
4748   memset(data, 0, sizeof(data));
4749   nghttp2_frame_hd_init(&hd, 357, NGHTTP2_DATA,
4750                         NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PADDED, 1);
4751
4752   nghttp2_frame_pack_frame_hd(data, &hd);
4753   /* Set Pad Length field, which itself is padding */
4754   data[NGHTTP2_FRAME_HDLEN] = 255;
4755
4756   CU_ASSERT(
4757       (ssize_t)(NGHTTP2_FRAME_HDLEN + hd.length) ==
4758       nghttp2_session_mem_recv(session, data, NGHTTP2_FRAME_HDLEN + hd.length));
4759
4760   CU_ASSERT((int32_t)hd.length == session->recv_window_size);
4761   CU_ASSERT((int32_t)hd.length == stream->recv_window_size);
4762   CU_ASSERT(256 == session->consumed_size);
4763   CU_ASSERT(256 == stream->consumed_size);
4764
4765   nghttp2_session_del(session);
4766 }
4767
4768 void test_nghttp2_session_data_read_temporal_failure(void) {
4769   nghttp2_session *session;
4770   nghttp2_session_callbacks callbacks;
4771   my_user_data ud;
4772   nghttp2_data_provider data_prd;
4773   nghttp2_frame frame;
4774   nghttp2_stream *stream;
4775   size_t data_size = 128 * 1024;
4776
4777   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4778   callbacks.send_callback = null_send_callback;
4779   callbacks.on_frame_send_callback = on_frame_send_callback;
4780   data_prd.read_callback = fixed_length_data_source_read_callback;
4781
4782   ud.data_source_length = data_size;
4783
4784   /* Initial window size is 64KiB - 1 */
4785   nghttp2_session_client_new(&session, &callbacks, &ud);
4786   nghttp2_submit_request(session, NULL, NULL, 0, &data_prd, NULL);
4787
4788   /* Sends NGHTTP2_INITIAL_WINDOW_SIZE data, assuming, it is equal to
4789      or smaller than NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE */
4790   CU_ASSERT(0 == nghttp2_session_send(session));
4791   CU_ASSERT(data_size - NGHTTP2_INITIAL_WINDOW_SIZE == ud.data_source_length);
4792
4793   stream = nghttp2_session_get_stream(session, 1);
4794   CU_ASSERT(nghttp2_stream_check_deferred_by_flow_control(stream));
4795   CU_ASSERT(NGHTTP2_DATA == stream->item->frame.hd.type);
4796
4797   stream->item->aux_data.data.data_prd.read_callback =
4798       temporal_failure_data_source_read_callback;
4799
4800   /* Back NGHTTP2_INITIAL_WINDOW_SIZE to both connection-level and
4801      stream-wise window */
4802   nghttp2_frame_window_update_init(&frame.window_update, NGHTTP2_FLAG_NONE, 1,
4803                                    NGHTTP2_INITIAL_WINDOW_SIZE);
4804   nghttp2_session_on_window_update_received(session, &frame);
4805   frame.hd.stream_id = 0;
4806   nghttp2_session_on_window_update_received(session, &frame);
4807   nghttp2_frame_window_update_free(&frame.window_update);
4808
4809   /* Sending data will fail (soft fail) and treated as stream error */
4810   ud.frame_send_cb_called = 0;
4811   CU_ASSERT(0 == nghttp2_session_send(session));
4812   CU_ASSERT(data_size - NGHTTP2_INITIAL_WINDOW_SIZE == ud.data_source_length);
4813
4814   CU_ASSERT(1 == ud.frame_send_cb_called);
4815   CU_ASSERT(NGHTTP2_RST_STREAM == ud.sent_frame_type);
4816
4817   data_prd.read_callback = fail_data_source_read_callback;
4818   nghttp2_submit_request(session, NULL, NULL, 0, &data_prd, NULL);
4819   /* Sending data will fail (hard fail) and session tear down */
4820   CU_ASSERT(NGHTTP2_ERR_CALLBACK_FAILURE == nghttp2_session_send(session));
4821
4822   nghttp2_session_del(session);
4823 }
4824
4825 void test_nghttp2_session_on_stream_close(void) {
4826   nghttp2_session *session;
4827   nghttp2_session_callbacks callbacks;
4828   my_user_data user_data;
4829   nghttp2_stream *stream;
4830
4831   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4832   callbacks.on_stream_close_callback = on_stream_close_callback;
4833   user_data.stream_close_cb_called = 0;
4834
4835   nghttp2_session_client_new(&session, &callbacks, &user_data);
4836   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
4837                                        &pri_spec_default, NGHTTP2_STREAM_OPENED,
4838                                        &user_data);
4839   CU_ASSERT(stream != NULL);
4840   CU_ASSERT(nghttp2_session_close_stream(session, 1, NGHTTP2_NO_ERROR) == 0);
4841   CU_ASSERT(user_data.stream_close_cb_called == 1);
4842   nghttp2_session_del(session);
4843 }
4844
4845 void test_nghttp2_session_on_ctrl_not_send(void) {
4846   nghttp2_session *session;
4847   nghttp2_session_callbacks callbacks;
4848   my_user_data user_data;
4849   nghttp2_stream *stream;
4850
4851   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4852   callbacks.on_frame_not_send_callback = on_frame_not_send_callback;
4853   callbacks.send_callback = null_send_callback;
4854   user_data.frame_not_send_cb_called = 0;
4855   user_data.not_sent_frame_type = 0;
4856   user_data.not_sent_error = 0;
4857
4858   nghttp2_session_server_new(&session, &callbacks, &user_data);
4859   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
4860                                        &pri_spec_default,
4861                                        NGHTTP2_STREAM_OPENING, &user_data);
4862
4863   /* Check response HEADERS */
4864   /* Send bogus stream ID */
4865   CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, 3,
4866                                         NULL, NULL, 0, NULL));
4867   CU_ASSERT(0 == nghttp2_session_send(session));
4868   CU_ASSERT(1 == user_data.frame_not_send_cb_called);
4869   CU_ASSERT(NGHTTP2_HEADERS == user_data.not_sent_frame_type);
4870   CU_ASSERT(NGHTTP2_ERR_STREAM_CLOSED == user_data.not_sent_error);
4871
4872   user_data.frame_not_send_cb_called = 0;
4873   /* Shutdown transmission */
4874   stream->shut_flags |= NGHTTP2_SHUT_WR;
4875   CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, 1,
4876                                         NULL, NULL, 0, NULL));
4877   CU_ASSERT(0 == nghttp2_session_send(session));
4878   CU_ASSERT(1 == user_data.frame_not_send_cb_called);
4879   CU_ASSERT(NGHTTP2_HEADERS == user_data.not_sent_frame_type);
4880   CU_ASSERT(NGHTTP2_ERR_STREAM_SHUT_WR == user_data.not_sent_error);
4881
4882   stream->shut_flags = NGHTTP2_SHUT_NONE;
4883   user_data.frame_not_send_cb_called = 0;
4884   /* Queue RST_STREAM */
4885   CU_ASSERT(0 == nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, 1,
4886                                         NULL, NULL, 0, NULL));
4887   CU_ASSERT(0 == nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, 1,
4888                                            NGHTTP2_INTERNAL_ERROR));
4889   CU_ASSERT(0 == nghttp2_session_send(session));
4890   CU_ASSERT(1 == user_data.frame_not_send_cb_called);
4891   CU_ASSERT(NGHTTP2_HEADERS == user_data.not_sent_frame_type);
4892   CU_ASSERT(NGHTTP2_ERR_STREAM_CLOSING == user_data.not_sent_error);
4893
4894   nghttp2_session_del(session);
4895
4896   /* Check request HEADERS */
4897   user_data.frame_not_send_cb_called = 0;
4898   CU_ASSERT(nghttp2_session_client_new(&session, &callbacks, &user_data) == 0);
4899   /* Maximum Stream ID is reached */
4900   session->next_stream_id = (1u << 31) + 1;
4901   CU_ASSERT(NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE ==
4902             nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, -1, NULL,
4903                                    NULL, 0, NULL));
4904
4905   user_data.frame_not_send_cb_called = 0;
4906   /* GOAWAY received */
4907   session->goaway_flags |= NGHTTP2_GOAWAY_RECV;
4908   session->next_stream_id = 9;
4909
4910   CU_ASSERT(0 < nghttp2_submit_headers(session, NGHTTP2_FLAG_END_STREAM, -1,
4911                                        NULL, NULL, 0, NULL));
4912   CU_ASSERT(0 == nghttp2_session_send(session));
4913   CU_ASSERT(1 == user_data.frame_not_send_cb_called);
4914   CU_ASSERT(NGHTTP2_HEADERS == user_data.not_sent_frame_type);
4915   CU_ASSERT(NGHTTP2_ERR_START_STREAM_NOT_ALLOWED == user_data.not_sent_error);
4916
4917   nghttp2_session_del(session);
4918 }
4919
4920 void test_nghttp2_session_get_outbound_queue_size(void) {
4921   nghttp2_session *session;
4922   nghttp2_session_callbacks callbacks;
4923
4924   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4925   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, NULL));
4926   CU_ASSERT(0 == nghttp2_session_get_outbound_queue_size(session));
4927
4928   CU_ASSERT(0 == nghttp2_submit_ping(session, NGHTTP2_FLAG_NONE, NULL));
4929   CU_ASSERT(1 == nghttp2_session_get_outbound_queue_size(session));
4930
4931   CU_ASSERT(0 == nghttp2_submit_goaway(session, NGHTTP2_FLAG_NONE, 2,
4932                                        NGHTTP2_NO_ERROR, NULL, 0));
4933   CU_ASSERT(2 == nghttp2_session_get_outbound_queue_size(session));
4934
4935   nghttp2_session_del(session);
4936 }
4937
4938 void test_nghttp2_session_get_effective_local_window_size(void) {
4939   nghttp2_session *session;
4940   nghttp2_session_callbacks callbacks;
4941   nghttp2_stream *stream;
4942
4943   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
4944   CU_ASSERT(0 == nghttp2_session_client_new(&session, &callbacks, NULL));
4945
4946   stream = nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
4947                                        &pri_spec_default, NGHTTP2_STREAM_OPENED,
4948                                        NULL);
4949
4950   CU_ASSERT(NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE ==
4951             nghttp2_session_get_effective_local_window_size(session));
4952   CU_ASSERT(0 == nghttp2_session_get_effective_recv_data_length(session));
4953
4954   CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE ==
4955             nghttp2_session_get_stream_effective_local_window_size(session, 1));
4956   CU_ASSERT(0 ==
4957             nghttp2_session_get_stream_effective_recv_data_length(session, 1));
4958
4959   /* Check connection flow control */
4960   session->recv_window_size = 100;
4961   nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 0, 1100);
4962
4963   CU_ASSERT(NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE + 1000 ==
4964             nghttp2_session_get_effective_local_window_size(session));
4965   CU_ASSERT(0 == nghttp2_session_get_effective_recv_data_length(session));
4966
4967   nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 0, -50);
4968   /* Now session->recv_window_size = -50 */
4969   CU_ASSERT(NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE + 950 ==
4970             nghttp2_session_get_effective_local_window_size(session));
4971   CU_ASSERT(0 == nghttp2_session_get_effective_recv_data_length(session));
4972
4973   session->recv_window_size += 50;
4974   /* Now session->recv_window_size = 0 */
4975   nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 0, 100);
4976   CU_ASSERT(NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE + 1050 ==
4977             nghttp2_session_get_effective_local_window_size(session));
4978   CU_ASSERT(50 == nghttp2_session_get_effective_recv_data_length(session));
4979
4980   /* Check stream flow control */
4981   stream->recv_window_size = 100;
4982   nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 1, 1100);
4983
4984   CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE + 1000 ==
4985             nghttp2_session_get_stream_effective_local_window_size(session, 1));
4986   CU_ASSERT(0 ==
4987             nghttp2_session_get_stream_effective_recv_data_length(session, 1));
4988
4989   nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 1, -50);
4990   /* Now stream->recv_window_size = -50 */
4991   CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE + 950 ==
4992             nghttp2_session_get_stream_effective_local_window_size(session, 1));
4993   CU_ASSERT(0 ==
4994             nghttp2_session_get_stream_effective_recv_data_length(session, 1));
4995
4996   stream->recv_window_size += 50;
4997   /* Now stream->recv_window_size = 0 */
4998   nghttp2_submit_window_update(session, NGHTTP2_FLAG_NONE, 1, 100);
4999   CU_ASSERT(NGHTTP2_INITIAL_WINDOW_SIZE + 1050 ==
5000             nghttp2_session_get_stream_effective_local_window_size(session, 1));
5001   CU_ASSERT(50 ==
5002             nghttp2_session_get_stream_effective_recv_data_length(session, 1));
5003
5004   nghttp2_session_del(session);
5005 }
5006
5007 void test_nghttp2_session_set_option(void) {
5008   nghttp2_session *session;
5009   nghttp2_session_callbacks callbacks;
5010   nghttp2_option *option;
5011
5012   nghttp2_option_new(&option);
5013
5014   nghttp2_option_set_no_auto_window_update(option, 1);
5015
5016   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
5017   nghttp2_session_client_new2(&session, &callbacks, NULL, option);
5018
5019   CU_ASSERT(session->opt_flags & NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE);
5020
5021   nghttp2_session_del(session);
5022
5023   nghttp2_option_set_peer_max_concurrent_streams(option, 100);
5024
5025   nghttp2_session_client_new2(&session, &callbacks, NULL, option);
5026
5027   CU_ASSERT(100 == session->remote_settings.max_concurrent_streams);
5028   nghttp2_session_del(session);
5029
5030   nghttp2_option_del(option);
5031 }
5032
5033 void test_nghttp2_session_data_backoff_by_high_pri_frame(void) {
5034   nghttp2_session *session;
5035   nghttp2_session_callbacks callbacks;
5036   my_user_data ud;
5037   nghttp2_data_provider data_prd;
5038   nghttp2_stream *stream;
5039
5040   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
5041   callbacks.send_callback = block_count_send_callback;
5042   callbacks.on_frame_send_callback = on_frame_send_callback;
5043   data_prd.read_callback = fixed_length_data_source_read_callback;
5044
5045   ud.frame_send_cb_called = 0;
5046   ud.data_source_length = NGHTTP2_DATA_PAYLOADLEN * 4;
5047
5048   nghttp2_session_client_new(&session, &callbacks, &ud);
5049   nghttp2_submit_request(session, NULL, NULL, 0, &data_prd, NULL);
5050
5051   ud.block_count = 2;
5052   /* Sends request HEADERS + DATA[0] */
5053   CU_ASSERT(0 == nghttp2_session_send(session));
5054   CU_ASSERT(NGHTTP2_DATA == ud.sent_frame_type);
5055   /* data for DATA[1] is read from data_prd but it is not sent */
5056   CU_ASSERT(ud.data_source_length == NGHTTP2_DATA_PAYLOADLEN * 2);
5057
5058   nghttp2_submit_ping(session, NGHTTP2_FLAG_NONE, NULL);
5059   ud.block_count = 2;
5060   /* Sends DATA[1] + PING, PING is interleaved in DATA sequence */
5061   CU_ASSERT(0 == nghttp2_session_send(session));
5062   CU_ASSERT(NGHTTP2_PING == ud.sent_frame_type);
5063   /* data for DATA[2] is read from data_prd but it is not sent */
5064   CU_ASSERT(ud.data_source_length == NGHTTP2_DATA_PAYLOADLEN);
5065
5066   ud.block_count = 2;
5067   /* Sends DATA[2..3] */
5068   CU_ASSERT(0 == nghttp2_session_send(session));
5069
5070   stream = nghttp2_session_get_stream(session, 1);
5071   CU_ASSERT(stream->shut_flags & NGHTTP2_SHUT_WR);
5072
5073   nghttp2_session_del(session);
5074 }
5075
5076 static void check_session_recv_data_with_padding(nghttp2_bufs *bufs,
5077                                                  size_t datalen) {
5078   nghttp2_session *session;
5079   my_user_data ud;
5080   nghttp2_session_callbacks callbacks;
5081   uint8_t *in;
5082   size_t inlen;
5083
5084   memset(&callbacks, 0, sizeof(callbacks));
5085   callbacks.on_frame_recv_callback = on_frame_recv_callback;
5086   callbacks.on_data_chunk_recv_callback = on_data_chunk_recv_callback;
5087   nghttp2_session_server_new(&session, &callbacks, &ud);
5088
5089   nghttp2_session_open_stream(session, 1, NGHTTP2_STREAM_FLAG_NONE,
5090                               &pri_spec_default, NGHTTP2_STREAM_OPENING, NULL);
5091
5092   inlen = nghttp2_bufs_remove(bufs, &in);
5093
5094   ud.frame_recv_cb_called = 0;
5095   ud.data_chunk_len = 0;
5096
5097   CU_ASSERT((ssize_t)inlen == nghttp2_session_mem_recv(session, in, inlen));
5098
5099   CU_ASSERT(1 == ud.frame_recv_cb_called);
5100   CU_ASSERT(datalen == ud.data_chunk_len);
5101
5102   free(in);
5103   nghttp2_session_del(session);
5104 }
5105
5106 void test_nghttp2_session_pack_data_with_padding(void) {
5107   nghttp2_session *session;
5108   my_user_data ud;
5109   nghttp2_session_callbacks callbacks;
5110   nghttp2_data_provider data_prd;
5111   nghttp2_frame *frame;
5112   size_t datalen = 55;
5113
5114   memset(&callbacks, 0, sizeof(callbacks));
5115   callbacks.send_callback = block_count_send_callback;
5116   callbacks.on_frame_send_callback = on_frame_send_callback;
5117   callbacks.select_padding_callback = select_padding_callback;
5118
5119   data_prd.read_callback = fixed_length_data_source_read_callback;
5120
5121   nghttp2_session_client_new(&session, &callbacks, &ud);
5122
5123   ud.padlen = 63;
5124
5125   nghttp2_submit_request(session, NULL, NULL, 0, &data_prd, NULL);
5126   ud.block_count = 1;
5127   ud.data_source_length = datalen;
5128   /* Sends HEADERS */
5129   CU_ASSERT(0 == nghttp2_session_send(session));
5130   CU_ASSERT(NGHTTP2_HEADERS == ud.sent_frame_type);
5131
5132   frame = &session->aob.item->frame;
5133
5134   CU_ASSERT(ud.padlen == frame->data.padlen);
5135   CU_ASSERT(frame->hd.flags & NGHTTP2_FLAG_PADDED);
5136
5137   /* Check reception of this DATA frame */
5138   check_session_recv_data_with_padding(&session->aob.framebufs, datalen);
5139
5140   nghttp2_session_del(session);
5141 }
5142
5143 void test_nghttp2_session_pack_headers_with_padding(void) {
5144   nghttp2_session *session, *sv_session;
5145   accumulator acc;
5146   my_user_data ud;
5147   nghttp2_session_callbacks callbacks;
5148   nghttp2_nv nv = MAKE_NV(":path", "/");
5149
5150   memset(&callbacks, 0, sizeof(callbacks));
5151   callbacks.send_callback = accumulator_send_callback;
5152   callbacks.on_frame_send_callback = on_frame_send_callback;
5153   callbacks.select_padding_callback = select_padding_callback;
5154   callbacks.on_frame_recv_callback = on_frame_recv_callback;
5155
5156   acc.length = 0;
5157   ud.acc = &acc;
5158
5159   nghttp2_session_client_new(&session, &callbacks, &ud);
5160   nghttp2_session_server_new(&sv_session, &callbacks, &ud);
5161
5162   ud.padlen = 163;
5163
5164   CU_ASSERT(1 == nghttp2_submit_request(session, NULL, &nv, 1, NULL, NULL));
5165   CU_ASSERT(0 == nghttp2_session_send(session));
5166
5167   CU_ASSERT(acc.length < NGHTTP2_MAX_PAYLOADLEN);
5168   ud.frame_recv_cb_called = 0;
5169   CU_ASSERT((ssize_t)acc.length ==
5170             nghttp2_session_mem_recv(sv_session, acc.buf, acc.length));
5171   CU_ASSERT(1 == ud.frame_recv_cb_called);
5172   CU_ASSERT(NULL == nghttp2_session_get_next_ob_item(sv_session));
5173
5174   nghttp2_session_del(sv_session);
5175   nghttp2_session_del(session);
5176 }
5177
5178 void test_nghttp2_pack_settings_payload(void) {
5179   nghttp2_settings_entry iv[2];
5180   uint8_t buf[64];
5181   ssize_t len;
5182   nghttp2_settings_entry *resiv;
5183   size_t resniv;
5184   nghttp2_mem *mem;
5185
5186   mem = nghttp2_mem_default();
5187
5188   iv[0].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
5189   iv[0].value = 1023;
5190   iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
5191   iv[1].value = 4095;
5192
5193   len = nghttp2_pack_settings_payload(buf, sizeof(buf), iv, 2);
5194   CU_ASSERT(2 * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH == len);
5195   CU_ASSERT(0 == nghttp2_frame_unpack_settings_payload2(&resiv, &resniv, buf,
5196                                                         len, mem));
5197   CU_ASSERT(2 == resniv);
5198   CU_ASSERT(NGHTTP2_SETTINGS_HEADER_TABLE_SIZE == resiv[0].settings_id);
5199   CU_ASSERT(1023 == resiv[0].value);
5200   CU_ASSERT(NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE == resiv[1].settings_id);
5201   CU_ASSERT(4095 == resiv[1].value);
5202
5203   free(resiv);
5204
5205   len = nghttp2_pack_settings_payload(buf, 9 /* too small */, iv, 2);
5206   CU_ASSERT(NGHTTP2_ERR_INSUFF_BUFSIZE == len);
5207 }
5208
5209 #define check_stream_dep_sib(STREAM, DEP_PREV, DEP_NEXT, SIB_PREV, SIB_NEXT)   \
5210   do {                                                                         \
5211     CU_ASSERT(DEP_PREV == STREAM->dep_prev);                                   \
5212     CU_ASSERT(DEP_NEXT == STREAM->dep_next);                                   \
5213     CU_ASSERT(SIB_PREV == STREAM->sib_prev);                                   \
5214     CU_ASSERT(SIB_NEXT == STREAM->sib_next);                                   \
5215   } while (0)
5216
5217 /* nghttp2_stream_dep_add() and its families functions should be
5218    tested in nghttp2_stream_test.c, but it is easier to use
5219    nghttp2_session_open_stream().  Therefore, we test them here. */
5220 void test_nghttp2_session_stream_dep_add(void) {
5221   nghttp2_session *session;
5222   nghttp2_session_callbacks callbacks;
5223   nghttp2_stream *a, *b, *c, *d, *e;
5224
5225   memset(&callbacks, 0, sizeof(callbacks));
5226
5227   nghttp2_session_server_new(&session, &callbacks, NULL);
5228
5229   a = open_stream(session, 1);
5230
5231   c = open_stream_with_dep(session, 5, a);
5232   b = open_stream_with_dep(session, 3, a);
5233   d = open_stream_with_dep(session, 7, c);
5234
5235   /* a
5236    * |
5237    * b--c
5238    *    |
5239    *    d
5240    */
5241
5242   CU_ASSERT(4 == a->num_substreams);
5243   CU_ASSERT(1 == b->num_substreams);
5244   CU_ASSERT(2 == c->num_substreams);
5245   CU_ASSERT(1 == d->num_substreams);
5246
5247   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == a->sum_dep_weight);
5248   CU_ASSERT(0 == b->sum_dep_weight);
5249   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
5250   CU_ASSERT(0 == d->sum_dep_weight);
5251
5252   check_stream_dep_sib(a, NULL, b, NULL, NULL);
5253   check_stream_dep_sib(b, a, NULL, NULL, c);
5254   check_stream_dep_sib(c, NULL, d, b, NULL);
5255   check_stream_dep_sib(d, c, NULL, NULL, NULL);
5256
5257   CU_ASSERT(4 == session->roots.num_streams);
5258   CU_ASSERT(a == session->roots.head);
5259   CU_ASSERT(NULL == a->root_next);
5260
5261   e = open_stream_with_dep_excl(session, 9, a);
5262
5263   /* a
5264    * |
5265    * e
5266    * |
5267    * b--c
5268    *    |
5269    *    d
5270    */
5271
5272   CU_ASSERT(5 == a->num_substreams);
5273   CU_ASSERT(4 == e->num_substreams);
5274   CU_ASSERT(1 == b->num_substreams);
5275   CU_ASSERT(2 == c->num_substreams);
5276   CU_ASSERT(1 == d->num_substreams);
5277
5278   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
5279   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == e->sum_dep_weight);
5280   CU_ASSERT(0 == b->sum_dep_weight);
5281   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
5282   CU_ASSERT(0 == d->sum_dep_weight);
5283
5284   check_stream_dep_sib(a, NULL, e, NULL, NULL);
5285   check_stream_dep_sib(e, a, b, NULL, NULL);
5286   check_stream_dep_sib(b, e, NULL, NULL, c);
5287   check_stream_dep_sib(c, NULL, d, b, NULL);
5288   check_stream_dep_sib(d, c, NULL, NULL, NULL);
5289
5290   CU_ASSERT(5 == session->roots.num_streams);
5291   CU_ASSERT(a == session->roots.head);
5292   CU_ASSERT(NULL == a->root_next);
5293
5294   nghttp2_session_del(session);
5295 }
5296
5297 void test_nghttp2_session_stream_dep_remove(void) {
5298   nghttp2_session *session;
5299   nghttp2_session_callbacks callbacks;
5300   nghttp2_stream *a, *b, *c, *d, *e, *f;
5301
5302   memset(&callbacks, 0, sizeof(callbacks));
5303
5304   /* Remove root */
5305   nghttp2_session_server_new(&session, &callbacks, NULL);
5306
5307   a = open_stream(session, 1);
5308   b = open_stream_with_dep(session, 3, a);
5309   c = open_stream_with_dep(session, 5, a);
5310   d = open_stream_with_dep(session, 7, c);
5311
5312   /* a
5313    * |
5314    * c--b
5315    * |
5316    * d
5317    */
5318
5319   nghttp2_stream_dep_remove(a);
5320
5321   /* becomes:
5322    * b    c
5323    *      |
5324    *      d
5325    */
5326
5327   CU_ASSERT(1 == a->num_substreams);
5328   CU_ASSERT(1 == b->num_substreams);
5329   CU_ASSERT(2 == c->num_substreams);
5330   CU_ASSERT(1 == d->num_substreams);
5331
5332   CU_ASSERT(0 == a->sum_dep_weight);
5333   CU_ASSERT(0 == b->sum_dep_weight);
5334   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
5335   CU_ASSERT(0 == d->sum_dep_weight);
5336
5337   check_stream_dep_sib(a, NULL, NULL, NULL, NULL);
5338   check_stream_dep_sib(b, NULL, NULL, NULL, NULL);
5339   check_stream_dep_sib(c, NULL, d, NULL, NULL);
5340   check_stream_dep_sib(d, c, NULL, NULL, NULL);
5341
5342   CU_ASSERT(3 == session->roots.num_streams);
5343   CU_ASSERT(b == session->roots.head);
5344   CU_ASSERT(c == b->root_next);
5345   CU_ASSERT(NULL == c->root_next);
5346
5347   nghttp2_session_del(session);
5348
5349   /* Remove left most stream */
5350   nghttp2_session_server_new(&session, &callbacks, NULL);
5351
5352   a = open_stream(session, 1);
5353   b = open_stream_with_dep(session, 3, a);
5354   c = open_stream_with_dep(session, 5, a);
5355   d = open_stream_with_dep(session, 7, c);
5356
5357   /* a
5358    * |
5359    * c--b
5360    * |
5361    * d
5362    */
5363
5364   nghttp2_stream_dep_remove(b);
5365
5366   /* becomes:
5367    * a
5368    * |
5369    * c
5370    * |
5371    * d
5372    */
5373
5374   CU_ASSERT(3 == a->num_substreams);
5375   CU_ASSERT(1 == b->num_substreams);
5376   CU_ASSERT(2 == c->num_substreams);
5377   CU_ASSERT(1 == d->num_substreams);
5378
5379   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
5380   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
5381   CU_ASSERT(0 == d->sum_dep_weight);
5382   CU_ASSERT(0 == b->sum_dep_weight);
5383
5384   check_stream_dep_sib(a, NULL, c, NULL, NULL);
5385   check_stream_dep_sib(b, NULL, NULL, NULL, NULL);
5386   check_stream_dep_sib(c, a, d, NULL, NULL);
5387   check_stream_dep_sib(d, c, NULL, NULL, NULL);
5388
5389   CU_ASSERT(3 == session->roots.num_streams);
5390   CU_ASSERT(a == session->roots.head);
5391   CU_ASSERT(NULL == a->root_next);
5392
5393   nghttp2_session_del(session);
5394
5395   /* Remove right most stream */
5396   nghttp2_session_server_new(&session, &callbacks, NULL);
5397
5398   a = open_stream(session, 1);
5399   b = open_stream_with_dep(session, 3, a);
5400   c = open_stream_with_dep(session, 5, a);
5401   d = open_stream_with_dep(session, 7, c);
5402
5403   /* a
5404    * |
5405    * c--b
5406    * |
5407    * d
5408    */
5409
5410   nghttp2_stream_dep_remove(c);
5411
5412   /* becomes:
5413    * a
5414    * |
5415    * d--b
5416    */
5417
5418   CU_ASSERT(3 == a->num_substreams);
5419   CU_ASSERT(1 == b->num_substreams);
5420   CU_ASSERT(1 == c->num_substreams);
5421   CU_ASSERT(1 == d->num_substreams);
5422
5423   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == a->sum_dep_weight);
5424   CU_ASSERT(0 == b->sum_dep_weight);
5425   CU_ASSERT(0 == d->sum_dep_weight);
5426   CU_ASSERT(0 == c->sum_dep_weight);
5427
5428   check_stream_dep_sib(a, NULL, d, NULL, NULL);
5429   check_stream_dep_sib(b, NULL, NULL, d, NULL);
5430   check_stream_dep_sib(c, NULL, NULL, NULL, NULL);
5431   check_stream_dep_sib(d, a, NULL, NULL, b);
5432
5433   nghttp2_session_del(session);
5434
5435   /* Remove middle stream */
5436   nghttp2_session_server_new(&session, &callbacks, NULL);
5437
5438   a = open_stream(session, 1);
5439   b = open_stream_with_dep(session, 3, a);
5440   c = open_stream_with_dep(session, 5, a);
5441   d = open_stream_with_dep(session, 7, a);
5442   e = open_stream_with_dep(session, 9, c);
5443   f = open_stream_with_dep(session, 11, c);
5444
5445   /* a
5446    * |
5447    * d--c--b
5448    *    |
5449    *    f--e
5450    */
5451
5452   CU_ASSERT(6 == a->num_substreams);
5453   CU_ASSERT(1 == b->num_substreams);
5454   CU_ASSERT(3 == c->num_substreams);
5455   CU_ASSERT(1 == d->num_substreams);
5456   CU_ASSERT(1 == e->num_substreams);
5457   CU_ASSERT(1 == f->num_substreams);
5458
5459   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 3 == a->sum_dep_weight);
5460   CU_ASSERT(0 == b->sum_dep_weight);
5461   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == c->sum_dep_weight);
5462   CU_ASSERT(0 == d->sum_dep_weight);
5463   CU_ASSERT(0 == e->sum_dep_weight);
5464   CU_ASSERT(0 == f->sum_dep_weight);
5465
5466   nghttp2_stream_dep_remove(c);
5467
5468   /* becomes:
5469    * a
5470    * |
5471    * d--f--e--b
5472    */
5473
5474   CU_ASSERT(5 == a->num_substreams);
5475   CU_ASSERT(1 == b->num_substreams);
5476   CU_ASSERT(1 == c->num_substreams);
5477   CU_ASSERT(1 == d->num_substreams);
5478   CU_ASSERT(1 == e->num_substreams);
5479   CU_ASSERT(1 == f->num_substreams);
5480
5481   /* c's weight 16 is distributed evenly to e and f.  Each weight of e
5482      and f becomes 8. */
5483   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 + 8 * 2 == a->sum_dep_weight);
5484   CU_ASSERT(0 == b->sum_dep_weight);
5485   CU_ASSERT(0 == c->sum_dep_weight);
5486   CU_ASSERT(0 == d->sum_dep_weight);
5487   CU_ASSERT(0 == e->sum_dep_weight);
5488   CU_ASSERT(0 == f->sum_dep_weight);
5489
5490   check_stream_dep_sib(a, NULL, d, NULL, NULL);
5491   check_stream_dep_sib(b, NULL, NULL, e, NULL);
5492   check_stream_dep_sib(c, NULL, NULL, NULL, NULL);
5493   check_stream_dep_sib(e, NULL, NULL, f, b);
5494   check_stream_dep_sib(f, NULL, NULL, d, e);
5495   check_stream_dep_sib(d, a, NULL, NULL, f);
5496
5497   nghttp2_session_del(session);
5498 }
5499
5500 void test_nghttp2_session_stream_dep_add_subtree(void) {
5501   nghttp2_session *session;
5502   nghttp2_session_callbacks callbacks;
5503   nghttp2_stream *a, *b, *c, *d, *e, *f;
5504
5505   memset(&callbacks, 0, sizeof(callbacks));
5506
5507   /* dep_stream has dep_next */
5508   nghttp2_session_server_new(&session, &callbacks, NULL);
5509
5510   a = open_stream(session, 1);
5511   b = open_stream_with_dep(session, 3, a);
5512   c = open_stream_with_dep(session, 5, a);
5513   d = open_stream_with_dep(session, 7, c);
5514
5515   e = open_stream(session, 9);
5516   f = open_stream_with_dep(session, 11, e);
5517
5518   /* a         e
5519    * |         |
5520    * c--b      f
5521    * |
5522    * d
5523    */
5524
5525   nghttp2_stream_dep_add_subtree(a, e, session);
5526
5527   /* becomes
5528    * a
5529    * |
5530    * e--c--b
5531    * |  |
5532    * f  d
5533    */
5534
5535   CU_ASSERT(6 == a->num_substreams);
5536   CU_ASSERT(1 == b->num_substreams);
5537   CU_ASSERT(2 == c->num_substreams);
5538   CU_ASSERT(1 == d->num_substreams);
5539   CU_ASSERT(2 == e->num_substreams);
5540   CU_ASSERT(1 == f->num_substreams);
5541
5542   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 3 == a->sum_dep_weight);
5543   CU_ASSERT(0 == b->sum_dep_weight);
5544   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
5545   CU_ASSERT(0 == d->sum_dep_weight);
5546   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == e->sum_dep_weight);
5547   CU_ASSERT(0 == f->sum_dep_weight);
5548
5549   check_stream_dep_sib(a, NULL, e, NULL, NULL);
5550   check_stream_dep_sib(b, NULL, NULL, c, NULL);
5551   check_stream_dep_sib(c, NULL, d, e, b);
5552   check_stream_dep_sib(d, c, NULL, NULL, NULL);
5553   check_stream_dep_sib(e, a, f, NULL, c);
5554   check_stream_dep_sib(f, e, NULL, NULL, NULL);
5555
5556   nghttp2_session_del(session);
5557
5558   /* dep_stream has dep_next and now we insert subtree */
5559   nghttp2_session_server_new(&session, &callbacks, NULL);
5560
5561   a = open_stream(session, 1);
5562   b = open_stream_with_dep(session, 3, a);
5563   c = open_stream_with_dep(session, 5, a);
5564   d = open_stream_with_dep(session, 7, c);
5565
5566   e = open_stream(session, 9);
5567   f = open_stream_with_dep(session, 11, e);
5568
5569   /* a         e
5570    * |         |
5571    * c--b      f
5572    * |
5573    * d
5574    */
5575
5576   nghttp2_stream_dep_insert_subtree(a, e, session);
5577
5578   /* becomes
5579    * a
5580    * |
5581    * e
5582    * |
5583    * f--c--b
5584    *    |
5585    *    d
5586    */
5587
5588   CU_ASSERT(6 == a->num_substreams);
5589   CU_ASSERT(1 == b->num_substreams);
5590   CU_ASSERT(2 == c->num_substreams);
5591   CU_ASSERT(1 == d->num_substreams);
5592   CU_ASSERT(5 == e->num_substreams);
5593   CU_ASSERT(1 == f->num_substreams);
5594
5595   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
5596   CU_ASSERT(0 == b->sum_dep_weight);
5597   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
5598   CU_ASSERT(0 == d->sum_dep_weight);
5599   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 3 == e->sum_dep_weight);
5600   CU_ASSERT(0 == f->sum_dep_weight);
5601
5602   check_stream_dep_sib(a, NULL, e, NULL, NULL);
5603   check_stream_dep_sib(e, a, f, NULL, NULL);
5604   check_stream_dep_sib(f, e, NULL, NULL, c);
5605   check_stream_dep_sib(b, NULL, NULL, c, NULL);
5606   check_stream_dep_sib(c, NULL, d, f, b);
5607   check_stream_dep_sib(d, c, NULL, NULL, NULL);
5608
5609   nghttp2_session_del(session);
5610 }
5611
5612 void test_nghttp2_session_stream_dep_remove_subtree(void) {
5613   nghttp2_session *session;
5614   nghttp2_session_callbacks callbacks;
5615   nghttp2_stream *a, *b, *c, *d, *e;
5616
5617   memset(&callbacks, 0, sizeof(callbacks));
5618
5619   /* Remove left most stream */
5620   nghttp2_session_server_new(&session, &callbacks, NULL);
5621
5622   a = open_stream(session, 1);
5623   b = open_stream_with_dep(session, 3, a);
5624   c = open_stream_with_dep(session, 5, a);
5625   d = open_stream_with_dep(session, 7, c);
5626
5627   /* a
5628    * |
5629    * c--b
5630    * |
5631    * d
5632    */
5633
5634   nghttp2_stream_dep_remove_subtree(c);
5635
5636   /* becomes
5637    * a  c
5638    * |  |
5639    * b  d
5640    */
5641
5642   CU_ASSERT(2 == a->num_substreams);
5643   CU_ASSERT(1 == b->num_substreams);
5644   CU_ASSERT(2 == c->num_substreams);
5645   CU_ASSERT(1 == d->num_substreams);
5646
5647   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
5648   CU_ASSERT(0 == b->sum_dep_weight);
5649   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
5650   CU_ASSERT(0 == d->sum_dep_weight);
5651
5652   check_stream_dep_sib(a, NULL, b, NULL, NULL);
5653   check_stream_dep_sib(b, a, NULL, NULL, NULL);
5654   check_stream_dep_sib(c, NULL, d, NULL, NULL);
5655   check_stream_dep_sib(d, c, NULL, NULL, NULL);
5656
5657   nghttp2_session_del(session);
5658
5659   /* Remove right most stream */
5660   nghttp2_session_server_new(&session, &callbacks, NULL);
5661
5662   a = open_stream(session, 1);
5663   b = open_stream_with_dep(session, 3, a);
5664   c = open_stream_with_dep(session, 5, a);
5665   d = open_stream_with_dep(session, 7, c);
5666
5667   /* a
5668    * |
5669    * c--b
5670    * |
5671    * d
5672    */
5673
5674   nghttp2_stream_dep_remove_subtree(b);
5675
5676   /* becomes
5677    * a  b
5678    * |
5679    * c
5680    * |
5681    * d
5682    */
5683
5684   CU_ASSERT(3 == a->num_substreams);
5685   CU_ASSERT(1 == b->num_substreams);
5686   CU_ASSERT(2 == c->num_substreams);
5687   CU_ASSERT(1 == d->num_substreams);
5688
5689   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
5690   CU_ASSERT(0 == b->sum_dep_weight);
5691   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
5692   CU_ASSERT(0 == d->sum_dep_weight);
5693
5694   check_stream_dep_sib(a, NULL, c, NULL, NULL);
5695   check_stream_dep_sib(c, a, d, NULL, NULL);
5696   check_stream_dep_sib(d, c, NULL, NULL, NULL);
5697   check_stream_dep_sib(b, NULL, NULL, NULL, NULL);
5698
5699   nghttp2_session_del(session);
5700
5701   /* Remove middle stream */
5702   nghttp2_session_server_new(&session, &callbacks, NULL);
5703
5704   a = open_stream(session, 1);
5705   e = open_stream_with_dep(session, 9, a);
5706   c = open_stream_with_dep(session, 5, a);
5707   b = open_stream_with_dep(session, 3, a);
5708   d = open_stream_with_dep(session, 7, c);
5709
5710   /* a
5711    * |
5712    * b--c--e
5713    *    |
5714    *    d
5715    */
5716
5717   nghttp2_stream_dep_remove_subtree(c);
5718
5719   /* becomes
5720    * a     c
5721    * |     |
5722    * b--e  d
5723    */
5724
5725   CU_ASSERT(3 == a->num_substreams);
5726   CU_ASSERT(1 == b->num_substreams);
5727   CU_ASSERT(1 == e->num_substreams);
5728   CU_ASSERT(2 == c->num_substreams);
5729   CU_ASSERT(1 == d->num_substreams);
5730
5731   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == a->sum_dep_weight);
5732   CU_ASSERT(0 == b->sum_dep_weight);
5733   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
5734   CU_ASSERT(0 == d->sum_dep_weight);
5735   CU_ASSERT(0 == e->sum_dep_weight);
5736
5737   check_stream_dep_sib(a, NULL, b, NULL, NULL);
5738   check_stream_dep_sib(b, a, NULL, NULL, e);
5739   check_stream_dep_sib(e, NULL, NULL, b, NULL);
5740   check_stream_dep_sib(c, NULL, d, NULL, NULL);
5741   check_stream_dep_sib(d, c, NULL, NULL, NULL);
5742
5743   nghttp2_session_del(session);
5744 }
5745
5746 void test_nghttp2_session_stream_dep_all_your_stream_are_belong_to_us(void) {
5747   nghttp2_session *session;
5748   nghttp2_session_callbacks callbacks;
5749   nghttp2_stream *a, *b, *c, *d;
5750
5751   memset(&callbacks, 0, sizeof(callbacks));
5752
5753   nghttp2_session_server_new(&session, &callbacks, NULL);
5754
5755   a = open_stream(session, 1);
5756   b = open_stream_with_dep(session, 3, a);
5757
5758   c = open_stream(session, 5);
5759
5760   /* a     c
5761    * |
5762    * b
5763    */
5764
5765   nghttp2_stream_dep_remove_subtree(c);
5766   CU_ASSERT(0 ==
5767             nghttp2_stream_dep_all_your_stream_are_belong_to_us(c, session));
5768
5769   /*
5770    * c
5771    * |
5772    * a
5773    * |
5774    * b
5775    */
5776
5777   CU_ASSERT(3 == c->num_substreams);
5778   CU_ASSERT(2 == a->num_substreams);
5779   CU_ASSERT(1 == b->num_substreams);
5780
5781   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == c->sum_dep_weight);
5782   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
5783   CU_ASSERT(0 == b->sum_dep_weight);
5784
5785   check_stream_dep_sib(c, NULL, a, NULL, NULL);
5786   check_stream_dep_sib(a, c, b, NULL, NULL);
5787   check_stream_dep_sib(b, a, NULL, NULL, NULL);
5788
5789   nghttp2_session_del(session);
5790
5791   nghttp2_session_server_new(&session, &callbacks, NULL);
5792
5793   a = open_stream(session, 1);
5794
5795   b = open_stream(session, 3);
5796
5797   c = open_stream(session, 5);
5798
5799   /*
5800    * a  b   c
5801    */
5802
5803   nghttp2_stream_dep_remove_subtree(c);
5804   CU_ASSERT(0 ==
5805             nghttp2_stream_dep_all_your_stream_are_belong_to_us(c, session));
5806
5807   /*
5808    * c
5809    * |
5810    * b--a
5811    */
5812
5813   CU_ASSERT(3 == c->num_substreams);
5814   CU_ASSERT(1 == a->num_substreams);
5815   CU_ASSERT(1 == b->num_substreams);
5816
5817   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == c->sum_dep_weight);
5818   CU_ASSERT(0 == b->sum_dep_weight);
5819   CU_ASSERT(0 == a->sum_dep_weight);
5820
5821   check_stream_dep_sib(c, NULL, b, NULL, NULL);
5822   check_stream_dep_sib(b, c, NULL, NULL, a);
5823   check_stream_dep_sib(a, NULL, NULL, b, NULL);
5824
5825   nghttp2_session_del(session);
5826
5827   nghttp2_session_server_new(&session, &callbacks, NULL);
5828
5829   a = open_stream(session, 1);
5830   b = open_stream_with_dep(session, 3, a);
5831
5832   c = open_stream(session, 5);
5833   d = open_stream_with_dep(session, 7, c);
5834
5835   /* a     c
5836    * |     |
5837    * b     d
5838    */
5839
5840   nghttp2_stream_dep_remove_subtree(c);
5841   CU_ASSERT(0 ==
5842             nghttp2_stream_dep_all_your_stream_are_belong_to_us(c, session));
5843
5844   /*
5845    * c
5846    * |
5847    * a--d
5848    * |
5849    * b
5850    */
5851
5852   CU_ASSERT(4 == c->num_substreams);
5853   CU_ASSERT(1 == d->num_substreams);
5854   CU_ASSERT(2 == a->num_substreams);
5855   CU_ASSERT(1 == b->num_substreams);
5856
5857   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT * 2 == c->sum_dep_weight);
5858   CU_ASSERT(0 == d->sum_dep_weight);
5859   CU_ASSERT(NGHTTP2_DEFAULT_WEIGHT == a->sum_dep_weight);
5860   CU_ASSERT(0 == b->sum_dep_weight);
5861
5862   check_stream_dep_sib(c, NULL, a, NULL, NULL);
5863   check_stream_dep_sib(d, NULL, NULL, a, NULL);
5864   check_stream_dep_sib(a, c, b, NULL, d);
5865   check_stream_dep_sib(b, a, NULL, NULL, NULL);
5866
5867   nghttp2_session_del(session);
5868 }
5869
5870 void test_nghttp2_session_stream_attach_item(void) {
5871   nghttp2_session *session;
5872   nghttp2_session_callbacks callbacks;
5873   nghttp2_stream *a, *b, *c, *d;
5874   nghttp2_outbound_item *da, *db, *dc, *dd;
5875
5876   memset(&callbacks, 0, sizeof(callbacks));
5877
5878   nghttp2_session_server_new(&session, &callbacks, NULL);
5879
5880   a = open_stream(session, 1);
5881   b = open_stream_with_dep(session, 3, a);
5882   c = open_stream_with_dep(session, 5, a);
5883   d = open_stream_with_dep(session, 7, c);
5884
5885   /* a
5886    * |
5887    * c--b
5888    * |
5889    * d
5890    */
5891
5892   db = create_data_ob_item();
5893
5894   nghttp2_stream_attach_item(b, db, session);
5895
5896   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
5897   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
5898   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
5899   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
5900
5901   CU_ASSERT(16 == b->effective_weight);
5902
5903   CU_ASSERT(16 == a->sum_norest_weight);
5904
5905   CU_ASSERT(1 == db->queued);
5906
5907   dc = create_data_ob_item();
5908
5909   nghttp2_stream_attach_item(c, dc, session);
5910
5911   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
5912   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
5913   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri);
5914   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
5915
5916   CU_ASSERT(16 * 16 / 32 == b->effective_weight);
5917   CU_ASSERT(16 * 16 / 32 == c->effective_weight);
5918
5919   CU_ASSERT(32 == a->sum_norest_weight);
5920
5921   CU_ASSERT(1 == dc->queued);
5922
5923   da = create_data_ob_item();
5924
5925   nghttp2_stream_attach_item(a, da, session);
5926
5927   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == a->dpri);
5928   CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == b->dpri);
5929   CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == c->dpri);
5930   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
5931
5932   CU_ASSERT(16 == a->effective_weight);
5933
5934   CU_ASSERT(1 == da->queued);
5935
5936   nghttp2_stream_detach_item(a, session);
5937
5938   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
5939   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
5940   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri);
5941   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
5942
5943   CU_ASSERT(16 * 16 / 32 == b->effective_weight);
5944   CU_ASSERT(16 * 16 / 32 == c->effective_weight);
5945
5946   dd = create_data_ob_item();
5947
5948   nghttp2_stream_attach_item(d, dd, session);
5949
5950   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
5951   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
5952   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == c->dpri);
5953   CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == d->dpri);
5954
5955   CU_ASSERT(16 * 16 / 32 == b->effective_weight);
5956   CU_ASSERT(16 * 16 / 32 == c->effective_weight);
5957
5958   CU_ASSERT(0 == dd->queued);
5959
5960   nghttp2_stream_detach_item(c, session);
5961
5962   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
5963   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
5964   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
5965   CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == d->dpri);
5966
5967   CU_ASSERT(16 * 16 / 16 == b->effective_weight);
5968
5969   CU_ASSERT(0 == dd->queued);
5970
5971   nghttp2_stream_detach_item(b, session);
5972
5973   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
5974   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == b->dpri);
5975   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
5976   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == d->dpri);
5977
5978   CU_ASSERT(16 * 16 / 16 == d->effective_weight);
5979
5980   CU_ASSERT(1 == dd->queued);
5981
5982   nghttp2_session_del(session);
5983 }
5984
5985 void test_nghttp2_session_stream_attach_item_subtree(void) {
5986   nghttp2_session *session;
5987   nghttp2_session_callbacks callbacks;
5988   nghttp2_stream *a, *b, *c, *d, *e, *f;
5989   nghttp2_outbound_item *db, *dd, *de;
5990
5991   memset(&callbacks, 0, sizeof(callbacks));
5992
5993   nghttp2_session_server_new(&session, &callbacks, NULL);
5994
5995   a = open_stream(session, 1);
5996   b = open_stream_with_dep(session, 3, a);
5997   c = open_stream_with_dep(session, 5, a);
5998   d = open_stream_with_dep(session, 7, c);
5999
6000   e = open_stream(session, 9);
6001   f = open_stream_with_dep(session, 11, e);
6002   /*
6003    * a        e
6004    * |        |
6005    * c--b     f
6006    * |
6007    * d
6008    */
6009
6010   de = create_data_ob_item();
6011
6012   nghttp2_stream_attach_item(e, de, session);
6013
6014   db = create_data_ob_item();
6015
6016   nghttp2_stream_attach_item(b, db, session);
6017
6018   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
6019   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
6020   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
6021   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
6022   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
6023   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
6024
6025   CU_ASSERT(16 == b->effective_weight);
6026   CU_ASSERT(16 == e->effective_weight);
6027
6028   /* Insert subtree e under a */
6029
6030   nghttp2_stream_dep_remove_subtree(e);
6031   nghttp2_stream_dep_insert_subtree(a, e, session);
6032
6033   /*
6034    * a
6035    * |
6036    * e
6037    * |
6038    * f--c--b
6039    *    |
6040    *    d
6041    */
6042
6043   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
6044   CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == b->dpri);
6045   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
6046   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
6047   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
6048   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
6049
6050   CU_ASSERT(16 == e->effective_weight);
6051
6052   /* Remove subtree b */
6053
6054   nghttp2_stream_dep_remove_subtree(b);
6055
6056   nghttp2_stream_dep_make_root(b, session);
6057
6058   /*
6059    * a       b
6060    * |
6061    * e
6062    * |
6063    * f--c
6064    *    |
6065    *    d
6066    */
6067
6068   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
6069   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
6070   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
6071   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
6072   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
6073   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
6074
6075   CU_ASSERT(16 == b->effective_weight);
6076   CU_ASSERT(16 == e->effective_weight);
6077
6078   /* Remove subtree a */
6079
6080   nghttp2_stream_dep_remove_subtree(a);
6081
6082   nghttp2_stream_dep_make_root(a, session);
6083
6084   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
6085   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
6086   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
6087   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
6088   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
6089   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
6090
6091   /* Remove subtree c */
6092
6093   nghttp2_stream_dep_remove_subtree(c);
6094
6095   nghttp2_stream_dep_make_root(c, session);
6096
6097   /*
6098    * a       b     c
6099    * |             |
6100    * e             d
6101    * |
6102    * f
6103    */
6104
6105   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
6106   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
6107   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
6108   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == d->dpri);
6109   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
6110   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
6111
6112   dd = create_data_ob_item();
6113
6114   nghttp2_stream_attach_item(d, dd, session);
6115
6116   /* Add subtree c to a */
6117
6118   nghttp2_stream_dep_remove_subtree(c);
6119   nghttp2_stream_dep_add_subtree(a, c, session);
6120
6121   /*
6122    * a       b
6123    * |
6124    * c--e
6125    * |  |
6126    * d  f
6127    */
6128
6129   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
6130   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
6131   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
6132   CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == d->dpri);
6133   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == e->dpri);
6134   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
6135
6136   CU_ASSERT(16 == b->effective_weight);
6137   CU_ASSERT(16 * 16 / 16 == e->effective_weight);
6138
6139   CU_ASSERT(32 == a->sum_norest_weight);
6140   CU_ASSERT(16 == c->sum_norest_weight);
6141
6142   /* Insert b under a */
6143
6144   nghttp2_stream_dep_remove_subtree(b);
6145   nghttp2_stream_dep_insert_subtree(a, b, session);
6146
6147   /*
6148    * a
6149    * |
6150    * b
6151    * |
6152    * e--c
6153    * |  |
6154    * f  d
6155    */
6156
6157   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
6158   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
6159   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
6160   CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == d->dpri);
6161   CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == e->dpri);
6162   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
6163
6164   CU_ASSERT(16 == b->effective_weight);
6165
6166   CU_ASSERT(16 == a->sum_norest_weight);
6167   CU_ASSERT(0 == b->sum_norest_weight);
6168
6169   /* Remove subtree b */
6170
6171   nghttp2_stream_dep_remove_subtree(b);
6172   nghttp2_stream_dep_make_root(b, session);
6173
6174   /*
6175    * b       a
6176    * |
6177    * e--c
6178    * |  |
6179    * f  d
6180    */
6181
6182   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == a->dpri);
6183   CU_ASSERT(NGHTTP2_STREAM_DPRI_TOP == b->dpri);
6184   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == c->dpri);
6185   CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == d->dpri);
6186   CU_ASSERT(NGHTTP2_STREAM_DPRI_REST == e->dpri);
6187   CU_ASSERT(NGHTTP2_STREAM_DPRI_NO_ITEM == f->dpri);
6188
6189   CU_ASSERT(0 == a->sum_norest_weight);
6190   CU_ASSERT(0 == b->sum_norest_weight);
6191
6192   nghttp2_session_del(session);
6193 }
6194
6195 void test_nghttp2_session_keep_closed_stream(void) {
6196   nghttp2_session *session;
6197   nghttp2_session_callbacks callbacks;
6198   const size_t max_concurrent_streams = 5;
6199   nghttp2_settings_entry iv = {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
6200                                max_concurrent_streams};
6201   size_t i;
6202
6203   memset(&callbacks, 0, sizeof(callbacks));
6204   callbacks.send_callback = null_send_callback;
6205
6206   nghttp2_session_server_new(&session, &callbacks, NULL);
6207
6208   nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, &iv, 1);
6209
6210   for (i = 0; i < max_concurrent_streams; ++i) {
6211     open_stream(session, (int)i * 2 + 1);
6212   }
6213
6214   CU_ASSERT(0 == session->num_closed_streams);
6215
6216   nghttp2_session_close_stream(session, 1, NGHTTP2_NO_ERROR);
6217
6218   CU_ASSERT(1 == session->num_closed_streams);
6219   CU_ASSERT(1 == session->closed_stream_tail->stream_id);
6220   CU_ASSERT(session->closed_stream_tail == session->closed_stream_head);
6221
6222   nghttp2_session_close_stream(session, 5, NGHTTP2_NO_ERROR);
6223
6224   CU_ASSERT(2 == session->num_closed_streams);
6225   CU_ASSERT(5 == session->closed_stream_tail->stream_id);
6226   CU_ASSERT(1 == session->closed_stream_head->stream_id);
6227   CU_ASSERT(session->closed_stream_head ==
6228             session->closed_stream_tail->closed_prev);
6229   CU_ASSERT(NULL == session->closed_stream_tail->closed_next);
6230   CU_ASSERT(session->closed_stream_tail ==
6231             session->closed_stream_head->closed_next);
6232   CU_ASSERT(NULL == session->closed_stream_head->closed_prev);
6233
6234   open_stream(session, 11);
6235
6236   CU_ASSERT(1 == session->num_closed_streams);
6237   CU_ASSERT(5 == session->closed_stream_tail->stream_id);
6238   CU_ASSERT(session->closed_stream_tail == session->closed_stream_head);
6239   CU_ASSERT(NULL == session->closed_stream_head->closed_prev);
6240   CU_ASSERT(NULL == session->closed_stream_head->closed_next);
6241
6242   open_stream(session, 13);
6243
6244   CU_ASSERT(0 == session->num_closed_streams);
6245   CU_ASSERT(NULL == session->closed_stream_tail);
6246   CU_ASSERT(NULL == session->closed_stream_head);
6247
6248   nghttp2_session_del(session);
6249 }
6250
6251 void test_nghttp2_session_keep_idle_stream(void) {
6252   nghttp2_session *session;
6253   nghttp2_session_callbacks callbacks;
6254   const size_t max_concurrent_streams = 1;
6255   nghttp2_settings_entry iv = {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
6256                                max_concurrent_streams};
6257   int i;
6258
6259   memset(&callbacks, 0, sizeof(callbacks));
6260   callbacks.send_callback = null_send_callback;
6261
6262   nghttp2_session_server_new(&session, &callbacks, NULL);
6263
6264   nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, &iv, 1);
6265
6266   /* We at least allow 2 idle streams even if max concurrent streams
6267      is very low. */
6268   for (i = 0; i < 2; ++i) {
6269     nghttp2_session_open_stream(session, i * 2 + 1, NGHTTP2_STREAM_FLAG_NONE,
6270                                 &pri_spec_default, NGHTTP2_STREAM_IDLE, NULL);
6271   }
6272
6273   CU_ASSERT(2 == session->num_idle_streams);
6274
6275   CU_ASSERT(1 == session->idle_stream_head->stream_id);
6276   CU_ASSERT(3 == session->idle_stream_tail->stream_id);
6277
6278   nghttp2_session_open_stream(session, 5, NGHTTP2_FLAG_NONE, &pri_spec_default,
6279                               NGHTTP2_STREAM_IDLE, NULL);
6280
6281   CU_ASSERT(2 == session->num_idle_streams);
6282
6283   CU_ASSERT(3 == session->idle_stream_head->stream_id);
6284   CU_ASSERT(5 == session->idle_stream_tail->stream_id);
6285
6286   nghttp2_session_del(session);
6287 }
6288
6289 void test_nghttp2_session_detach_idle_stream(void) {
6290   nghttp2_session *session;
6291   nghttp2_session_callbacks callbacks;
6292   int i;
6293   nghttp2_stream *stream;
6294
6295   memset(&callbacks, 0, sizeof(callbacks));
6296   callbacks.send_callback = null_send_callback;
6297
6298   nghttp2_session_server_new(&session, &callbacks, NULL);
6299
6300   for (i = 1; i <= 3; ++i) {
6301     nghttp2_session_open_stream(session, i, NGHTTP2_STREAM_FLAG_NONE,
6302                                 &pri_spec_default, NGHTTP2_STREAM_IDLE, NULL);
6303   }
6304
6305   CU_ASSERT(3 == session->num_idle_streams);
6306
6307   /* Detach middle stream */
6308   stream = nghttp2_session_get_stream_raw(session, 2);
6309
6310   CU_ASSERT(session->idle_stream_head == stream->closed_prev);
6311   CU_ASSERT(session->idle_stream_tail == stream->closed_next);
6312   CU_ASSERT(stream == session->idle_stream_head->closed_next);
6313   CU_ASSERT(stream == session->idle_stream_tail->closed_prev);
6314
6315   nghttp2_session_detach_idle_stream(session, stream);
6316
6317   CU_ASSERT(2 == session->num_idle_streams);
6318
6319   CU_ASSERT(NULL == stream->closed_prev);
6320   CU_ASSERT(NULL == stream->closed_next);
6321
6322   CU_ASSERT(session->idle_stream_head ==
6323             session->idle_stream_tail->closed_prev);
6324   CU_ASSERT(session->idle_stream_tail ==
6325             session->idle_stream_head->closed_next);
6326
6327   /* Detach head stream */
6328   stream = session->idle_stream_head;
6329
6330   nghttp2_session_detach_idle_stream(session, stream);
6331
6332   CU_ASSERT(1 == session->num_idle_streams);
6333
6334   CU_ASSERT(session->idle_stream_head == session->idle_stream_tail);
6335   CU_ASSERT(NULL == session->idle_stream_head->closed_prev);
6336   CU_ASSERT(NULL == session->idle_stream_head->closed_next);
6337
6338   /* Detach last stream */
6339
6340   stream = session->idle_stream_head;
6341
6342   nghttp2_session_detach_idle_stream(session, stream);
6343
6344   CU_ASSERT(0 == session->num_idle_streams);
6345
6346   CU_ASSERT(NULL == session->idle_stream_head);
6347   CU_ASSERT(NULL == session->idle_stream_tail);
6348
6349   for (i = 4; i <= 5; ++i) {
6350     nghttp2_session_open_stream(session, i, NGHTTP2_STREAM_FLAG_NONE,
6351                                 &pri_spec_default, NGHTTP2_STREAM_IDLE, NULL);
6352   }
6353
6354   CU_ASSERT(2 == session->num_idle_streams);
6355
6356   /* Detach tail stream */
6357
6358   stream = session->idle_stream_tail;
6359
6360   nghttp2_session_detach_idle_stream(session, stream);
6361
6362   CU_ASSERT(1 == session->num_idle_streams);
6363
6364   CU_ASSERT(session->idle_stream_head == session->idle_stream_tail);
6365   CU_ASSERT(NULL == session->idle_stream_head->closed_prev);
6366   CU_ASSERT(NULL == session->idle_stream_head->closed_next);
6367
6368   nghttp2_session_del(session);
6369 }
6370
6371 void test_nghttp2_session_large_dep_tree(void) {
6372   nghttp2_session *session;
6373   nghttp2_session_callbacks callbacks;
6374   size_t i;
6375   nghttp2_stream *dep_stream = NULL;
6376   nghttp2_stream *root_stream;
6377   int32_t stream_id;
6378
6379   memset(&callbacks, 0, sizeof(callbacks));
6380   callbacks.send_callback = null_send_callback;
6381
6382   nghttp2_session_server_new(&session, &callbacks, NULL);
6383
6384   stream_id = 1;
6385   for (i = 0; i < NGHTTP2_MAX_DEP_TREE_LENGTH; ++i) {
6386     dep_stream = open_stream_with_dep(session, stream_id, dep_stream);
6387     stream_id += 2;
6388   }
6389
6390   root_stream = nghttp2_session_get_stream(session, 1);
6391
6392   /* Check that last dep_stream must be part of tree */
6393   CU_ASSERT(nghttp2_stream_dep_subtree_find(root_stream, dep_stream));
6394
6395   dep_stream = open_stream_with_dep(session, stream_id, dep_stream);
6396
6397   /* We exceeded NGHTTP2_MAX_DEP_TREE_LENGTH limit.  dep_stream is now
6398      root node and has no descendants. */
6399   CU_ASSERT(!nghttp2_stream_dep_subtree_find(root_stream, dep_stream));
6400   CU_ASSERT(nghttp2_stream_in_dep_tree(dep_stream));
6401
6402   nghttp2_session_del(session);
6403 }
6404
6405 void test_nghttp2_session_graceful_shutdown(void) {
6406   nghttp2_session *session;
6407   nghttp2_session_callbacks callbacks;
6408   my_user_data ud;
6409
6410   memset(&callbacks, 0, sizeof(callbacks));
6411   callbacks.send_callback = null_send_callback;
6412   callbacks.on_frame_send_callback = on_frame_send_callback;
6413   callbacks.on_stream_close_callback = on_stream_close_callback;
6414
6415   nghttp2_session_server_new(&session, &callbacks, &ud);
6416
6417   open_stream(session, 301);
6418   open_stream(session, 302);
6419   open_stream(session, 309);
6420   open_stream(session, 311);
6421   open_stream(session, 319);
6422
6423   CU_ASSERT(0 == nghttp2_submit_shutdown_notice(session));
6424
6425   ud.frame_send_cb_called = 0;
6426
6427   CU_ASSERT(0 == nghttp2_session_send(session));
6428
6429   CU_ASSERT(1 == ud.frame_send_cb_called);
6430   CU_ASSERT((1u << 31) - 1 == session->local_last_stream_id);
6431
6432   CU_ASSERT(0 == nghttp2_submit_goaway(session, NGHTTP2_FLAG_NONE, 311,
6433                                        NGHTTP2_NO_ERROR, NULL, 0));
6434
6435   ud.frame_send_cb_called = 0;
6436   ud.stream_close_cb_called = 0;
6437
6438   CU_ASSERT(0 == nghttp2_session_send(session));
6439
6440   CU_ASSERT(1 == ud.frame_send_cb_called);
6441   CU_ASSERT(311 == session->local_last_stream_id);
6442   CU_ASSERT(1 == ud.stream_close_cb_called);
6443
6444   CU_ASSERT(0 ==
6445             nghttp2_session_terminate_session2(session, 301, NGHTTP2_NO_ERROR));
6446
6447   ud.frame_send_cb_called = 0;
6448   ud.stream_close_cb_called = 0;
6449
6450   CU_ASSERT(0 == nghttp2_session_send(session));
6451
6452   CU_ASSERT(1 == ud.frame_send_cb_called);
6453   CU_ASSERT(301 == session->local_last_stream_id);
6454   CU_ASSERT(2 == ud.stream_close_cb_called);
6455
6456   CU_ASSERT(NULL != nghttp2_session_get_stream(session, 301));
6457   CU_ASSERT(NULL != nghttp2_session_get_stream(session, 302));
6458   CU_ASSERT(NULL == nghttp2_session_get_stream(session, 309));
6459   CU_ASSERT(NULL == nghttp2_session_get_stream(session, 311));
6460   CU_ASSERT(NULL == nghttp2_session_get_stream(session, 319));
6461
6462   nghttp2_session_del(session);
6463 }
6464
6465 void test_nghttp2_session_on_header_temporal_failure(void) {
6466   nghttp2_session *session;
6467   nghttp2_session_callbacks callbacks;
6468   my_user_data ud;
6469   nghttp2_bufs bufs;
6470   nghttp2_buf *buf;
6471   nghttp2_hd_deflater deflater;
6472   nghttp2_nv nv[] = {MAKE_NV("alpha", "bravo"), MAKE_NV("charlie", "delta")};
6473   nghttp2_nv *nva;
6474   size_t hdpos;
6475   ssize_t rv;
6476   nghttp2_frame frame;
6477   nghttp2_frame_hd hd;
6478   nghttp2_outbound_item *item;
6479   nghttp2_mem *mem;
6480
6481   mem = nghttp2_mem_default();
6482   memset(&callbacks, 0, sizeof(callbacks));
6483   callbacks.on_header_callback = temporal_failure_on_header_callback;
6484
6485   nghttp2_session_server_new(&session, &callbacks, &ud);
6486
6487   frame_pack_bufs_init(&bufs);
6488
6489   nghttp2_hd_deflate_init(&deflater, mem);
6490
6491   nghttp2_nv_array_copy(&nva, nv, 1, mem);
6492
6493   nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_STREAM, 1,
6494                              NGHTTP2_HCAT_REQUEST, NULL, nva, 1);
6495   nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
6496   nghttp2_frame_headers_free(&frame.headers, mem);
6497
6498   /* We are going to create CONTINUATION.  First serialize header
6499      block, and then frame header. */
6500   hdpos = nghttp2_bufs_len(&bufs);
6501
6502   buf = &bufs.head->buf;
6503   buf->last += NGHTTP2_FRAME_HDLEN;
6504
6505   nghttp2_hd_deflate_hd_bufs(&deflater, &bufs, &nv[1], 1);
6506
6507   nghttp2_frame_hd_init(&hd,
6508                         nghttp2_bufs_len(&bufs) - hdpos - NGHTTP2_FRAME_HDLEN,
6509                         NGHTTP2_CONTINUATION, NGHTTP2_FLAG_END_HEADERS, 1);
6510
6511   nghttp2_frame_pack_frame_hd(&buf->pos[hdpos], &hd);
6512
6513   rv = nghttp2_session_mem_recv(session, buf->pos, nghttp2_bufs_len(&bufs));
6514
6515   CU_ASSERT(rv == nghttp2_bufs_len(&bufs));
6516
6517   item = nghttp2_session_get_next_ob_item(session);
6518
6519   CU_ASSERT(NGHTTP2_RST_STREAM == item->frame.hd.type);
6520
6521   /* Make sure no header decompression error occurred */
6522   CU_ASSERT(NGHTTP2_GOAWAY_NONE == session->goaway_flags);
6523
6524   nghttp2_bufs_free(&bufs);
6525
6526   nghttp2_hd_deflate_free(&deflater);
6527   nghttp2_session_del(session);
6528 }
6529
6530 void test_nghttp2_session_recv_client_preface(void) {
6531   nghttp2_session *session;
6532   nghttp2_session_callbacks callbacks;
6533   nghttp2_option *option;
6534   ssize_t rv;
6535   nghttp2_frame ping_frame;
6536   uint8_t buf[16];
6537
6538   memset(&callbacks, 0, sizeof(callbacks));
6539
6540   nghttp2_option_new(&option);
6541   nghttp2_option_set_recv_client_preface(option, 1);
6542
6543   /* Check success case */
6544   nghttp2_session_server_new2(&session, &callbacks, NULL, option);
6545
6546   CU_ASSERT(session->opt_flags & NGHTTP2_OPTMASK_RECV_CLIENT_PREFACE);
6547
6548   rv = nghttp2_session_mem_recv(
6549       session, (const uint8_t *)NGHTTP2_CLIENT_CONNECTION_PREFACE,
6550       NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
6551
6552   CU_ASSERT(rv == NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
6553   CU_ASSERT(NGHTTP2_IB_READ_FIRST_SETTINGS == session->iframe.state);
6554
6555   /* Receiving PING is error */
6556   nghttp2_frame_ping_init(&ping_frame.ping, NGHTTP2_FLAG_NONE, NULL);
6557
6558   nghttp2_frame_pack_frame_hd(buf, &ping_frame.ping.hd);
6559
6560   rv = nghttp2_session_mem_recv(session, buf, NGHTTP2_FRAME_HDLEN);
6561   CU_ASSERT(NGHTTP2_FRAME_HDLEN == rv);
6562   CU_ASSERT(NGHTTP2_IB_IGN_PAYLOAD == session->iframe.state);
6563   CU_ASSERT(8 == session->iframe.payloadleft);
6564
6565   nghttp2_frame_ping_free(&ping_frame.ping);
6566
6567   nghttp2_session_del(session);
6568
6569   /* Check bad case */
6570   nghttp2_session_server_new2(&session, &callbacks, NULL, option);
6571
6572   /* Feed preface with one byte less */
6573   rv = nghttp2_session_mem_recv(
6574       session, (const uint8_t *)NGHTTP2_CLIENT_CONNECTION_PREFACE,
6575       NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - 1);
6576
6577   CU_ASSERT(rv == NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - 1);
6578   CU_ASSERT(NGHTTP2_IB_READ_CLIENT_PREFACE == session->iframe.state);
6579   CU_ASSERT(1 == session->iframe.payloadleft);
6580
6581   rv = nghttp2_session_mem_recv(session, (const uint8_t *)"\0", 1);
6582
6583   CU_ASSERT(NGHTTP2_ERR_BAD_PREFACE == rv);
6584
6585   nghttp2_session_del(session);
6586
6587   nghttp2_option_del(option);
6588 }
6589
6590 void test_nghttp2_session_delete_data_item(void) {
6591   nghttp2_session *session;
6592   nghttp2_session_callbacks callbacks;
6593   nghttp2_stream *a;
6594   nghttp2_data_provider prd;
6595
6596   memset(&callbacks, 0, sizeof(callbacks));
6597
6598   nghttp2_session_server_new(&session, &callbacks, NULL);
6599
6600   a = open_stream(session, 1);
6601   open_stream_with_dep(session, 3, a);
6602
6603   /* We don't care about these members, since we won't send data */
6604   prd.source.ptr = NULL;
6605   prd.read_callback = fail_data_source_read_callback;
6606
6607   /* This data item will be marked as TOP */
6608   CU_ASSERT(0 == nghttp2_submit_data(session, NGHTTP2_FLAG_NONE, 1, &prd));
6609   /* This data item will be marked as REST */
6610   CU_ASSERT(0 == nghttp2_submit_data(session, NGHTTP2_FLAG_NONE, 3, &prd));
6611
6612   nghttp2_session_del(session);
6613 }
6614
6615 void test_nghttp2_session_open_idle_stream(void) {
6616   nghttp2_session *session;
6617   nghttp2_session_callbacks callbacks;
6618   nghttp2_stream *stream;
6619   nghttp2_stream *opened_stream;
6620   nghttp2_priority_spec pri_spec;
6621   nghttp2_frame frame;
6622
6623   memset(&callbacks, 0, sizeof(nghttp2_session_callbacks));
6624
6625   nghttp2_session_server_new(&session, &callbacks, NULL);
6626
6627   nghttp2_priority_spec_init(&pri_spec, 0, 3, 0);
6628
6629   nghttp2_frame_priority_init(&frame.priority, 1, &pri_spec);
6630
6631   CU_ASSERT(0 == nghttp2_session_on_priority_received(session, &frame));
6632
6633   stream = nghttp2_session_get_stream_raw(session, 1);
6634
6635   CU_ASSERT(NGHTTP2_STREAM_IDLE == stream->state);
6636   CU_ASSERT(NULL == stream->closed_prev);
6637   CU_ASSERT(NULL == stream->closed_next);
6638   CU_ASSERT(1 == session->num_idle_streams);
6639   CU_ASSERT(session->idle_stream_head == stream);
6640   CU_ASSERT(session->idle_stream_tail == stream);
6641
6642   opened_stream = nghttp2_session_open_stream(
6643       session, 1, NGHTTP2_STREAM_FLAG_NONE, &pri_spec_default,
6644       NGHTTP2_STREAM_OPENING, NULL);
6645
6646   CU_ASSERT(stream == opened_stream);
6647   CU_ASSERT(NGHTTP2_STREAM_OPENING == stream->state);
6648   CU_ASSERT(0 == session->num_idle_streams);
6649   CU_ASSERT(NULL == session->idle_stream_head);
6650   CU_ASSERT(NULL == session->idle_stream_tail);
6651
6652   nghttp2_frame_priority_free(&frame.priority);
6653
6654   nghttp2_session_del(session);
6655 }