Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Kitware
GitHub Repository: Kitware/CMake
Path: blob/master/Utilities/cmnghttp2/lib/nghttp2_submit.c
3153 views
1
/*
2
* nghttp2 - HTTP/2 C Library
3
*
4
* Copyright (c) 2012, 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_submit.h"
26
27
#include <string.h>
28
#include <assert.h>
29
30
#include "nghttp2_session.h"
31
#include "nghttp2_frame.h"
32
#include "nghttp2_helper.h"
33
#include "nghttp2_priority_spec.h"
34
35
/*
36
* Detects the dependency error, that is stream attempted to depend on
37
* itself. If |stream_id| is -1, we use session->next_stream_id as
38
* stream ID.
39
*
40
* This function returns 0 if it succeeds, or one of the following
41
* error codes:
42
*
43
* NGHTTP2_ERR_INVALID_ARGUMENT
44
* Stream attempted to depend on itself.
45
*/
46
static int detect_self_dependency(nghttp2_session *session, int32_t stream_id,
47
const nghttp2_priority_spec *pri_spec) {
48
assert(pri_spec);
49
50
if (stream_id == -1) {
51
if ((int32_t)session->next_stream_id == pri_spec->stream_id) {
52
return NGHTTP2_ERR_INVALID_ARGUMENT;
53
}
54
return 0;
55
}
56
57
if (stream_id == pri_spec->stream_id) {
58
return NGHTTP2_ERR_INVALID_ARGUMENT;
59
}
60
61
return 0;
62
}
63
64
/* This function takes ownership of |nva_copy|. Regardless of the
65
return value, the caller must not free |nva_copy| after this
66
function returns. */
67
static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
68
int32_t stream_id,
69
const nghttp2_priority_spec *pri_spec,
70
nghttp2_nv *nva_copy, size_t nvlen,
71
const nghttp2_data_provider *data_prd,
72
void *stream_user_data) {
73
int rv;
74
uint8_t flags_copy;
75
nghttp2_outbound_item *item = NULL;
76
nghttp2_frame *frame = NULL;
77
nghttp2_headers_category hcat;
78
nghttp2_mem *mem;
79
80
mem = &session->mem;
81
82
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
83
if (item == NULL) {
84
rv = NGHTTP2_ERR_NOMEM;
85
goto fail;
86
}
87
88
nghttp2_outbound_item_init(item);
89
90
if (data_prd != NULL && data_prd->read_callback != NULL) {
91
item->aux_data.headers.data_prd = *data_prd;
92
}
93
94
item->aux_data.headers.stream_user_data = stream_user_data;
95
96
flags_copy =
97
(uint8_t)((flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) |
98
NGHTTP2_FLAG_END_HEADERS);
99
100
if (stream_id == -1) {
101
if (session->next_stream_id > INT32_MAX) {
102
rv = NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE;
103
goto fail;
104
}
105
106
stream_id = (int32_t)session->next_stream_id;
107
session->next_stream_id += 2;
108
109
hcat = NGHTTP2_HCAT_REQUEST;
110
} else {
111
/* More specific categorization will be done later. */
112
hcat = NGHTTP2_HCAT_HEADERS;
113
}
114
115
frame = &item->frame;
116
117
nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, hcat,
118
pri_spec, nva_copy, nvlen);
119
120
rv = nghttp2_session_add_item(session, item);
121
122
if (rv != 0) {
123
nghttp2_frame_headers_free(&frame->headers, mem);
124
goto fail2;
125
}
126
127
if (hcat == NGHTTP2_HCAT_REQUEST) {
128
return stream_id;
129
}
130
131
return 0;
132
133
fail:
134
/* nghttp2_frame_headers_init() takes ownership of nva_copy. */
135
nghttp2_nv_array_del(nva_copy, mem);
136
fail2:
137
nghttp2_mem_free(mem, item);
138
139
return rv;
140
}
141
142
static int32_t submit_headers_shared_nva(nghttp2_session *session,
143
uint8_t flags, int32_t stream_id,
144
const nghttp2_priority_spec *pri_spec,
145
const nghttp2_nv *nva, size_t nvlen,
146
const nghttp2_data_provider *data_prd,
147
void *stream_user_data) {
148
int rv;
149
nghttp2_nv *nva_copy;
150
nghttp2_priority_spec copy_pri_spec;
151
nghttp2_mem *mem;
152
153
mem = &session->mem;
154
155
if (pri_spec) {
156
copy_pri_spec = *pri_spec;
157
nghttp2_priority_spec_normalize_weight(&copy_pri_spec);
158
} else {
159
nghttp2_priority_spec_default_init(&copy_pri_spec);
160
}
161
162
rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen, mem);
163
if (rv < 0) {
164
return rv;
165
}
166
167
return submit_headers_shared(session, flags, stream_id, &copy_pri_spec,
168
nva_copy, nvlen, data_prd, stream_user_data);
169
}
170
171
int nghttp2_submit_trailer(nghttp2_session *session, int32_t stream_id,
172
const nghttp2_nv *nva, size_t nvlen) {
173
if (stream_id <= 0) {
174
return NGHTTP2_ERR_INVALID_ARGUMENT;
175
}
176
177
return (int)submit_headers_shared_nva(session, NGHTTP2_FLAG_END_STREAM,
178
stream_id, NULL, nva, nvlen, NULL,
179
NULL);
180
}
181
182
int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
183
int32_t stream_id,
184
const nghttp2_priority_spec *pri_spec,
185
const nghttp2_nv *nva, size_t nvlen,
186
void *stream_user_data) {
187
int rv;
188
189
if (stream_id == -1) {
190
if (session->server) {
191
return NGHTTP2_ERR_PROTO;
192
}
193
} else if (stream_id <= 0) {
194
return NGHTTP2_ERR_INVALID_ARGUMENT;
195
}
196
197
flags &= NGHTTP2_FLAG_END_STREAM;
198
199
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
200
session->remote_settings.no_rfc7540_priorities != 1) {
201
rv = detect_self_dependency(session, stream_id, pri_spec);
202
if (rv != 0) {
203
return rv;
204
}
205
206
flags |= NGHTTP2_FLAG_PRIORITY;
207
} else {
208
pri_spec = NULL;
209
}
210
211
return submit_headers_shared_nva(session, flags, stream_id, pri_spec, nva,
212
nvlen, NULL, stream_user_data);
213
}
214
215
int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
216
const uint8_t *opaque_data) {
217
flags &= NGHTTP2_FLAG_ACK;
218
return nghttp2_session_add_ping(session, flags, opaque_data);
219
}
220
221
int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
222
int32_t stream_id,
223
const nghttp2_priority_spec *pri_spec) {
224
int rv;
225
nghttp2_outbound_item *item;
226
nghttp2_frame *frame;
227
nghttp2_priority_spec copy_pri_spec;
228
nghttp2_mem *mem;
229
(void)flags;
230
231
mem = &session->mem;
232
233
if (session->remote_settings.no_rfc7540_priorities == 1) {
234
return 0;
235
}
236
237
if (stream_id == 0 || pri_spec == NULL) {
238
return NGHTTP2_ERR_INVALID_ARGUMENT;
239
}
240
241
if (stream_id == pri_spec->stream_id) {
242
return NGHTTP2_ERR_INVALID_ARGUMENT;
243
}
244
245
copy_pri_spec = *pri_spec;
246
247
nghttp2_priority_spec_normalize_weight(&copy_pri_spec);
248
249
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
250
251
if (item == NULL) {
252
return NGHTTP2_ERR_NOMEM;
253
}
254
255
nghttp2_outbound_item_init(item);
256
257
frame = &item->frame;
258
259
nghttp2_frame_priority_init(&frame->priority, stream_id, &copy_pri_spec);
260
261
rv = nghttp2_session_add_item(session, item);
262
263
if (rv != 0) {
264
nghttp2_frame_priority_free(&frame->priority);
265
nghttp2_mem_free(mem, item);
266
267
return rv;
268
}
269
270
return 0;
271
}
272
273
int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
274
int32_t stream_id, uint32_t error_code) {
275
(void)flags;
276
277
if (stream_id == 0) {
278
return NGHTTP2_ERR_INVALID_ARGUMENT;
279
}
280
281
return nghttp2_session_add_rst_stream(session, stream_id, error_code);
282
}
283
284
int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags,
285
int32_t last_stream_id, uint32_t error_code,
286
const uint8_t *opaque_data, size_t opaque_data_len) {
287
(void)flags;
288
289
if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) {
290
return 0;
291
}
292
return nghttp2_session_add_goaway(session, last_stream_id, error_code,
293
opaque_data, opaque_data_len,
294
NGHTTP2_GOAWAY_AUX_NONE);
295
}
296
297
int nghttp2_submit_shutdown_notice(nghttp2_session *session) {
298
if (!session->server) {
299
return NGHTTP2_ERR_INVALID_STATE;
300
}
301
if (session->goaway_flags) {
302
return 0;
303
}
304
return nghttp2_session_add_goaway(session, (1u << 31) - 1, NGHTTP2_NO_ERROR,
305
NULL, 0,
306
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE);
307
}
308
309
int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags,
310
const nghttp2_settings_entry *iv, size_t niv) {
311
(void)flags;
312
return nghttp2_session_add_settings(session, NGHTTP2_FLAG_NONE, iv, niv);
313
}
314
315
int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
316
int32_t stream_id, const nghttp2_nv *nva,
317
size_t nvlen,
318
void *promised_stream_user_data) {
319
nghttp2_outbound_item *item;
320
nghttp2_frame *frame;
321
nghttp2_nv *nva_copy;
322
uint8_t flags_copy;
323
int32_t promised_stream_id;
324
int rv;
325
nghttp2_mem *mem;
326
(void)flags;
327
328
mem = &session->mem;
329
330
if (stream_id <= 0 || nghttp2_session_is_my_stream_id(session, stream_id)) {
331
return NGHTTP2_ERR_INVALID_ARGUMENT;
332
}
333
334
if (!session->server) {
335
return NGHTTP2_ERR_PROTO;
336
}
337
338
/* All 32bit signed stream IDs are spent. */
339
if (session->next_stream_id > INT32_MAX) {
340
return NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE;
341
}
342
343
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
344
if (item == NULL) {
345
return NGHTTP2_ERR_NOMEM;
346
}
347
348
nghttp2_outbound_item_init(item);
349
350
item->aux_data.headers.stream_user_data = promised_stream_user_data;
351
352
frame = &item->frame;
353
354
rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen, mem);
355
if (rv < 0) {
356
nghttp2_mem_free(mem, item);
357
return rv;
358
}
359
360
flags_copy = NGHTTP2_FLAG_END_HEADERS;
361
362
promised_stream_id = (int32_t)session->next_stream_id;
363
session->next_stream_id += 2;
364
365
nghttp2_frame_push_promise_init(&frame->push_promise, flags_copy, stream_id,
366
promised_stream_id, nva_copy, nvlen);
367
368
rv = nghttp2_session_add_item(session, item);
369
370
if (rv != 0) {
371
nghttp2_frame_push_promise_free(&frame->push_promise, mem);
372
nghttp2_mem_free(mem, item);
373
374
return rv;
375
}
376
377
return promised_stream_id;
378
}
379
380
int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
381
int32_t stream_id,
382
int32_t window_size_increment) {
383
int rv;
384
nghttp2_stream *stream = 0;
385
(void)flags;
386
387
if (window_size_increment == 0) {
388
return 0;
389
}
390
if (stream_id == 0) {
391
rv = nghttp2_adjust_local_window_size(
392
&session->local_window_size, &session->recv_window_size,
393
&session->recv_reduction, &window_size_increment);
394
if (rv != 0) {
395
return rv;
396
}
397
} else {
398
stream = nghttp2_session_get_stream(session, stream_id);
399
if (!stream) {
400
return 0;
401
}
402
403
rv = nghttp2_adjust_local_window_size(
404
&stream->local_window_size, &stream->recv_window_size,
405
&stream->recv_reduction, &window_size_increment);
406
if (rv != 0) {
407
return rv;
408
}
409
}
410
411
if (window_size_increment > 0) {
412
if (stream_id == 0) {
413
session->consumed_size =
414
nghttp2_max(0, session->consumed_size - window_size_increment);
415
} else {
416
stream->consumed_size =
417
nghttp2_max(0, stream->consumed_size - window_size_increment);
418
}
419
420
return nghttp2_session_add_window_update(session, 0, stream_id,
421
window_size_increment);
422
}
423
return 0;
424
}
425
426
int nghttp2_session_set_local_window_size(nghttp2_session *session,
427
uint8_t flags, int32_t stream_id,
428
int32_t window_size) {
429
int32_t window_size_increment;
430
nghttp2_stream *stream;
431
int rv;
432
(void)flags;
433
434
if (window_size < 0) {
435
return NGHTTP2_ERR_INVALID_ARGUMENT;
436
}
437
438
if (stream_id == 0) {
439
window_size_increment = window_size - session->local_window_size;
440
441
if (window_size_increment == 0) {
442
return 0;
443
}
444
445
if (window_size_increment < 0) {
446
return nghttp2_adjust_local_window_size(
447
&session->local_window_size, &session->recv_window_size,
448
&session->recv_reduction, &window_size_increment);
449
}
450
451
rv = nghttp2_increase_local_window_size(
452
&session->local_window_size, &session->recv_window_size,
453
&session->recv_reduction, &window_size_increment);
454
455
if (rv != 0) {
456
return rv;
457
}
458
459
if (window_size_increment > 0) {
460
return nghttp2_session_add_window_update(session, 0, stream_id,
461
window_size_increment);
462
}
463
464
return nghttp2_session_update_recv_connection_window_size(session, 0);
465
} else {
466
stream = nghttp2_session_get_stream(session, stream_id);
467
468
if (stream == NULL) {
469
return 0;
470
}
471
472
window_size_increment = window_size - stream->local_window_size;
473
474
if (window_size_increment == 0) {
475
return 0;
476
}
477
478
if (window_size_increment < 0) {
479
return nghttp2_adjust_local_window_size(
480
&stream->local_window_size, &stream->recv_window_size,
481
&stream->recv_reduction, &window_size_increment);
482
}
483
484
rv = nghttp2_increase_local_window_size(
485
&stream->local_window_size, &stream->recv_window_size,
486
&stream->recv_reduction, &window_size_increment);
487
488
if (rv != 0) {
489
return rv;
490
}
491
492
if (window_size_increment > 0) {
493
return nghttp2_session_add_window_update(session, 0, stream_id,
494
window_size_increment);
495
}
496
497
return nghttp2_session_update_recv_stream_window_size(session, stream, 0,
498
1);
499
}
500
}
501
502
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
503
int32_t stream_id, const uint8_t *origin,
504
size_t origin_len, const uint8_t *field_value,
505
size_t field_value_len) {
506
nghttp2_mem *mem;
507
uint8_t *buf, *p;
508
uint8_t *origin_copy;
509
uint8_t *field_value_copy;
510
nghttp2_outbound_item *item;
511
nghttp2_frame *frame;
512
nghttp2_ext_altsvc *altsvc;
513
int rv;
514
(void)flags;
515
516
mem = &session->mem;
517
518
if (!session->server) {
519
return NGHTTP2_ERR_INVALID_STATE;
520
}
521
522
if (2 + origin_len + field_value_len > NGHTTP2_MAX_PAYLOADLEN) {
523
return NGHTTP2_ERR_INVALID_ARGUMENT;
524
}
525
526
if (stream_id == 0) {
527
if (origin_len == 0) {
528
return NGHTTP2_ERR_INVALID_ARGUMENT;
529
}
530
} else if (origin_len != 0) {
531
return NGHTTP2_ERR_INVALID_ARGUMENT;
532
}
533
534
buf = nghttp2_mem_malloc(mem, origin_len + field_value_len + 2);
535
if (buf == NULL) {
536
return NGHTTP2_ERR_NOMEM;
537
}
538
539
p = buf;
540
541
origin_copy = p;
542
if (origin_len) {
543
p = nghttp2_cpymem(p, origin, origin_len);
544
}
545
*p++ = '\0';
546
547
field_value_copy = p;
548
if (field_value_len) {
549
p = nghttp2_cpymem(p, field_value, field_value_len);
550
}
551
*p++ = '\0';
552
553
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
554
if (item == NULL) {
555
rv = NGHTTP2_ERR_NOMEM;
556
goto fail_item_malloc;
557
}
558
559
nghttp2_outbound_item_init(item);
560
561
item->aux_data.ext.builtin = 1;
562
563
altsvc = &item->ext_frame_payload.altsvc;
564
565
frame = &item->frame;
566
frame->ext.payload = altsvc;
567
568
nghttp2_frame_altsvc_init(&frame->ext, stream_id, origin_copy, origin_len,
569
field_value_copy, field_value_len);
570
571
rv = nghttp2_session_add_item(session, item);
572
if (rv != 0) {
573
nghttp2_frame_altsvc_free(&frame->ext, mem);
574
nghttp2_mem_free(mem, item);
575
576
return rv;
577
}
578
579
return 0;
580
581
fail_item_malloc:
582
free(buf);
583
584
return rv;
585
}
586
587
int nghttp2_submit_origin(nghttp2_session *session, uint8_t flags,
588
const nghttp2_origin_entry *ov, size_t nov) {
589
nghttp2_mem *mem;
590
uint8_t *p;
591
nghttp2_outbound_item *item;
592
nghttp2_frame *frame;
593
nghttp2_ext_origin *origin;
594
nghttp2_origin_entry *ov_copy;
595
size_t len = 0;
596
size_t i;
597
int rv;
598
(void)flags;
599
600
mem = &session->mem;
601
602
if (!session->server) {
603
return NGHTTP2_ERR_INVALID_STATE;
604
}
605
606
if (nov) {
607
for (i = 0; i < nov; ++i) {
608
len += ov[i].origin_len;
609
}
610
611
if (2 * nov + len > NGHTTP2_MAX_PAYLOADLEN) {
612
return NGHTTP2_ERR_INVALID_ARGUMENT;
613
}
614
615
/* The last nov is added for terminal NULL character. */
616
ov_copy =
617
nghttp2_mem_malloc(mem, nov * sizeof(nghttp2_origin_entry) + len + nov);
618
if (ov_copy == NULL) {
619
return NGHTTP2_ERR_NOMEM;
620
}
621
622
p = (uint8_t *)ov_copy + nov * sizeof(nghttp2_origin_entry);
623
624
for (i = 0; i < nov; ++i) {
625
ov_copy[i].origin = p;
626
ov_copy[i].origin_len = ov[i].origin_len;
627
p = nghttp2_cpymem(p, ov[i].origin, ov[i].origin_len);
628
*p++ = '\0';
629
}
630
631
assert((size_t)(p - (uint8_t *)ov_copy) ==
632
nov * sizeof(nghttp2_origin_entry) + len + nov);
633
} else {
634
ov_copy = NULL;
635
}
636
637
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
638
if (item == NULL) {
639
rv = NGHTTP2_ERR_NOMEM;
640
goto fail_item_malloc;
641
}
642
643
nghttp2_outbound_item_init(item);
644
645
item->aux_data.ext.builtin = 1;
646
647
origin = &item->ext_frame_payload.origin;
648
649
frame = &item->frame;
650
frame->ext.payload = origin;
651
652
nghttp2_frame_origin_init(&frame->ext, ov_copy, nov);
653
654
rv = nghttp2_session_add_item(session, item);
655
if (rv != 0) {
656
nghttp2_frame_origin_free(&frame->ext, mem);
657
nghttp2_mem_free(mem, item);
658
659
return rv;
660
}
661
662
return 0;
663
664
fail_item_malloc:
665
free(ov_copy);
666
667
return rv;
668
}
669
670
int nghttp2_submit_priority_update(nghttp2_session *session, uint8_t flags,
671
int32_t stream_id,
672
const uint8_t *field_value,
673
size_t field_value_len) {
674
nghttp2_mem *mem;
675
uint8_t *buf, *p;
676
nghttp2_outbound_item *item;
677
nghttp2_frame *frame;
678
nghttp2_ext_priority_update *priority_update;
679
int rv;
680
(void)flags;
681
682
mem = &session->mem;
683
684
if (session->server) {
685
return NGHTTP2_ERR_INVALID_STATE;
686
}
687
688
if (session->remote_settings.no_rfc7540_priorities == 0) {
689
return 0;
690
}
691
692
if (stream_id == 0 || 4 + field_value_len > NGHTTP2_MAX_PAYLOADLEN) {
693
return NGHTTP2_ERR_INVALID_ARGUMENT;
694
}
695
696
if (field_value_len) {
697
buf = nghttp2_mem_malloc(mem, field_value_len + 1);
698
if (buf == NULL) {
699
return NGHTTP2_ERR_NOMEM;
700
}
701
702
p = nghttp2_cpymem(buf, field_value, field_value_len);
703
*p = '\0';
704
} else {
705
buf = NULL;
706
}
707
708
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
709
if (item == NULL) {
710
rv = NGHTTP2_ERR_NOMEM;
711
goto fail_item_malloc;
712
}
713
714
nghttp2_outbound_item_init(item);
715
716
item->aux_data.ext.builtin = 1;
717
718
priority_update = &item->ext_frame_payload.priority_update;
719
720
frame = &item->frame;
721
frame->ext.payload = priority_update;
722
723
nghttp2_frame_priority_update_init(&frame->ext, stream_id, buf,
724
field_value_len);
725
726
rv = nghttp2_session_add_item(session, item);
727
if (rv != 0) {
728
nghttp2_frame_priority_update_free(&frame->ext, mem);
729
nghttp2_mem_free(mem, item);
730
731
return rv;
732
}
733
734
return 0;
735
736
fail_item_malloc:
737
free(buf);
738
739
return rv;
740
}
741
742
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
743
const nghttp2_data_provider *data_prd) {
744
uint8_t flags = NGHTTP2_FLAG_NONE;
745
if (data_prd == NULL || data_prd->read_callback == NULL) {
746
flags |= NGHTTP2_FLAG_END_STREAM;
747
}
748
749
if (pri_spec) {
750
flags |= NGHTTP2_FLAG_PRIORITY;
751
}
752
753
return flags;
754
}
755
756
int32_t nghttp2_submit_request(nghttp2_session *session,
757
const nghttp2_priority_spec *pri_spec,
758
const nghttp2_nv *nva, size_t nvlen,
759
const nghttp2_data_provider *data_prd,
760
void *stream_user_data) {
761
uint8_t flags;
762
int rv;
763
764
if (session->server) {
765
return NGHTTP2_ERR_PROTO;
766
}
767
768
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec) &&
769
session->remote_settings.no_rfc7540_priorities != 1) {
770
rv = detect_self_dependency(session, -1, pri_spec);
771
if (rv != 0) {
772
return rv;
773
}
774
} else {
775
pri_spec = NULL;
776
}
777
778
flags = set_request_flags(pri_spec, data_prd);
779
780
return submit_headers_shared_nva(session, flags, -1, pri_spec, nva, nvlen,
781
data_prd, stream_user_data);
782
}
783
784
static uint8_t set_response_flags(const nghttp2_data_provider *data_prd) {
785
uint8_t flags = NGHTTP2_FLAG_NONE;
786
if (data_prd == NULL || data_prd->read_callback == NULL) {
787
flags |= NGHTTP2_FLAG_END_STREAM;
788
}
789
return flags;
790
}
791
792
int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
793
const nghttp2_nv *nva, size_t nvlen,
794
const nghttp2_data_provider *data_prd) {
795
uint8_t flags;
796
797
if (stream_id <= 0) {
798
return NGHTTP2_ERR_INVALID_ARGUMENT;
799
}
800
801
if (!session->server) {
802
return NGHTTP2_ERR_PROTO;
803
}
804
805
flags = set_response_flags(data_prd);
806
return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen,
807
data_prd, NULL);
808
}
809
810
int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
811
int32_t stream_id,
812
const nghttp2_data_provider *data_prd) {
813
int rv;
814
nghttp2_outbound_item *item;
815
nghttp2_frame *frame;
816
nghttp2_data_aux_data *aux_data;
817
uint8_t nflags = flags & NGHTTP2_FLAG_END_STREAM;
818
nghttp2_mem *mem;
819
820
mem = &session->mem;
821
822
if (stream_id == 0) {
823
return NGHTTP2_ERR_INVALID_ARGUMENT;
824
}
825
826
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
827
if (item == NULL) {
828
return NGHTTP2_ERR_NOMEM;
829
}
830
831
nghttp2_outbound_item_init(item);
832
833
frame = &item->frame;
834
aux_data = &item->aux_data.data;
835
aux_data->data_prd = *data_prd;
836
aux_data->eof = 0;
837
aux_data->flags = nflags;
838
839
/* flags are sent on transmission */
840
nghttp2_frame_data_init(&frame->data, NGHTTP2_FLAG_NONE, stream_id);
841
842
rv = nghttp2_session_add_item(session, item);
843
if (rv != 0) {
844
nghttp2_frame_data_free(&frame->data);
845
nghttp2_mem_free(mem, item);
846
return rv;
847
}
848
return 0;
849
}
850
851
ssize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,
852
const nghttp2_settings_entry *iv,
853
size_t niv) {
854
if (!nghttp2_iv_check(iv, niv)) {
855
return NGHTTP2_ERR_INVALID_ARGUMENT;
856
}
857
858
if (buflen < (niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH)) {
859
return NGHTTP2_ERR_INSUFF_BUFSIZE;
860
}
861
862
return (ssize_t)nghttp2_frame_pack_settings_payload(buf, iv, niv);
863
}
864
865
int nghttp2_submit_extension(nghttp2_session *session, uint8_t type,
866
uint8_t flags, int32_t stream_id, void *payload) {
867
int rv;
868
nghttp2_outbound_item *item;
869
nghttp2_frame *frame;
870
nghttp2_mem *mem;
871
872
mem = &session->mem;
873
874
if (type <= NGHTTP2_CONTINUATION) {
875
return NGHTTP2_ERR_INVALID_ARGUMENT;
876
}
877
878
if (!session->callbacks.pack_extension_callback) {
879
return NGHTTP2_ERR_INVALID_STATE;
880
}
881
882
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
883
if (item == NULL) {
884
return NGHTTP2_ERR_NOMEM;
885
}
886
887
nghttp2_outbound_item_init(item);
888
889
frame = &item->frame;
890
nghttp2_frame_extension_init(&frame->ext, type, flags, stream_id, payload);
891
892
rv = nghttp2_session_add_item(session, item);
893
if (rv != 0) {
894
nghttp2_frame_extension_free(&frame->ext);
895
nghttp2_mem_free(mem, item);
896
return rv;
897
}
898
899
return 0;
900
}
901
902