Example #1
0
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
                           nghttp2_frame *frame, nghttp2_nv *nv, int token,
                           int trailer) {
  int rv;

  /* We are strict for pseudo header field.  One bad character should
     lead to fail.  OTOH, we should be a bit forgiving for regular
     headers, since existing public internet has so much illegal
     headers floating around and if we kill the stream because of
     this, we may disrupt many web sites and/or libraries.  So we
     become conservative here, and just ignore those illegal regular
     headers. */
  if (!nghttp2_check_header_name(nv->name, nv->namelen)) {
    size_t i;
    if (nv->namelen > 0 && nv->name[0] == ':') {
      return NGHTTP2_ERR_HTTP_HEADER;
    }
    /* header field name must be lower-cased without exception */
    for (i = 0; i < nv->namelen; ++i) {
      uint8_t c = nv->name[i];
      if ('A' <= c && c <= 'Z') {
        return NGHTTP2_ERR_HTTP_HEADER;
      }
    }
    /* When ignoring regular headers, we set this flag so that we
       still enforce header field ordering rule for pseudo header
       fields. */
    stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
    return NGHTTP2_ERR_IGN_HTTP_HEADER;
  }

  if (token == NGHTTP2_TOKEN__AUTHORITY || token == NGHTTP2_TOKEN_HOST) {
    rv = check_authority(nv->value, nv->valuelen);
  } else if (token == NGHTTP2_TOKEN__SCHEME) {
    rv = check_scheme(nv->value, nv->valuelen);
  } else {
    rv = nghttp2_check_header_value(nv->value, nv->valuelen);
  }

  if (rv == 0) {
    assert(nv->namelen > 0);
    if (nv->name[0] == ':') {
      return NGHTTP2_ERR_HTTP_HEADER;
    }
    /* When ignoring regular headers, we set this flag so that we
       still enforce header field ordering rule for pseudo header
       fields. */
    stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
    return NGHTTP2_ERR_IGN_HTTP_HEADER;
  }

  if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
    return http_request_on_header(stream, nv, token, trailer);
  }

  return http_response_on_header(stream, nv, token, trailer);
}
Example #2
0
File: http2.c Project: RexSi/curl
/* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
                     const uint8_t *name, size_t namelen,
                     const uint8_t *value, size_t valuelen,
                     uint8_t flags,
                     void *userp)
{
  struct connectdata *conn = (struct connectdata *)userp;
  struct http_conn *c = &conn->proto.httpc;
  int rv;

  (void)session;
  (void)frame;
  (void)flags;

  if(frame->hd.stream_id != c->stream_id) {
    return 0;
  }

  if(c->bodystarted) {
    /* Ignore trailer or HEADERS not mapped to HTTP semantics.  The
       consequence is handled in on_frame_recv(). */
    return 0;
  }

  if(!nghttp2_check_header_name(name, namelen) ||
     !nghttp2_check_header_value(value, valuelen)) {

    rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
                                   frame->hd.stream_id,
                                   NGHTTP2_PROTOCOL_ERROR);

    if(nghttp2_is_fatal(rv)) {
      return NGHTTP2_ERR_CALLBACK_FAILURE;
    }

    return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
  }

  if(namelen == sizeof(":status") - 1 &&
     memcmp(STATUS, name, namelen) == 0) {

    /* :status must appear exactly once. */
    if(c->status_code != -1 ||
       (c->status_code = decode_status_code(value, valuelen)) == -1) {

      rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
                                     frame->hd.stream_id,
                                     NGHTTP2_PROTOCOL_ERROR);
      if(nghttp2_is_fatal(rv)) {
        return NGHTTP2_ERR_CALLBACK_FAILURE;
      }

      return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
    }

    Curl_add_buffer(c->header_recvbuf, "HTTP/2.0 ", 9);
    Curl_add_buffer(c->header_recvbuf, value, valuelen);
    Curl_add_buffer(c->header_recvbuf, "\r\n", 2);

    return 0;
  }
  else {
    /* Here we are sure that namelen > 0 because of
       nghttp2_check_header_name().  Pseudo header other than :status
       is illegal. */
    if(c->status_code == -1 || name[0] == ':') {
      rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
                                     frame->hd.stream_id,
                                     NGHTTP2_PROTOCOL_ERROR);
      if(nghttp2_is_fatal(rv)) {
        return NGHTTP2_ERR_CALLBACK_FAILURE;
      }

      return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
    }

    /* convert to a HTTP1-style header */
    infof(conn->data, "got header\n");
    Curl_add_buffer(c->header_recvbuf, name, namelen);
    Curl_add_buffer(c->header_recvbuf, ":", 1);
    Curl_add_buffer(c->header_recvbuf, value, valuelen);
    Curl_add_buffer(c->header_recvbuf, "\r\n", 2);
  }

  return 0; /* 0 is successful */
}