コード例 #1
0
ファイル: ml-http2.c プロジェクト: iamblue/ml-http2
/**
* @brief       Callback function invoked after the frame |frame| is sent.
*              To set this callback to :type:`nghttp2_session_callbacks`, use
*              `nghttp2_session_callbacks_set_on_frame_send_callback()`.
* @param[in]   session: nghttp2 session.
* @param[in]   frame: nghttp2 frame.
* @param[in]   user_data: The |user_data| pointer is the third argument passed in to the call to
*              `nghttp2_session_client_new()` or `nghttp2_session_server_new()`
* @return      The implementation of this function must return 0 if it succeeds.
*              If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()`
*              and `nghttp2_session_mem_send()` functions immediately return :enum:
*              `NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
static int on_frame_send_callback(nghttp2_session *session,
                                  const nghttp2_frame *frame,
                                  void *user_data)
{
    size_t i;
    printf("on_frame_send_callback %d\n", frame->hd.type);
    switch (frame->hd.type) {
        case NGHTTP2_HEADERS:
            if (nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)) {
                const nghttp2_nv *nva = frame->headers.nva;
                printf("[INFO] C --------> S (HEADERS)\n");
                for (i = 0; i < frame->headers.nvlen; ++i) {
                    printf("%s: %s\n", nva[i].name, nva[i].value);
                }
            }
            break;
        case NGHTTP2_RST_STREAM:
            printf("[INFO] C ------> S (RST_STREAM)\n");
            break;
        case NGHTTP2_GOAWAY:
            printf("[INFO] C -------> S (GOAWAY)\n");
            break;
    }
    return 0;
}
コード例 #2
0
ファイル: ml-http2.c プロジェクト: iamblue/ml-http2
/**
* @brief       Callback function invoked by `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` when a frame is received.
*              If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen``member of their data structure are always
*              ``NULL`` and 0 respectively.  The header name/value pairs are emitted via:type:`nghttp2_on_header_callback`
*              To set this callback to :type:`nghttp2_session_callbacks`, use`nghttp2_session_callbacks_set_on_frame_send_callback()`.
*              For HEADERS, PUSH_PROMISE and DATA frames, this callback may be called after stream is closed (see:type:
*              `nghttp2_on_stream_close_callback`).  The application should check that stream is still alive using its own stream
*              management or :func:`nghttp2_session_get_stream_user_data()`.
*              Only HEADERS and DATA frame can signal the end of incoming data. If ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM``
*              is nonzero, the|frame| is the last frame from the remote peer in this stream.
*              This callback won't be called for CONTINUATION frames.
*              HEADERS/PUSH_PROMISE + CONTINUATIONs are treated as single frame.
* @param[in]   session: nghttp2 session.
* @param[in]   frame: nghttp2 frame.
* @param[in]   user_data: The |user_data| pointer is the third argument passed in to the call to
*              `nghttp2_session_client_new()` or `nghttp2_session_server_new()`
* @return      The implementation of this function must return 0 if it succeeds.
*              If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()`
*              and `nghttp2_session_mem_send()` functions immediately return :enum:
*              `NGHTTP2_ERR_CALLBACK_FAILURE`.
*/
static int on_frame_recv_callback(nghttp2_session *session,
                                  const nghttp2_frame *frame,
                                  void *user_data)
{
    size_t i;
    printf("on_frame_recv_callback %d\n", frame->hd.type);
    switch (frame->hd.type) {
        case NGHTTP2_HEADERS:
            if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
                const nghttp2_nv *nva = frame->headers.nva;
                struct Request *req;
                req = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
                if (req) {
                    printf("[INFO] C <--------- S (HEADERS)\n");
                    for (i = 0; i < frame->headers.nvlen; ++i) {
                        printf("%s %s\r\n", nva[i].name, nva[i].value);
                    }
                }
            }
            break;
        case NGHTTP2_RST_STREAM:
            printf("[INFO] C <--------- S (RST_STREAM)\n");
            break;
        case NGHTTP2_GOAWAY:
            printf("[INFO] C <-------- S (GOAWAY)\n");
            break;
        case NGHTTP2_DATA:
            if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
                printf("end stream flag\r\n");
            }
            break;
    }
    return 0;
}
コード例 #3
0
ファイル: http2.c プロジェクト: 601040605/WNetLicensor
static int on_stream_close(nghttp2_session *session, int32_t stream_id,
                           uint32_t error_code, void *userp)
{
  struct SessionHandle *data_s;
  struct HTTP *stream;
  (void)session;
  (void)stream_id;
  (void)userp;

  if(stream_id) {
    /* get the stream from the hash based on Stream ID, stream ID zero is for
       connection-oriented stuff */
    data_s = nghttp2_session_get_stream_user_data(session, stream_id);
    if(!data_s) {
      /* We could get stream ID not in the hash.  For example, if we
         decided to reject stream (e.g., PUSH_PROMISE). */
      return 0;
    }
    DEBUGF(infof(data_s, "on_stream_close(), error_code = %d, stream %u\n",
                 error_code, stream_id));
    stream = data_s->req.protop;
    if(!stream)
      return NGHTTP2_ERR_CALLBACK_FAILURE;

    stream->error_code = error_code;
    stream->closed = TRUE;

    /* remove the entry from the hash as the stream is now gone */
    nghttp2_session_set_stream_user_data(session, stream_id, 0);
    DEBUGF(infof(data_s, "Removed stream %u hash!\n", stream_id));
  }
  return 0;
}
コード例 #4
0
ファイル: libevent-server.c プロジェクト: LPardue/nghttp2
/* nghttp2_on_header_callback: Called when nghttp2 library emits
   single header name/value pair. */
static int on_header_callback(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 *user_data) {
  http2_stream_data *stream_data;
  const char PATH[] = ":path";
  (void)flags;
  (void)user_data;

  switch (frame->hd.type) {
  case NGHTTP2_HEADERS:
    if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
      break;
    }
    stream_data =
        nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
    if (!stream_data || stream_data->request_path) {
      break;
    }
    if (namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
      size_t j;
      for (j = 0; j < valuelen && value[j] != '?'; ++j)
        ;
      stream_data->request_path = percent_decode(value, j);
    }
    break;
  }
  return 0;
}
コード例 #5
0
ファイル: client.c プロジェクト: flyqiu/nghttp2
static int on_frame_recv_callback(nghttp2_session *session,
                                  const nghttp2_frame *frame, void *user_data) {
  size_t i;
  (void)user_data;

  switch (frame->hd.type) {
  case NGHTTP2_HEADERS:
    if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
      const nghttp2_nv *nva = frame->headers.nva;
      struct Request *req;
      req = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
      if (req) {
        printf("[INFO] C <---------------------------- S (HEADERS)\n");
        for (i = 0; i < frame->headers.nvlen; ++i) {
          fwrite(nva[i].name, 1, nva[i].namelen, stdout);
          printf(": ");
          fwrite(nva[i].value, 1, nva[i].valuelen, stdout);
          printf("\n");
        }
      }
    }
    break;
  case NGHTTP2_RST_STREAM:
    printf("[INFO] C <---------------------------- S (RST_STREAM)\n");
    break;
  case NGHTTP2_GOAWAY:
    printf("[INFO] C <---------------------------- S (GOAWAY)\n");
    break;
  }
  return 0;
}
コード例 #6
0
ファイル: http2.c プロジェクト: Inspirati/premake-core
static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
                              int32_t stream_id,
                              const uint8_t *data, size_t len, void *userp)
{
  struct HTTP *stream;
  struct SessionHandle *data_s;
  size_t nread;
  struct connectdata *conn = (struct connectdata *)userp;
  (void)session;
  (void)flags;
  (void)data;

  DEBUGASSERT(stream_id); /* should never be a zero stream ID here */

  /* get the stream from the hash based on Stream ID */
  data_s = nghttp2_session_get_stream_user_data(session, stream_id);
  if(!data_s)
    /* Receiving a Stream ID not in the hash should not happen, this is an
       internal error more than anything else! */
    return NGHTTP2_ERR_CALLBACK_FAILURE;

  stream = data_s->req.protop;
  if(!stream)
    return NGHTTP2_ERR_CALLBACK_FAILURE;

  nread = MIN(stream->len, len);
  memcpy(&stream->mem[stream->memlen], data, nread);

  stream->len -= nread;
  stream->memlen += nread;

  data_s->state.drain++;

  /* if we receive data for another handle, wake that up */
  if(conn->data != data_s)
    Curl_expire(data_s, 1); /* TODO: fix so that this can be set to 0 for
                               immediately? */

  DEBUGF(infof(data_s, "%zu data received for stream %u "
               "(%zu left in buffer %p, total %zu)\n",
               nread, stream_id,
               stream->len, stream->mem,
               stream->memlen));

  if(nread < len) {
    stream->pausedata = data + nread;
    stream->pauselen = len - nread;
    DEBUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
                 ", stream %u\n",
                 len - nread, stream_id));
    data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
    return NGHTTP2_ERR_PAUSE;
  }
  return 0;
}
コード例 #7
0
ファイル: http2.c プロジェクト: 601040605/WNetLicensor
static int on_begin_headers(nghttp2_session *session,
                            const nghttp2_frame *frame, void *userp)
{
  struct SessionHandle *data_s = NULL;
  (void)userp;

  data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
  if(data_s) {
    DEBUGF(infof(data_s, "on_begin_headers() was called\n"));
  }
  return 0;
}
コード例 #8
0
ファイル: libevent-server.c プロジェクト: bizzbyster/nghttp2
static int on_stream_close_callback(nghttp2_session *session,
                                    int32_t stream_id,
                                    nghttp2_error_code error_code,
                                    void *user_data)
{
  http2_session_data *session_data = (http2_session_data*)user_data;
  http2_stream_data *stream_data;

  stream_data = nghttp2_session_get_stream_user_data(session, stream_id);
  remove_stream(session_data, stream_data);
  delete_http2_stream_data(stream_data);
  return 0;
}
コード例 #9
0
ファイル: ml-http2.c プロジェクト: iamblue/ml-http2
/**
* @brief        Callback function invoked when a chunk of data in DATA frame is received.
*               The implementation of nghttp2_on_data_chunk_recv_callback type. We use this function to print the received response body.
* @param[in]    session: nghttp2 session.
* @param[in]    flags: no using.
* @param[in]    stream_id: the stream ID this DATA frame belongs to.
* @param[in]    data: receive data.
* @param[in]    len: data length.
* @param[in]    user_data: The |user_data| pointer is the third argument passed in to the call to
*               `nghttp2_session_client_new()` or `nghttp2_session_server_new()`
* @return       The implementation of this function must return 0 if it succeeds.
*               If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()`
*               and `nghttp2_session_mem_send()` functions immediately return :enum:
*               `NGHTTP2_ERR_CALLBACK_FAILURE`.
 */
static int on_data_chunk_recv_callback(nghttp2_session *session,
                                       uint8_t flags, int32_t stream_id,
                                       const uint8_t *data, size_t len,
                                       void *user_data)
{
    struct Request *req;
    req = nghttp2_session_get_stream_user_data(session, stream_id);
    if (req) {
        printf("[INFO] C <----------- S (DATA chunk)\n" "%lu bytes\n", (unsigned long int)len);
        //printf("data chunk %s\n", data);
    }
    return 0;
}
コード例 #10
0
ファイル: http2.c プロジェクト: 601040605/WNetLicensor
static int on_frame_send(nghttp2_session *session,
                         const nghttp2_frame *frame,
                         void *userp)
{
  struct SessionHandle *data_s;
  (void)userp;

  data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
  if(data_s) {
    DEBUGF(infof(data_s, "on_frame_send() was called, length = %zd\n",
                 frame->hd.length));
  }
  return 0;
}
コード例 #11
0
ファイル: http2.c プロジェクト: 601040605/WNetLicensor
static int on_invalid_frame_recv(nghttp2_session *session,
                                 const nghttp2_frame *frame,
                                 int lib_error_code, void *userp)
{
  struct SessionHandle *data_s = NULL;
  (void)userp;

  data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
  if(data_s) {
    DEBUGF(infof(data_s,
                 "on_invalid_frame_recv() was called, error=%d:%s\n",
                 lib_error_code, nghttp2_strerror(lib_error_code)));
  }
  return 0;
}
コード例 #12
0
ファイル: http2.c プロジェクト: 601040605/WNetLicensor
static int on_frame_not_send(nghttp2_session *session,
                             const nghttp2_frame *frame,
                             int lib_error_code, void *userp)
{
  struct SessionHandle *data_s;
  (void)userp;

  data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
  if(data_s) {
    DEBUGF(infof(data_s,
                 "on_frame_not_send() was called, lib_error_code = %d\n",
                 lib_error_code));
  }
  return 0;
}
コード例 #13
0
ファイル: http2.c プロジェクト: 601040605/WNetLicensor
static ssize_t data_source_read_callback(nghttp2_session *session,
                                         int32_t stream_id,
                                         uint8_t *buf, size_t length,
                                         uint32_t *data_flags,
                                         nghttp2_data_source *source,
                                         void *userp)
{
  struct SessionHandle *data_s;
  struct HTTP *stream = NULL;
  size_t nread;
  (void)source;
  (void)userp;

  if(stream_id) {
    /* get the stream from the hash based on Stream ID, stream ID zero is for
       connection-oriented stuff */
    data_s = nghttp2_session_get_stream_user_data(session, stream_id);
    if(!data_s)
      /* Receiving a Stream ID not in the hash should not happen, this is an
         internal error more than anything else! */
      return NGHTTP2_ERR_CALLBACK_FAILURE;

    stream = data_s->req.protop;
    if(!stream)
      return NGHTTP2_ERR_CALLBACK_FAILURE;
  }
  else
    return NGHTTP2_ERR_INVALID_ARGUMENT;

  nread = MIN(stream->upload_len, length);
  if(nread > 0) {
    memcpy(buf, stream->upload_mem, nread);
    stream->upload_mem += nread;
    stream->upload_len -= nread;
    stream->upload_left -= nread;
  }

  if(stream->upload_left == 0)
    *data_flags = 1;
  else if(nread == 0)
    return NGHTTP2_ERR_DEFERRED;

  DEBUGF(infof(data_s, "data_source_read_callback: "
               "returns %zu bytes stream %u\n",
               nread, stream_id));

  return nread;
}
コード例 #14
0
ファイル: ml-http2.c プロジェクト: iamblue/ml-http2
/**
* @brief       Callback function invoked when the stream |stream_id| is closed.
*              We use this function to know if the response is fully received. Since we just fetch 1 resource in this program, after
*              the response is received, we submit GOAWAY and close the session.
* @param[in]   session: nghttp2 session.
* @param[in]   stream_id: stream id.
* @param[in]   error_code: The reason of closure.
*              Usually one of :enum:`nghttp2_error_code`, but that is not guaranteed.  The stream_user_data, which was specified in
*              `nghttp2_submit_request()` or `nghttp2_submit_headers()`, is still available in this function.
* @param[in]   user_data: The |user_data| pointer is the third argument passed in to the call to
*              `nghttp2_session_client_new()` or `nghttp2_session_server_new()`
* @return      The implementation of this function must return 0 if it succeeds.
*              If nonzero is returned, it is treated as fatal error and `nghttp2_session_send()`
*              and `nghttp2_session_mem_send()` functions immediately return :enum:
*              `NGHTTP2_ERR_CALLBACK_FAILURE`.
 */
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
                                    uint32_t error_code,
                                    void *user_data)
{
    struct Request *req;
    req = nghttp2_session_get_stream_user_data(session, stream_id);
    if (req) {
        int rv;
        rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);

        if (rv != 0) {
            printf("stream close nghttp2_session_terminate_session\r\n");
        }
    }
    return 0;
}
コード例 #15
0
ファイル: libevent-server.c プロジェクト: bizzbyster/nghttp2
static int on_request_recv_callback(nghttp2_session *session,
                                    int32_t stream_id, void *user_data)
{
  int fd;
  http2_session_data *session_data = (http2_session_data*)user_data;
  http2_stream_data *stream_data;
  nghttp2_nv hdrs[] = {
    MAKE_NV(":status", "200")
  };
  char *rel_path;

  stream_data = (http2_stream_data*)nghttp2_session_get_stream_user_data
    (session, stream_id);
  if(!stream_data->request_path) {
    if(error_reply(session, stream_data) != 0) {
      return NGHTTP2_ERR_CALLBACK_FAILURE;
    }
    return 0;
  }
  fprintf(stderr, "%s GET %s\n", session_data->client_addr,
          stream_data->request_path);
  if(!check_path(stream_data->request_path)) {
    if(error_reply(session, stream_data) != 0) {
      return NGHTTP2_ERR_CALLBACK_FAILURE;
    }
    return 0;
  }
  for(rel_path = stream_data->request_path; *rel_path == '/'; ++rel_path);
  fd = open(rel_path, O_RDONLY);
  if(fd == -1) {
    if(error_reply(session, stream_data) != 0) {
      return NGHTTP2_ERR_CALLBACK_FAILURE;
    }
    return 0;
  }
  stream_data->fd = fd;

  if(send_response(session, stream_id, hdrs, ARRLEN(hdrs), fd) != 0) {
    close(fd);
    return NGHTTP2_ERR_CALLBACK_FAILURE;
  }
  return 0;
}
コード例 #16
0
ファイル: libevent-server.c プロジェクト: LPardue/nghttp2
static int on_frame_recv_callback(nghttp2_session *session,
                                  const nghttp2_frame *frame, void *user_data) {
  http2_session_data *session_data = (http2_session_data *)user_data;
  http2_stream_data *stream_data;
  switch (frame->hd.type) {
  case NGHTTP2_DATA:
  case NGHTTP2_HEADERS:
    /* Check that the client request has finished */
    if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
      stream_data =
          nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
      /* For DATA and HEADERS frame, this callback may be called after
         on_stream_close_callback. Check that stream still alive. */
      if (!stream_data) {
        return 0;
      }
      return on_request_recv(session, session_data, stream_data);
    }
    break;
  default:
    break;
  }
  return 0;
}
コード例 #17
0
ファイル: http2.c プロジェクト: 601040605/WNetLicensor
static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
                         void *userp)
{
  struct connectdata *conn = NULL;
  struct http_conn *httpc = NULL;
  struct SessionHandle *data_s = NULL;
  struct HTTP *stream = NULL;
  static int lastStream = -1;
  int rv;
  size_t left, ncopy;
  int32_t stream_id = frame->hd.stream_id;

  (void)userp;

  if(!stream_id) {
    /* stream ID zero is for connection-oriented stuff */
    return 0;
  }
  data_s = nghttp2_session_get_stream_user_data(session,
                                                frame->hd.stream_id);
  if(lastStream != frame->hd.stream_id) {
    lastStream = frame->hd.stream_id;
  }
  if(!data_s) {
    DEBUGF(infof(conn->data,
                 "No SessionHandle associated with stream: %x\n",
                 stream_id));
    return 0;
  }

  stream = data_s->req.protop;
  if(!stream)
    return NGHTTP2_ERR_CALLBACK_FAILURE;

  DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n",
               frame->hd.type, stream_id));

  conn = data_s->easy_conn;
  assert(conn);
  assert(conn->data == data_s);
  httpc = &conn->proto.httpc;
  switch(frame->hd.type) {
  case NGHTTP2_DATA:
    /* If body started on this stream, then receiving DATA is illegal. */
    if(!stream->bodystarted) {
      rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
                                     stream_id, NGHTTP2_PROTOCOL_ERROR);

      if(nghttp2_is_fatal(rv)) {
        return NGHTTP2_ERR_CALLBACK_FAILURE;
      }
    }
    break;
  case NGHTTP2_HEADERS:
    if(frame->headers.cat == NGHTTP2_HCAT_REQUEST)
      break;

    if(stream->bodystarted) {
      /* Only valid HEADERS after body started is trailer HEADERS.  We
         ignores trailer HEADERS for now.  nghttp2 guarantees that it
         has END_STREAM flag set. */
      break;
    }

    /* nghttp2 guarantees that :status is received, and we store it to
       stream->status_code */
    DEBUGASSERT(stream->status_code != -1);

    /* Only final status code signals the end of header */
    if(stream->status_code / 100 != 1) {
      stream->bodystarted = TRUE;
      stream->status_code = -1;
    }

    Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);

    left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
    ncopy = MIN(stream->len, left);

    memcpy(&stream->mem[stream->memlen],
           stream->header_recvbuf->buffer + stream->nread_header_recvbuf,
           ncopy);
    stream->nread_header_recvbuf += ncopy;

    DEBUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n",
                 ncopy, stream_id, stream->mem));

    stream->len -= ncopy;
    stream->memlen += ncopy;

    data_s->state.drain++;
    Curl_expire(data_s, 1);
    break;
  case NGHTTP2_PUSH_PROMISE:
    rv = push_promise(data_s, conn, &frame->push_promise);
    if(rv) { /* deny! */
      rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
                                     frame->push_promise.promised_stream_id,
                                     NGHTTP2_CANCEL);
      if(nghttp2_is_fatal(rv)) {
        return rv;
      }
    }
    break;
  case NGHTTP2_SETTINGS:
  {
    uint32_t max_conn = httpc->settings.max_concurrent_streams;
    DEBUGF(infof(conn->data, "Got SETTINGS for stream %u!\n", stream_id));
    httpc->settings.max_concurrent_streams =
      nghttp2_session_get_remote_settings(
        session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
    httpc->settings.enable_push =
      nghttp2_session_get_remote_settings(
        session, NGHTTP2_SETTINGS_ENABLE_PUSH);
    DEBUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n",
                 httpc->settings.max_concurrent_streams));
    DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n",
                 httpc->settings.enable_push?"TRUE":"false"));
    if(max_conn != httpc->settings.max_concurrent_streams) {
      /* only signal change if the value actually changed */
      infof(conn->data,
            "Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n");
      Curl_multi_connchanged(conn->data->multi);
    }
  }
  break;
  default:
    DEBUGF(infof(conn->data, "Got frame type %x for stream %u!\n",
                 frame->hd.type, stream_id));
    break;
  }
  return 0;
}
コード例 #18
0
ファイル: http2.c プロジェクト: 601040605/WNetLicensor
/* 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 HTTP *stream;
  struct SessionHandle *data_s;
  int32_t stream_id = frame->hd.stream_id;

  (void)flags;
  (void)userp;

  DEBUGASSERT(stream_id); /* should never be a zero stream ID here */

  /* get the stream from the hash based on Stream ID */
  data_s = nghttp2_session_get_stream_user_data(session, stream_id);
  if(!data_s)
    /* Receiving a Stream ID not in the hash should not happen, this is an
       internal error more than anything else! */
    return NGHTTP2_ERR_CALLBACK_FAILURE;

  stream = data_s->req.protop;
  if(!stream) {
    failf(data_s, "Internal NULL stream! 5\n");
    return NGHTTP2_ERR_CALLBACK_FAILURE;
  }

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

  /* Store received PUSH_PROMISE headers to be used when the subsequent
     PUSH_PROMISE callback comes */
  if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
    char *h;

    if(!stream->push_headers) {
      stream->push_headers_alloc = 10;
      stream->push_headers = malloc(stream->push_headers_alloc *
                                    sizeof(char *));
      stream->push_headers_used = 0;
    }
    else if(stream->push_headers_used ==
            stream->push_headers_alloc) {
      char **headp;
      stream->push_headers_alloc *= 2;
      headp = realloc(stream->push_headers,
                      stream->push_headers_alloc * sizeof(char *));
      if(!headp) {
        free(stream->push_headers);
        stream->push_headers = NULL;
        return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
      }
      stream->push_headers = headp;
    }
    h = aprintf("%s:%s", name, value);
    if(h)
      stream->push_headers[stream->push_headers_used++] = h;
    return 0;
  }

  if(namelen == sizeof(":status") - 1 &&
     memcmp(":status", name, namelen) == 0) {
    /* nghttp2 guarantees :status is received first and only once, and
       value is 3 digits status code, and decode_status_code always
       succeeds. */
    stream->status_code = decode_status_code(value, valuelen);
    DEBUGASSERT(stream->status_code != -1);

    Curl_add_buffer(stream->header_recvbuf, "HTTP/2.0 ", 9);
    Curl_add_buffer(stream->header_recvbuf, value, valuelen);
    Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
    data_s->state.drain++;
    Curl_expire(data_s, 1);

    DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d\n",
                 stream->status_code));
    return 0;
  }

  /* nghttp2 guarantees that namelen > 0, and :status was already
     received, and this is not pseudo-header field . */
  /* convert to a HTTP1-style header */
  Curl_add_buffer(stream->header_recvbuf, name, namelen);
  Curl_add_buffer(stream->header_recvbuf, ":", 1);
  Curl_add_buffer(stream->header_recvbuf, value, valuelen);
  Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
  data_s->state.drain++;
  Curl_expire(data_s, 1);

  DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen,
               value));

  return 0; /* 0 is successful */
}