mirror of
https://github.com/libgit2/libgit2.git
synced 2026-01-25 02:56:17 +00:00
http: abstract http parsing out of httpclient
Avoid #ifdef's in httpclient.c, and move http parsing into its own file.
This commit is contained in:
@@ -1,39 +1,32 @@
|
||||
# Optional external dependency: http-parser
|
||||
if(USE_HTTP_PARSER STREQUAL "builtin")
|
||||
message(STATUS "support for bundled (legacy) http-parser explicitly requested")
|
||||
if(USE_HTTP_PARSER STREQUAL "http-parser")
|
||||
find_package(HTTPParser)
|
||||
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/deps/http-parser" "${PROJECT_BINARY_DIR}/deps/http-parser")
|
||||
list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/http-parser")
|
||||
list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$<TARGET_OBJECTS:http-parser>")
|
||||
add_feature_info(http-parser ON "http-parser support (bundled)")
|
||||
else()
|
||||
# By default, try to use system LLHTTP. Fall back to
|
||||
# system http-parser, and even to bundled http-parser
|
||||
# as a last resort.
|
||||
find_package(LLHTTP)
|
||||
if(HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2)
|
||||
list(APPEND LIBGIT2_SYSTEM_INCLUDES ${HTTP_PARSER_INCLUDE_DIRS})
|
||||
list(APPEND LIBGIT2_SYSTEM_LIBS ${HTTP_PARSER_LIBRARIES})
|
||||
list(APPEND LIBGIT2_PC_LIBS "-lhttp_parser")
|
||||
set(GIT_HTTPPARSER_HTTPPARSER 1)
|
||||
add_feature_info(http-parser ON "using http-parser (system)")
|
||||
else()
|
||||
message(FATAL_ERROR "http-parser support was requested but not found")
|
||||
endif()
|
||||
elseif(USE_HTTP_PARSER STREQUAL "llhttp")
|
||||
find_package(LLHTTP)
|
||||
|
||||
if(LLHTTP_FOUND AND LLHTTP_VERSION_MAJOR EQUAL 9)
|
||||
add_compile_definitions(USE_LLHTTP)
|
||||
list(APPEND LIBGIT2_SYSTEM_INCLUDES ${LLHTTP_INCLUDE_DIRS})
|
||||
list(APPEND LIBGIT2_SYSTEM_LIBS ${LLHTTP_LIBRARIES})
|
||||
list(APPEND LIBGIT2_PC_LIBS "-lllhttp")
|
||||
add_feature_info(llhttp ON "llhttp support (system)")
|
||||
set(GIT_HTTPPARSER_LLHTTP 1)
|
||||
add_feature_info(http-parser ON "using llhttp (system)")
|
||||
else()
|
||||
message(STATUS "llhttp support was requested but not found; checking (legacy) http-parser support")
|
||||
find_package(HTTPParser)
|
||||
|
||||
if(HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2)
|
||||
list(APPEND LIBGIT2_SYSTEM_INCLUDES ${HTTP_PARSER_INCLUDE_DIRS})
|
||||
list(APPEND LIBGIT2_SYSTEM_LIBS ${HTTP_PARSER_LIBRARIES})
|
||||
list(APPEND LIBGIT2_PC_LIBS "-lhttp_parser")
|
||||
add_feature_info(http-parser ON "http-parser support (system)")
|
||||
else()
|
||||
message(STATUS "neither llhttp nor http-parser support was found; proceeding with bundled (legacy) http-parser")
|
||||
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/deps/http-parser" "${PROJECT_BINARY_DIR}/deps/http-parser")
|
||||
list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/http-parser")
|
||||
list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$<TARGET_OBJECTS:http-parser>")
|
||||
add_feature_info(http-parser ON "http-parser support (bundled)")
|
||||
endif()
|
||||
endif()
|
||||
message(FATAL_ERROR "llhttp support was requested but not found")
|
||||
endif()
|
||||
else()
|
||||
add_subdirectory("${PROJECT_SOURCE_DIR}/deps/http-parser" "${PROJECT_BINARY_DIR}/deps/http-parser")
|
||||
list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/http-parser")
|
||||
list(APPEND LIBGIT2_DEPENDENCY_OBJECTS "$<TARGET_OBJECTS:http-parser>")
|
||||
set(GIT_HTTPPARSER_BUILTIN 1)
|
||||
add_feature_info(http-parser ON "using bundled parser")
|
||||
endif()
|
||||
|
||||
@@ -8,31 +8,6 @@
|
||||
#include "common.h"
|
||||
#include "git2.h"
|
||||
|
||||
#ifdef USE_LLHTTP
|
||||
#include <llhttp.h>
|
||||
typedef llhttp_settings_t http_settings_t;
|
||||
typedef llhttp_t http_parser_t;
|
||||
GIT_INLINE(http_settings_t *) http_client_parser_settings(void);
|
||||
#define git_http_parser_init(parser) llhttp_init(parser, HTTP_RESPONSE, http_client_parser_settings())
|
||||
#define git_http_parser_pause(parser) llhttp_pause(parser)
|
||||
#define git_http_parser_resume(parser) llhttp_resume(parser)
|
||||
#define git_http_parser_errno(parser) parser.error
|
||||
#define git_http_should_keep_alive(parser) llhttp_should_keep_alive(parser)
|
||||
#define git_http_errno_description(parser, errno) llhttp_get_error_reason(parser)
|
||||
#else
|
||||
#include <http_parser.h>
|
||||
/* Legacy http-parser. */
|
||||
typedef http_parser_settings http_settings_t;
|
||||
typedef struct http_parser http_parser_t;
|
||||
GIT_INLINE(http_settings_t *) http_client_parser_settings(void);
|
||||
#define git_http_parser_init(parser) http_parser_init(parser, HTTP_RESPONSE)
|
||||
#define git_http_parser_pause(parser) http_parser_pause(parser, 1)
|
||||
#define git_http_parser_resume(parser) http_parser_pause(parser, 0)
|
||||
#define git_http_parser_errno(parser) parser.http_errno
|
||||
#define git_http_should_keep_alive(parser) http_should_keep_alive(parser)
|
||||
#define git_http_errno_description(parser, errno) http_errno_description(errno)
|
||||
#endif /* USE_LLHTTP */
|
||||
|
||||
#include "vector.h"
|
||||
#include "trace.h"
|
||||
#include "httpclient.h"
|
||||
@@ -46,6 +21,7 @@ GIT_INLINE(http_settings_t *) http_client_parser_settings(void);
|
||||
#include "streams/socket.h"
|
||||
#include "streams/tls.h"
|
||||
#include "auth.h"
|
||||
#include "httpparser.h"
|
||||
|
||||
static git_http_auth_scheme auth_schemes[] = {
|
||||
{ GIT_HTTP_AUTH_NEGOTIATE, "Negotiate", GIT_CREDENTIAL_DEFAULT, git_http_auth_negotiate },
|
||||
@@ -133,7 +109,7 @@ struct git_http_client {
|
||||
git_http_server_t current_server;
|
||||
http_client_state state;
|
||||
|
||||
http_parser_t parser;
|
||||
git_http_parser parser;
|
||||
|
||||
git_http_server server;
|
||||
git_http_server proxy;
|
||||
@@ -179,7 +155,7 @@ void git_http_response_dispose(git_http_response *response)
|
||||
memset(response, 0, sizeof(git_http_response));
|
||||
}
|
||||
|
||||
static int on_header_complete(http_parser_t *parser)
|
||||
static int on_header_complete(git_http_parser *parser)
|
||||
{
|
||||
http_parser_context *ctx = (http_parser_context *) parser->data;
|
||||
git_http_client *client = ctx->client;
|
||||
@@ -244,7 +220,7 @@ static int on_header_complete(http_parser_t *parser)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_header_field(http_parser_t *parser, const char *str, size_t len)
|
||||
static int on_header_field(git_http_parser *parser, const char *str, size_t len)
|
||||
{
|
||||
http_parser_context *ctx = (http_parser_context *) parser->data;
|
||||
|
||||
@@ -279,7 +255,7 @@ static int on_header_field(http_parser_t *parser, const char *str, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_header_value(http_parser_t *parser, const char *str, size_t len)
|
||||
static int on_header_value(git_http_parser *parser, const char *str, size_t len)
|
||||
{
|
||||
http_parser_context *ctx = (http_parser_context *) parser->data;
|
||||
|
||||
@@ -367,7 +343,7 @@ static int resend_needed(git_http_client *client, git_http_response *response)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_headers_complete(http_parser_t *parser)
|
||||
static int on_headers_complete(git_http_parser *parser)
|
||||
{
|
||||
http_parser_context *ctx = (http_parser_context *) parser->data;
|
||||
|
||||
@@ -389,8 +365,8 @@ static int on_headers_complete(http_parser_t *parser)
|
||||
return ctx->parse_status = PARSE_STATUS_ERROR;
|
||||
}
|
||||
|
||||
ctx->response->status = parser->status_code;
|
||||
ctx->client->keepalive = git_http_should_keep_alive(parser);
|
||||
ctx->response->status = git_http_parser_status_code(parser);
|
||||
ctx->client->keepalive = git_http_parser_keep_alive(parser);
|
||||
|
||||
/* Prepare for authentication */
|
||||
collect_authinfo(&ctx->response->server_auth_schemetypes,
|
||||
@@ -403,28 +379,15 @@ static int on_headers_complete(http_parser_t *parser)
|
||||
ctx->response->resend_credentials = resend_needed(ctx->client,
|
||||
ctx->response);
|
||||
|
||||
#ifndef USE_LLHTTP
|
||||
/* Stop parsing. llhttp documentation says about llhttp_pause():
|
||||
* "Do not call this from user callbacks! User callbacks must
|
||||
* return HPE_PAUSED if pausing is required", so that's what
|
||||
* we will do, and call git_http_parser_pause() only for
|
||||
* http-parser. */
|
||||
git_http_parser_pause(parser);
|
||||
#endif
|
||||
|
||||
if (ctx->response->content_type || ctx->response->chunked)
|
||||
ctx->client->state = READING_BODY;
|
||||
else
|
||||
ctx->client->state = DONE;
|
||||
|
||||
#ifdef USE_LLHTTP
|
||||
return HPE_PAUSED;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
return git_http_parser_pause(parser);
|
||||
}
|
||||
|
||||
static int on_body(http_parser_t *parser, const char *buf, size_t len)
|
||||
static int on_body(git_http_parser *parser, const char *buf, size_t len)
|
||||
{
|
||||
http_parser_context *ctx = (http_parser_context *) parser->data;
|
||||
size_t max_len;
|
||||
@@ -446,7 +409,7 @@ static int on_body(http_parser_t *parser, const char *buf, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_message_complete(http_parser_t *parser)
|
||||
static int on_message_complete(git_http_parser *parser)
|
||||
{
|
||||
http_parser_context *ctx = (http_parser_context *) parser->data;
|
||||
|
||||
@@ -911,9 +874,29 @@ GIT_INLINE(int) server_setup_from_url(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool parser_settings_initialized;
|
||||
static git_http_parser_settings parser_settings;
|
||||
|
||||
GIT_INLINE(git_http_parser_settings *) http_client_parser_settings(void)
|
||||
{
|
||||
if (!parser_settings_initialized) {
|
||||
parser_settings.on_header_field = on_header_field;
|
||||
parser_settings.on_header_value = on_header_value;
|
||||
parser_settings.on_headers_complete = on_headers_complete;
|
||||
parser_settings.on_body = on_body;
|
||||
parser_settings.on_message_complete = on_message_complete;
|
||||
|
||||
parser_settings_initialized = true;
|
||||
}
|
||||
|
||||
return &parser_settings;
|
||||
}
|
||||
|
||||
static void reset_parser(git_http_client *client)
|
||||
{
|
||||
git_http_parser_init(&client->parser);
|
||||
git_http_parser_init(&client->parser,
|
||||
GIT_HTTP_PARSER_RESPONSE,
|
||||
http_client_parser_settings());
|
||||
}
|
||||
|
||||
static int setup_hosts(
|
||||
@@ -1156,64 +1139,9 @@ GIT_INLINE(int) client_read(git_http_client *client)
|
||||
return (int)read_len;
|
||||
}
|
||||
|
||||
static bool parser_settings_initialized;
|
||||
static http_settings_t parser_settings;
|
||||
|
||||
static size_t git_http_parser_execute(http_parser_t *parser, const char* data, size_t len)
|
||||
{
|
||||
#ifdef USE_LLHTTP
|
||||
llhttp_errno_t error;
|
||||
size_t parsed_len;
|
||||
|
||||
/*
|
||||
* Unlike http_parser, which returns the number of parsed
|
||||
* bytes in the _execute() call, llhttp returns an error
|
||||
* code.
|
||||
*/
|
||||
|
||||
if (data == NULL || len == 0) {
|
||||
error = llhttp_finish(parser);
|
||||
} else {
|
||||
error = llhttp_execute(parser, data, len);
|
||||
}
|
||||
|
||||
parsed_len = len;
|
||||
/*
|
||||
* Adjust number of parsed bytes in case of error.
|
||||
*/
|
||||
if (error != HPE_OK) {
|
||||
parsed_len = llhttp_get_error_pos(parser) - data;
|
||||
|
||||
/* This isn't a real pause, just a way to stop parsing early. */
|
||||
if (error == HPE_PAUSED_UPGRADE) {
|
||||
llhttp_resume_after_upgrade(parser);
|
||||
}
|
||||
}
|
||||
|
||||
return parsed_len;
|
||||
#else
|
||||
return http_parser_execute(parser, http_client_parser_settings(), data, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
GIT_INLINE(http_settings_t *) http_client_parser_settings(void)
|
||||
{
|
||||
if (!parser_settings_initialized) {
|
||||
parser_settings.on_header_field = on_header_field;
|
||||
parser_settings.on_header_value = on_header_value;
|
||||
parser_settings.on_headers_complete = on_headers_complete;
|
||||
parser_settings.on_body = on_body;
|
||||
parser_settings.on_message_complete = on_message_complete;
|
||||
|
||||
parser_settings_initialized = true;
|
||||
}
|
||||
|
||||
return &parser_settings;
|
||||
}
|
||||
|
||||
GIT_INLINE(int) client_read_and_parse(git_http_client *client)
|
||||
{
|
||||
http_parser_t *parser = &client->parser;
|
||||
git_http_parser *parser = &client->parser;
|
||||
http_parser_context *ctx = (http_parser_context *) parser->data;
|
||||
unsigned char http_errno;
|
||||
int read_len;
|
||||
@@ -1230,7 +1158,7 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client)
|
||||
parsed_len = git_http_parser_execute(parser,
|
||||
client->read_buf.ptr,
|
||||
client->read_buf.size);
|
||||
http_errno = git_http_parser_errno(client->parser);
|
||||
http_errno = git_http_parser_errno(parser);
|
||||
|
||||
if (parsed_len > INT_MAX) {
|
||||
git_error_set(GIT_ERROR_HTTP, "unexpectedly large parse");
|
||||
@@ -1249,29 +1177,29 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client)
|
||||
* (This can happen in response to an expect/continue request,
|
||||
* where the server gives you a 100 and 200 simultaneously.)
|
||||
*/
|
||||
if (http_errno == HPE_PAUSED) {
|
||||
#ifndef USE_LLHTTP
|
||||
/*
|
||||
* http-parser has a "feature" where it will not deliver the
|
||||
* final byte when paused in a callback. Consume that byte.
|
||||
* https://github.com/nodejs/http-parser/issues/97
|
||||
*/
|
||||
GIT_ASSERT(client->read_buf.size > parsed_len);
|
||||
if (http_errno == GIT_HTTP_PARSER_PAUSED) {
|
||||
size_t additional_size;
|
||||
|
||||
#endif
|
||||
git_http_parser_resume(parser);
|
||||
|
||||
#ifndef USE_LLHTTP
|
||||
parsed_len += git_http_parser_execute(parser,
|
||||
client->read_buf.ptr + parsed_len,
|
||||
1);
|
||||
#endif
|
||||
/*
|
||||
* http-parser has a "feature" where it will not deliver
|
||||
* the final byte when paused in a callback. Consume
|
||||
* that byte.
|
||||
*/
|
||||
if ((additional_size = git_http_parser_remain_after_pause(parser)) > 0) {
|
||||
GIT_ASSERT((client->read_buf.size - parsed_len) >= additional_size);
|
||||
|
||||
parsed_len += git_http_parser_execute(parser,
|
||||
client->read_buf.ptr + parsed_len,
|
||||
additional_size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Most failures will be reported in http_errno */
|
||||
else if (git_http_parser_errno(client->parser) != HPE_OK) {
|
||||
else if (git_http_parser_errno(parser) != GIT_HTTP_PARSER_OK) {
|
||||
git_error_set(GIT_ERROR_HTTP, "http parser error: %s",
|
||||
git_http_errno_description(parser, http_errno));
|
||||
git_http_parser_errmsg(parser, http_errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1279,7 +1207,7 @@ GIT_INLINE(int) client_read_and_parse(git_http_client *client)
|
||||
else if (parsed_len != client->read_buf.size) {
|
||||
git_error_set(GIT_ERROR_HTTP,
|
||||
"http parser did not consume entire buffer: %s",
|
||||
git_http_errno_description(parser, http_errno));
|
||||
git_http_parser_errmsg(parser, http_errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1318,7 +1246,7 @@ static void complete_response_body(git_http_client *client)
|
||||
|
||||
/* If there was an error, just close the connection. */
|
||||
if (client_read_and_parse(client) < 0 ||
|
||||
parser_context.error != HPE_OK ||
|
||||
parser_context.error != GIT_HTTP_PARSER_OK ||
|
||||
(parser_context.parse_status != PARSE_STATUS_OK &&
|
||||
parser_context.parse_status != PARSE_STATUS_NO_OUTPUT)) {
|
||||
git_error_clear();
|
||||
@@ -1596,7 +1524,7 @@ int git_http_client_skip_body(git_http_client *client)
|
||||
do {
|
||||
error = client_read_and_parse(client);
|
||||
|
||||
if (parser_context.error != HPE_OK ||
|
||||
if (parser_context.error != GIT_HTTP_PARSER_OK ||
|
||||
(parser_context.parse_status != PARSE_STATUS_OK &&
|
||||
parser_context.parse_status != PARSE_STATUS_NO_OUTPUT)) {
|
||||
git_error_set(GIT_ERROR_HTTP,
|
||||
|
||||
126
src/libgit2/transports/httpparser.c
Normal file
126
src/libgit2/transports/httpparser.c
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright (C) the libgit2 contributors. All rights reserved.
|
||||
*
|
||||
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
|
||||
#include "httpparser.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if defined(GIT_HTTPPARSER_HTTPPARSER) || defined(GIT_HTTPPARSER_BUILTIN)
|
||||
|
||||
#include "http_parser.h"
|
||||
|
||||
static int on_message_begin(http_parser *p)
|
||||
{
|
||||
git_http_parser *parser = (git_http_parser *)p;
|
||||
return parser->settings.on_message_begin(parser);
|
||||
}
|
||||
|
||||
static int on_url(http_parser *p, const char *str, size_t len)
|
||||
{
|
||||
git_http_parser *parser = (git_http_parser *)p;
|
||||
return parser->settings.on_url(parser, str, len);
|
||||
}
|
||||
|
||||
static int on_header_field(http_parser *p, const char *str, size_t len)
|
||||
{
|
||||
git_http_parser *parser = (git_http_parser *)p;
|
||||
return parser->settings.on_header_field(parser, str, len);
|
||||
}
|
||||
|
||||
static int on_header_value(http_parser *p, const char *str, size_t len)
|
||||
{
|
||||
git_http_parser *parser = (git_http_parser *)p;
|
||||
return parser->settings.on_header_value(parser, str, len);
|
||||
}
|
||||
|
||||
static int on_headers_complete(http_parser *p)
|
||||
{
|
||||
git_http_parser *parser = (git_http_parser *)p;
|
||||
return parser->settings.on_headers_complete(parser);
|
||||
}
|
||||
|
||||
static int on_body(http_parser *p, const char *buf, size_t len)
|
||||
{
|
||||
git_http_parser *parser = (git_http_parser *)p;
|
||||
return parser->settings.on_body(parser, buf, len);
|
||||
}
|
||||
|
||||
static int on_message_complete(http_parser *p)
|
||||
{
|
||||
git_http_parser *parser = (git_http_parser *)p;
|
||||
return parser->settings.on_message_complete(parser);
|
||||
}
|
||||
|
||||
void git_http_parser_init(
|
||||
git_http_parser *parser,
|
||||
git_http_parser_t type,
|
||||
git_http_parser_settings *settings)
|
||||
{
|
||||
http_parser_init(&parser->parser, (enum http_parser_type)type);
|
||||
memcpy(&parser->settings, settings, sizeof(git_http_parser_settings));
|
||||
}
|
||||
|
||||
size_t git_http_parser_execute(
|
||||
git_http_parser *parser,
|
||||
const char *data,
|
||||
size_t len)
|
||||
{
|
||||
struct http_parser_settings settings_proxy;
|
||||
|
||||
settings_proxy.on_message_begin = parser->settings.on_message_begin ? on_message_begin : NULL;
|
||||
settings_proxy.on_url = parser->settings.on_url ? on_url : NULL;
|
||||
settings_proxy.on_header_field = parser->settings.on_header_field ? on_header_field : NULL;
|
||||
settings_proxy.on_header_value = parser->settings.on_header_value ? on_header_value : NULL;
|
||||
settings_proxy.on_headers_complete = parser->settings.on_headers_complete ? on_headers_complete : NULL;
|
||||
settings_proxy.on_body = parser->settings.on_body ? on_body : NULL;
|
||||
settings_proxy.on_message_complete = parser->settings.on_message_complete ? on_message_complete : NULL;
|
||||
|
||||
return http_parser_execute(&parser->parser, &settings_proxy, data, len);
|
||||
}
|
||||
|
||||
#elif defined(GIT_HTTPPARSER_LLHTTP)
|
||||
|
||||
# include <llhttp.h>
|
||||
|
||||
size_t git_http_parser_execute(
|
||||
git_http_parser *parser,
|
||||
const char* data,
|
||||
size_t len)
|
||||
{
|
||||
llhttp_errno_t error;
|
||||
size_t parsed_len;
|
||||
|
||||
/*
|
||||
* Unlike http_parser, which returns the number of parsed
|
||||
* bytes in the _execute() call, llhttp returns an error
|
||||
* code.
|
||||
*/
|
||||
|
||||
if (data == NULL || len == 0)
|
||||
error = llhttp_finish(parser);
|
||||
else
|
||||
error = llhttp_execute(parser, data, len);
|
||||
|
||||
parsed_len = len;
|
||||
|
||||
/*
|
||||
* Adjust number of parsed bytes in case of error.
|
||||
*/
|
||||
if (error != HPE_OK) {
|
||||
parsed_len = llhttp_get_error_pos(parser) - data;
|
||||
|
||||
/* This isn't a real pause, just a way to stop parsing early. */
|
||||
if (error == HPE_PAUSED_UPGRADE)
|
||||
llhttp_resume_after_upgrade(parser);
|
||||
}
|
||||
|
||||
return parsed_len;
|
||||
}
|
||||
|
||||
#else
|
||||
# error unknown http-parser
|
||||
#endif
|
||||
99
src/libgit2/transports/httpparser.h
Normal file
99
src/libgit2/transports/httpparser.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) the libgit2 contributors. All rights reserved.
|
||||
*
|
||||
* This file is part of libgit2, distributed under the GNU GPL v2 with
|
||||
* a Linking Exception. For full terms see the included COPYING file.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_transports_httpparser_h__
|
||||
#define INCLUDE_transports_httpparser_h__
|
||||
|
||||
#include "git2_util.h"
|
||||
|
||||
#if defined(GIT_HTTPPARSER_HTTPPARSER) || defined(GIT_HTTPPARSER_BUILTIN)
|
||||
|
||||
# include <http_parser.h>
|
||||
|
||||
typedef enum {
|
||||
GIT_HTTP_PARSER_OK = HPE_OK,
|
||||
GIT_HTTP_PARSER_PAUSED = HPE_PAUSED,
|
||||
} git_http_parser_error_t;
|
||||
|
||||
typedef enum {
|
||||
GIT_HTTP_PARSER_REQUEST = HTTP_REQUEST,
|
||||
GIT_HTTP_PARSER_RESPONSE = HTTP_RESPONSE,
|
||||
} git_http_parser_t;
|
||||
|
||||
typedef struct git_http_parser git_http_parser;
|
||||
|
||||
typedef struct {
|
||||
int (*on_message_begin)(git_http_parser *);
|
||||
int (*on_url)(git_http_parser *, const char *, size_t);
|
||||
int (*on_header_field)(git_http_parser *, const char *, size_t);
|
||||
int (*on_header_value)(git_http_parser *, const char *, size_t);
|
||||
int (*on_headers_complete)(git_http_parser *);
|
||||
int (*on_body)(git_http_parser *, const char *, size_t);
|
||||
int (*on_message_complete)(git_http_parser *);
|
||||
} git_http_parser_settings;
|
||||
|
||||
struct git_http_parser {
|
||||
http_parser parser;
|
||||
git_http_parser_settings settings;
|
||||
void *data;
|
||||
};
|
||||
|
||||
void git_http_parser_init(
|
||||
git_http_parser *parser,
|
||||
git_http_parser_t type,
|
||||
git_http_parser_settings *settings);
|
||||
|
||||
size_t git_http_parser_execute(
|
||||
git_http_parser *parser,
|
||||
const char *data,
|
||||
size_t len);
|
||||
|
||||
# define git_http_parser_status_code(parser) parser->parser.status_code
|
||||
# define git_http_parser_keep_alive(parser) http_should_keep_alive(&parser->parser)
|
||||
# define git_http_parser_pause(parser) (http_parser_pause(&parser->parser, 1), 0)
|
||||
# define git_http_parser_resume(parser) http_parser_pause(&parser->parser, 0)
|
||||
# define git_http_parser_remain_after_pause(parser) 1
|
||||
# define git_http_parser_errno(parser) parser->parser.http_errno
|
||||
# define git_http_parser_errmsg(parser, errno) http_errno_description(errno)
|
||||
|
||||
#elif defined(GIT_HTTPPARSER_LLHTTP)
|
||||
|
||||
# include <llhttp.h>
|
||||
|
||||
typedef enum {
|
||||
GIT_HTTP_PARSER_OK = HPE_OK,
|
||||
GIT_HTTP_PARSER_PAUSED = HPE_PAUSED,
|
||||
} git_http_parser_error_t;
|
||||
|
||||
typedef enum {
|
||||
GIT_HTTP_PARSER_REQUEST = HTTP_REQUEST,
|
||||
GIT_HTTP_PARSER_RESPONSE = HTTP_RESPONSE,
|
||||
} git_http_parser_t;
|
||||
|
||||
typedef llhttp_t git_http_parser;
|
||||
typedef llhttp_settings_t git_http_parser_settings;
|
||||
|
||||
# define git_http_parser_init(parser, direction, settings) llhttp_init(parser, (llhttp_type_t)direction, settings)
|
||||
|
||||
size_t git_http_parser_execute(
|
||||
git_http_parser *parser,
|
||||
const char *data,
|
||||
size_t len);
|
||||
|
||||
# define git_http_parser_status_code(parser) parser->status_code
|
||||
# define git_http_parser_keep_alive(parser) llhttp_should_keep_alive(parser)
|
||||
# define git_http_parser_pause(parser) (llhttp_pause(parser), GIT_HTTP_PARSER_PAUSED)
|
||||
# define git_http_parser_resume(parser) llhttp_resume(parser)
|
||||
# define git_http_parser_remain_after_pause(parser) 0
|
||||
# define git_http_parser_errno(parser) parser->error
|
||||
# define git_http_parser_errmsg(parser, errno) llhttp_get_error_reason(parser)
|
||||
|
||||
#else
|
||||
# error unknown http-parser
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -46,6 +46,10 @@
|
||||
#cmakedefine GIT_MBEDTLS 1
|
||||
#cmakedefine GIT_SCHANNEL 1
|
||||
|
||||
#cmakedefine GIT_HTTPPARSER_HTTPPARSER 1
|
||||
#cmakedefine GIT_HTTPPARSER_LLHTTP 1
|
||||
#cmakedefine GIT_HTTPPARSER_BUILTIN 1
|
||||
|
||||
#cmakedefine GIT_SHA1_COLLISIONDETECT 1
|
||||
#cmakedefine GIT_SHA1_WIN32 1
|
||||
#cmakedefine GIT_SHA1_COMMON_CRYPTO 1
|
||||
|
||||
Reference in New Issue
Block a user