~ubuntu-branches/ubuntu/vivid/curl/vivid

« back to all changes in this revision

Viewing changes to lib/http2.c

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2014-11-10 08:48:21 UTC
  • mfrom: (3.4.52 sid)
  • Revision ID: package-import@ubuntu.com-20141110084821-inwi9tek417xe4te
Tags: 7.38.0-3ubuntu1
* Merge from Debian. Remaining changes:
  - Drop dependencies not in main:
    + Build-Depends: Drop stunnel4 and libssh2-1-dev.
    + Drop libssh2-1-dev from binary package Depends.
  - Add new libcurl3-udeb package.
  - Add new curl-udeb package.
* Dropped patches:
  - debian/patches/09_fix-timeout-in-poll-and-wait.patch: upstream
  - debian/patches/CVE-2014-3613.patch: upstream
  - debian/patches/CVE-2014-3620.patch: upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
/* include memdebug.h last */
40
40
#include "memdebug.h"
41
41
 
42
 
#if (NGHTTP2_VERSION_NUM < 0x000300)
 
42
#if (NGHTTP2_VERSION_NUM < 0x000600)
43
43
#error too old nghttp2 version, upgrade!
44
44
#endif
45
45
 
191
191
  struct connectdata *conn = (struct connectdata *)userp;
192
192
  struct http_conn *c = &conn->proto.httpc;
193
193
  int rv;
 
194
  size_t left, ncopy;
 
195
 
194
196
  (void)session;
195
197
  (void)frame;
196
198
  infof(conn->data, "on_frame_recv() was called with header %x\n",
197
199
        frame->hd.type);
198
200
  switch(frame->hd.type) {
 
201
  case NGHTTP2_DATA:
 
202
    /* If body started, then receiving DATA is illegal. */
 
203
    if(!c->bodystarted) {
 
204
      rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
 
205
                                     frame->hd.stream_id,
 
206
                                     NGHTTP2_PROTOCOL_ERROR);
 
207
 
 
208
      if(nghttp2_is_fatal(rv)) {
 
209
        return NGHTTP2_ERR_CALLBACK_FAILURE;
 
210
      }
 
211
    }
 
212
    break;
199
213
  case NGHTTP2_HEADERS:
200
 
    if(frame->headers.cat != NGHTTP2_HCAT_RESPONSE)
201
 
      break;
202
 
    c->bodystarted = TRUE;
 
214
    if(frame->headers.cat == NGHTTP2_HCAT_REQUEST)
 
215
      break;
 
216
 
 
217
    if(c->bodystarted) {
 
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,
 
223
                                       frame->hd.stream_id,
 
224
                                       NGHTTP2_PROTOCOL_ERROR);
 
225
 
 
226
        if(nghttp2_is_fatal(rv)) {
 
227
          return NGHTTP2_ERR_CALLBACK_FAILURE;
 
228
        }
 
229
      }
 
230
      break;
 
231
    }
 
232
 
 
233
    if(c->status_code == -1) {
 
234
      /* No :status header field means PROTOCOL_ERROR. */
 
235
      rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
 
236
                                     frame->hd.stream_id,
 
237
                                     NGHTTP2_PROTOCOL_ERROR);
 
238
 
 
239
      if(nghttp2_is_fatal(rv)) {
 
240
        return NGHTTP2_ERR_CALLBACK_FAILURE;
 
241
      }
 
242
 
 
243
      break;
 
244
    }
 
245
 
 
246
    /* Only final status code signals the end of header */
 
247
    if(c->status_code / 100 != 1) {
 
248
      c->bodystarted = TRUE;
 
249
    }
 
250
 
 
251
    c->status_code = -1;
 
252
 
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;
206
 
 
207
 
    memcpy(c->mem, c->header_recvbuf->buffer, c->nread_header_recvbuf);
208
 
 
209
 
    c->mem += c->nread_header_recvbuf;
210
 
    c->len -= c->nread_header_recvbuf;
 
254
 
 
255
    left = c->header_recvbuf->size_used - c->nread_header_recvbuf;
 
256
    ncopy = c->len < left ? c->len : left;
 
257
 
 
258
    memcpy(c->mem, c->header_recvbuf->buffer + c->nread_header_recvbuf, ncopy);
 
259
    c->nread_header_recvbuf += ncopy;
 
260
 
 
261
    c->mem += ncopy;
 
262
    c->len -= ncopy;
211
263
    break;
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,
 
267
                                   NGHTTP2_CANCEL);
215
268
    if(nghttp2_is_fatal(rv)) {
216
269
      return rv;
217
270
    }
222
275
 
223
276
static int on_invalid_frame_recv(nghttp2_session *session,
224
277
                                 const nghttp2_frame *frame,
225
 
                                 nghttp2_error_code error_code, void *userp)
 
278
                                 uint32_t error_code, void *userp)
226
279
{
227
280
  struct connectdata *conn = (struct connectdata *)userp;
228
281
  (void)session;
297
350
  return 0;
298
351
}
299
352
static int on_stream_close(nghttp2_session *session, int32_t stream_id,
300
 
                           nghttp2_error_code error_code, void *userp)
 
353
                           uint32_t error_code, void *userp)
301
354
{
302
355
  struct connectdata *conn = (struct connectdata *)userp;
303
356
  struct http_conn *c = &conn->proto.httpc;
315
368
  return 0;
316
369
}
317
370
 
318
 
static int on_unknown_frame_recv(nghttp2_session *session,
319
 
                                 const uint8_t *head, size_t headlen,
320
 
                                 const uint8_t *payload, size_t payloadlen,
321
 
                                 void *userp)
322
 
{
323
 
  struct connectdata *conn = (struct connectdata *)userp;
324
 
  (void)session;
325
 
  (void)head;
326
 
  (void)headlen;
327
 
  (void)payload;
328
 
  (void)payloadlen;
329
 
  infof(conn->data, "on_unknown_frame_recv() was called\n");
330
 
  return 0;
331
 
}
332
371
static int on_begin_headers(nghttp2_session *session,
333
372
                            const nghttp2_frame *frame, void *userp)
334
373
{
339
378
  return 0;
340
379
}
341
380
 
 
381
/* Decode HTTP status code.  Returns -1 if no valid status code was
 
382
   decoded. */
 
383
static int decode_status_code(const uint8_t *value, size_t len)
 
384
{
 
385
  int i;
 
386
  int res;
 
387
 
 
388
  if(len != 3) {
 
389
    return -1;
 
390
  }
 
391
 
 
392
  res = 0;
 
393
 
 
394
  for(i = 0; i < 3; ++i) {
 
395
    char c = value[i];
 
396
 
 
397
    if(c < '0' || c > '9') {
 
398
      return -1;
 
399
    }
 
400
 
 
401
    res *= 10;
 
402
    res += c - '0';
 
403
  }
 
404
 
 
405
  return res;
 
406
}
 
407
 
342
408
static const char STATUS[] = ":status";
343
409
 
344
410
/* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
350
416
{
351
417
  struct connectdata *conn = (struct connectdata *)userp;
352
418
  struct http_conn *c = &conn->proto.httpc;
 
419
  int rv;
 
420
  int goodname;
 
421
  int goodheader;
 
422
 
353
423
  (void)session;
354
424
  (void)frame;
355
425
  (void)flags;
358
428
    return 0;
359
429
  }
360
430
 
 
431
  if(c->bodystarted) {
 
432
    /* Ignore trailer or HEADERS not mapped to HTTP semantics.  The
 
433
       consequence is handled in on_frame_recv(). */
 
434
    return 0;
 
435
  }
 
436
 
 
437
  goodname = nghttp2_check_header_name(name, namelen);
 
438
  goodheader = nghttp2_check_header_value(value, valuelen);
 
439
 
 
440
  if(!goodname || !goodheader) {
 
441
 
 
442
    infof(conn->data, "Detected bad incoming header %s%s, reset stream!\n",
 
443
          goodname?"":"name",
 
444
          goodheader?"":"value");
 
445
 
 
446
    rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
 
447
                                   frame->hd.stream_id,
 
448
                                   NGHTTP2_PROTOCOL_ERROR);
 
449
 
 
450
    if(nghttp2_is_fatal(rv)) {
 
451
      return NGHTTP2_ERR_CALLBACK_FAILURE;
 
452
    }
 
453
 
 
454
    return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
 
455
  }
 
456
 
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';
 
459
 
 
460
    /* :status must appear exactly once. */
 
461
    if(c->status_code != -1 ||
 
462
       (c->status_code = decode_status_code(value, valuelen)) == -1) {
 
463
 
 
464
      rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
 
465
                                     frame->hd.stream_id,
 
466
                                     NGHTTP2_PROTOCOL_ERROR);
 
467
      if(nghttp2_is_fatal(rv)) {
 
468
        return NGHTTP2_ERR_CALLBACK_FAILURE;
 
469
      }
 
470
 
 
471
      return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
 
472
    }
 
473
 
 
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);
 
477
 
365
478
    return 0;
366
479
  }
367
480
  else {
 
481
    /* Here we are sure that namelen > 0 because of
 
482
       nghttp2_check_header_name().  Pseudo header other than :status
 
483
       is illegal. */
 
484
    if(c->status_code == -1 || name[0] == ':') {
 
485
      rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
 
486
                                     frame->hd.stream_id,
 
487
                                     NGHTTP2_PROTOCOL_ERROR);
 
488
      if(nghttp2_is_fatal(rv)) {
 
489
        return NGHTTP2_ERR_CALLBACK_FAILURE;
 
490
      }
 
491
 
 
492
      return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
 
493
    }
 
494
 
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);
 
500
 
 
501
    infof(conn->data, "got http2 header: %.*s: %.*s\n",
 
502
          namelen, name, valuelen, value);
374
503
  }
375
504
 
376
505
  return 0; /* 0 is successful */
377
506
}
378
507
 
379
 
/*
380
 
 * This is all callbacks nghttp2 calls
381
 
 */
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 */
397
 
#endif
398
 
};
399
 
 
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,
444
552
{
445
553
  if(!conn->proto.httpc.h2) {
446
554
    int rc;
 
555
    nghttp2_session_callbacks *callbacks;
 
556
 
447
557
    conn->proto.httpc.inbuf = malloc(H2_BUFSIZE);
448
558
    if(conn->proto.httpc.inbuf == NULL)
449
559
      return CURLE_OUT_OF_MEMORY;
450
560
 
 
561
    rc = nghttp2_session_callbacks_new(&callbacks);
 
562
 
 
563
    if(rc) {
 
564
      failf(conn->data, "Couldn't initialize nghttp2 callbacks!");
 
565
      return CURLE_OUT_OF_MEMORY; /* most likely at least */
 
566
    }
 
567
 
 
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);
 
596
 
451
597
    /* The nghttp2 session is not yet setup, do it */
452
598
    rc = nghttp2_session_client_new(&conn->proto.httpc.h2,
453
 
                                    &callbacks, conn);
 
599
                                    callbacks, conn);
 
600
 
 
601
    nghttp2_session_callbacks_del(callbacks);
 
602
 
454
603
    if(rc) {
455
604
      failf(conn->data, "Couldn't initialize nghttp2!");
456
605
      return CURLE_OUT_OF_MEMORY; /* most likely at least */
504
653
  }
505
654
  conn->proto.httpc.binlen = binlen;
506
655
 
507
 
  result = Curl_base64_encode(conn->data, (const char *)binsettings, binlen,
508
 
                              &base64, &blen);
 
656
  result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen,
 
657
                                 &base64, &blen);
509
658
  if(result)
510
659
    return result;
511
660
 
536
685
  (void)sockindex; /* we always do HTTP2 on sockindex 0 */
537
686
 
538
687
  if(httpc->closed) {
 
688
    /* Reset to FALSE to prevent infinite loop in readwrite_data
 
689
       function. */
 
690
    httpc->closed = FALSE;
539
691
    return 0;
540
692
  }
541
693
 
615
767
  /* If stream is closed, return 0 to signal the http routine to close
616
768
     the connection */
617
769
  if(httpc->closed) {
 
770
    /* Reset to FALSE to prevent infinite loop in readwrite_data
 
771
       function. */
 
772
    httpc->closed = FALSE;
618
773
    return 0;
619
774
  }
620
775
  *err = CURLE_AGAIN;
621
776
  return -1;
622
777
}
623
778
 
 
779
/* Index where :authority header field will appear in request header
 
780
   field list. */
 
781
#define AUTHORITY_DST_IDX 3
 
782
 
624
783
/* return number of received (decrypted) bytes */
625
784
static ssize_t http2_send(struct connectdata *conn, int sockindex,
626
785
                          const void *mem, size_t len, CURLcode *err)
635
794
  nghttp2_nv *nva;
636
795
  size_t nheader;
637
796
  size_t i;
 
797
  size_t authority_idx;
638
798
  char *hdbuf = (char*)mem;
639
799
  char *end;
640
800
  nghttp2_data_provider data_prd;
705
865
  hdbuf = strchr(hdbuf, 0x0a);
706
866
  ++hdbuf;
707
867
 
 
868
  authority_idx = 0;
 
869
 
708
870
  for(i = 3; i < nheader; ++i) {
709
871
    end = strchr(hdbuf, ':');
710
872
    assert(end);
711
873
    if(end - hdbuf == 4 && Curl_raw_nequal("host", hdbuf, 4)) {
 
874
      authority_idx = i;
712
875
      nva[i].name = (unsigned char *)":authority";
713
876
      nva[i].namelen = (uint16_t)strlen((char *)nva[i].name);
714
877
    }
739
902
    }
740
903
  }
741
904
 
 
905
  /* :authority must come before non-pseudo header fields */
 
906
  if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) {
 
907
    nghttp2_nv authority = nva[authority_idx];
 
908
    for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
 
909
      nva[i] = nva[i - 1];
 
910
    }
 
911
    nva[i] = authority;
 
912
  }
 
913
 
742
914
  switch(conn->data->set.httpreq) {
743
915
  case HTTPREQ_POST:
744
916
  case HTTPREQ_POST_FORM:
803
975
  httpc->upload_mem = NULL;
804
976
  httpc->upload_len = 0;
805
977
  httpc->stream_id = -1;
 
978
  httpc->status_code = -1;
806
979
 
807
980
  conn->httpversion = 20;
808
981
 
809
 
  /* Put place holder for status line */
810
 
  return Curl_add_buffer(httpc->header_recvbuf, "HTTP/2.0 200\r\n", 14);
 
982
  return 0;
811
983
}
812
984
 
813
 
int Curl_http2_switched(struct connectdata *conn)
 
985
CURLcode Curl_http2_switched(struct connectdata *conn)
814
986
{
815
 
  /* TODO: May get CURLE_AGAIN */
816
987
  CURLcode rc;
817
988
  struct http_conn *httpc = &conn->proto.httpc;
818
989
  int rv;
 
990
  struct SessionHandle *data = conn->data;
819
991
 
820
992
  httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET];
821
993
  httpc->send_underlying = (sending)conn->send[FIRSTSOCKET];
827
999
     NGHTTP2_CLIENT_CONNECTION_PREFACE,
828
1000
     NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN,
829
1001
     &rc);
830
 
  assert(rv == 24);
 
1002
  if(rc)
 
1003
    /* TODO: This may get CURLE_AGAIN */
 
1004
    return rc;
 
1005
 
 
1006
  if(rv != 24) {
 
1007
    failf(data, "Only sent partial HTTP2 packet");
 
1008
    return CURLE_SEND_ERROR;
 
1009
  }
 
1010
 
831
1011
  if(conn->data->req.upgr101 == UPGR101_RECEIVED) {
832
1012
    /* stream 1 is opened implicitly on upgrade */
833
1013
    httpc->stream_id = 1;
835
1015
    rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings,
836
1016
                                 httpc->binlen, NULL);
837
1017
    if(rv != 0) {
838
 
      failf(conn->data, "nghttp2_session_upgrade() failed: %s(%d)",
 
1018
      failf(data, "nghttp2_session_upgrade() failed: %s(%d)",
839
1019
            nghttp2_strerror(rv), rv);
840
 
      return -1;
 
1020
      return CURLE_HTTP2;
841
1021
    }
842
1022
  }
843
1023
  else {
845
1025
    httpc->stream_id = -1;
846
1026
    rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, NULL, 0);
847
1027
    if(rv != 0) {
848
 
      failf(conn->data, "nghttp2_submit_settings() failed: %s(%d)",
 
1028
      failf(data, "nghttp2_submit_settings() failed: %s(%d)",
849
1029
            nghttp2_strerror(rv), rv);
850
 
      return -1;
 
1030
      return CURLE_HTTP2;
851
1031
    }
852
1032
  }
853
 
  return 0;
 
1033
  return CURLE_OK;
854
1034
}
855
1035
 
856
1036
#endif