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