191
191
struct connectdata *conn = (struct connectdata *)userp;
192
192
struct http_conn *c = &conn->proto.httpc;
196
198
infof(conn->data, "on_frame_recv() was called with header %x\n",
198
200
switch(frame->hd.type) {
202
/* If body started, then receiving DATA is illegal. */
203
if(!c->bodystarted) {
204
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
206
NGHTTP2_PROTOCOL_ERROR);
208
if(nghttp2_is_fatal(rv)) {
209
return NGHTTP2_ERR_CALLBACK_FAILURE;
199
213
case NGHTTP2_HEADERS:
200
if(frame->headers.cat != NGHTTP2_HCAT_RESPONSE)
202
c->bodystarted = TRUE;
214
if(frame->headers.cat == NGHTTP2_HCAT_REQUEST)
218
/* Only valid HEADERS after body started is trailer header,
219
which is not fully supported in this code. If HEADERS is not
220
trailer, then it is a PROTOCOL_ERROR. */
221
if((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
222
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
224
NGHTTP2_PROTOCOL_ERROR);
226
if(nghttp2_is_fatal(rv)) {
227
return NGHTTP2_ERR_CALLBACK_FAILURE;
233
if(c->status_code == -1) {
234
/* No :status header field means PROTOCOL_ERROR. */
235
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
237
NGHTTP2_PROTOCOL_ERROR);
239
if(nghttp2_is_fatal(rv)) {
240
return NGHTTP2_ERR_CALLBACK_FAILURE;
246
/* Only final status code signals the end of header */
247
if(c->status_code / 100 != 1) {
248
c->bodystarted = TRUE;
203
253
Curl_add_buffer(c->header_recvbuf, "\r\n", 2);
204
c->nread_header_recvbuf = c->len < c->header_recvbuf->size_used ?
205
c->len : c->header_recvbuf->size_used;
207
memcpy(c->mem, c->header_recvbuf->buffer, c->nread_header_recvbuf);
209
c->mem += c->nread_header_recvbuf;
210
c->len -= c->nread_header_recvbuf;
255
left = c->header_recvbuf->size_used - c->nread_header_recvbuf;
256
ncopy = c->len < left ? c->len : left;
258
memcpy(c->mem, c->header_recvbuf->buffer + c->nread_header_recvbuf, ncopy);
259
c->nread_header_recvbuf += ncopy;
212
264
case NGHTTP2_PUSH_PROMISE:
213
265
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
214
frame->hd.stream_id, NGHTTP2_CANCEL);
266
frame->push_promise.promised_stream_id,
215
268
if(nghttp2_is_fatal(rv)) {
432
/* Ignore trailer or HEADERS not mapped to HTTP semantics. The
433
consequence is handled in on_frame_recv(). */
437
goodname = nghttp2_check_header_name(name, namelen);
438
goodheader = nghttp2_check_header_value(value, valuelen);
440
if(!goodname || !goodheader) {
442
infof(conn->data, "Detected bad incoming header %s%s, reset stream!\n",
444
goodheader?"":"value");
446
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
448
NGHTTP2_PROTOCOL_ERROR);
450
if(nghttp2_is_fatal(rv)) {
451
return NGHTTP2_ERR_CALLBACK_FAILURE;
454
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
361
457
if(namelen == sizeof(":status") - 1 &&
362
458
memcmp(STATUS, name, namelen) == 0) {
363
snprintf(c->header_recvbuf->buffer, 13, "HTTP/2.0 %s", value);
364
c->header_recvbuf->buffer[12] = '\r';
460
/* :status must appear exactly once. */
461
if(c->status_code != -1 ||
462
(c->status_code = decode_status_code(value, valuelen)) == -1) {
464
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
466
NGHTTP2_PROTOCOL_ERROR);
467
if(nghttp2_is_fatal(rv)) {
468
return NGHTTP2_ERR_CALLBACK_FAILURE;
471
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
474
Curl_add_buffer(c->header_recvbuf, "HTTP/2.0 ", 9);
475
Curl_add_buffer(c->header_recvbuf, value, valuelen);
476
Curl_add_buffer(c->header_recvbuf, "\r\n", 2);
481
/* Here we are sure that namelen > 0 because of
482
nghttp2_check_header_name(). Pseudo header other than :status
484
if(c->status_code == -1 || name[0] == ':') {
485
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
487
NGHTTP2_PROTOCOL_ERROR);
488
if(nghttp2_is_fatal(rv)) {
489
return NGHTTP2_ERR_CALLBACK_FAILURE;
492
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
368
495
/* convert to a HTTP1-style header */
369
infof(conn->data, "got header\n");
370
496
Curl_add_buffer(c->header_recvbuf, name, namelen);
371
497
Curl_add_buffer(c->header_recvbuf, ":", 1);
372
498
Curl_add_buffer(c->header_recvbuf, value, valuelen);
373
499
Curl_add_buffer(c->header_recvbuf, "\r\n", 2);
501
infof(conn->data, "got http2 header: %.*s: %.*s\n",
502
namelen, name, valuelen, value);
376
505
return 0; /* 0 is successful */
380
* This is all callbacks nghttp2 calls
382
static const nghttp2_session_callbacks callbacks = {
383
send_callback, /* nghttp2_send_callback */
384
NULL, /* nghttp2_recv_callback */
385
on_frame_recv, /* nghttp2_on_frame_recv_callback */
386
on_invalid_frame_recv, /* nghttp2_on_invalid_frame_recv_callback */
387
on_data_chunk_recv, /* nghttp2_on_data_chunk_recv_callback */
388
before_frame_send, /* nghttp2_before_frame_send_callback */
389
on_frame_send, /* nghttp2_on_frame_send_callback */
390
on_frame_not_send, /* nghttp2_on_frame_not_send_callback */
391
on_stream_close, /* nghttp2_on_stream_close_callback */
392
on_unknown_frame_recv, /* nghttp2_on_unknown_frame_recv_callback */
393
on_begin_headers, /* nghttp2_on_begin_headers_callback */
394
on_header /* nghttp2_on_header_callback */
395
#if NGHTTP2_VERSION_NUM >= 0x000400
396
, NULL /* nghttp2_select_padding_callback */
400
508
static ssize_t data_source_read_callback(nghttp2_session *session,
401
509
int32_t stream_id,
402
510
uint8_t *buf, size_t length,
445
553
if(!conn->proto.httpc.h2) {
555
nghttp2_session_callbacks *callbacks;
447
557
conn->proto.httpc.inbuf = malloc(H2_BUFSIZE);
448
558
if(conn->proto.httpc.inbuf == NULL)
449
559
return CURLE_OUT_OF_MEMORY;
561
rc = nghttp2_session_callbacks_new(&callbacks);
564
failf(conn->data, "Couldn't initialize nghttp2 callbacks!");
565
return CURLE_OUT_OF_MEMORY; /* most likely at least */
568
/* nghttp2_send_callback */
569
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
570
/* nghttp2_on_frame_recv_callback */
571
nghttp2_session_callbacks_set_on_frame_recv_callback
572
(callbacks, on_frame_recv);
573
/* nghttp2_on_invalid_frame_recv_callback */
574
nghttp2_session_callbacks_set_on_invalid_frame_recv_callback
575
(callbacks, on_invalid_frame_recv);
576
/* nghttp2_on_data_chunk_recv_callback */
577
nghttp2_session_callbacks_set_on_data_chunk_recv_callback
578
(callbacks, on_data_chunk_recv);
579
/* nghttp2_before_frame_send_callback */
580
nghttp2_session_callbacks_set_before_frame_send_callback
581
(callbacks, before_frame_send);
582
/* nghttp2_on_frame_send_callback */
583
nghttp2_session_callbacks_set_on_frame_send_callback
584
(callbacks, on_frame_send);
585
/* nghttp2_on_frame_not_send_callback */
586
nghttp2_session_callbacks_set_on_frame_not_send_callback
587
(callbacks, on_frame_not_send);
588
/* nghttp2_on_stream_close_callback */
589
nghttp2_session_callbacks_set_on_stream_close_callback
590
(callbacks, on_stream_close);
591
/* nghttp2_on_begin_headers_callback */
592
nghttp2_session_callbacks_set_on_begin_headers_callback
593
(callbacks, on_begin_headers);
594
/* nghttp2_on_header_callback */
595
nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header);
451
597
/* The nghttp2 session is not yet setup, do it */
452
598
rc = nghttp2_session_client_new(&conn->proto.httpc.h2,
601
nghttp2_session_callbacks_del(callbacks);
455
604
failf(conn->data, "Couldn't initialize nghttp2!");
456
605
return CURLE_OUT_OF_MEMORY; /* most likely at least */