diff --git a/lib/includes/nghttp2/nghttp2.h b/lib/includes/nghttp2/nghttp2.h index 83d4173a..acfe6ecb 100644 --- a/lib/includes/nghttp2/nghttp2.h +++ b/lib/includes/nghttp2/nghttp2.h @@ -4136,6 +4136,36 @@ typedef struct { size_t field_value_len; } nghttp2_ext_altsvc; +/** + * @function + * + * Submits ALTSVC frame. + * + * The |flags| is currently ignored and should be + * :enum:`NGHTTP2_FLAG_NONE`. + * + * The |origin| points to the origin this alternative service is + * associated with. The |origin_len| is the length of the origin. If + * |stream_id| is 0, the origin must be specified. If |stream_id| is + * not zero, the origin must be empty (in other words, |origin_len| + * must be 0). + * + * The ALTSVC frame is only usable from server side. If this function + * is invoked with client side session, this function returns + * :enum:`NGHTTP2_ERR_INVALID_STATE`. + * + * This function returns 0 if it succeeds, or one of the following + * negative error codes: + * + * :enum:`NGHTTP2_ERR_NOMEM` + * Out of memory + * :enum:`NGHTTP2_ERR_INVALID_STATE` + * The function is called from client side session + * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT` + * The sum of |origin_len| and |field_value_len| is larger than + * 16382; or |origin_len| is 0 while |stream_id| is 0; or + * |origin_len| is not 0 while |stream_id| is not 0. + */ NGHTTP2_EXTERN int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags, int32_t stream_id, const uint8_t *origin, diff --git a/lib/nghttp2_submit.c b/lib/nghttp2_submit.c index fc0663ce..3c6a3664 100644 --- a/lib/nghttp2_submit.c +++ b/lib/nghttp2_submit.c @@ -425,10 +425,22 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags _U_, mem = &session->mem; + if (!session->server) { + return NGHTTP2_ERR_INVALID_STATE; + } + if (2 + origin_len + field_value_len > NGHTTP2_MAX_PAYLOADLEN) { return NGHTTP2_ERR_INVALID_ARGUMENT; } + if (stream_id == 0) { + if (origin_len == 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + } else if (origin_len != 0) { + return NGHTTP2_ERR_INVALID_ARGUMENT; + } + buf = nghttp2_mem_malloc(mem, origin_len + field_value_len + 2); if (buf == NULL) { return NGHTTP2_ERR_NOMEM; @@ -437,11 +449,15 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags _U_, p = buf; origin_copy = p; - p = nghttp2_cpymem(p, origin, origin_len); + if (origin_len) { + p = nghttp2_cpymem(p, origin, origin_len); + } *p++ = '\0'; field_value_copy = p; - p = nghttp2_cpymem(p, field_value, field_value_len); + if (field_value_len) { + p = nghttp2_cpymem(p, field_value, field_value_len); + } *p++ = '\0'; item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item)); @@ -470,6 +486,8 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags _U_, if (rv != 0) { nghttp2_frame_altsvc_free(&frame->ext, mem); nghttp2_mem_free(mem, item); + + return rv; } return 0;