diff options
Diffstat (limited to 'libsoup')
-rw-r--r-- | libsoup/http2/soup-client-message-io-http2.c | 172 | ||||
-rw-r--r-- | libsoup/meson.build | 1 | ||||
-rw-r--r-- | libsoup/server/http2/soup-server-message-io-http2.c | 71 | ||||
-rw-r--r-- | libsoup/soup-http2-utils.c | 114 | ||||
-rw-r--r-- | libsoup/soup-http2-utils.h | 49 |
5 files changed, 186 insertions, 221 deletions
diff --git a/libsoup/http2/soup-client-message-io-http2.c b/libsoup/http2/soup-client-message-io-http2.c index 39c9eb2f..8ee95e8a 100644 --- a/libsoup/http2/soup-client-message-io-http2.c +++ b/libsoup/http2/soup-client-message-io-http2.c @@ -40,25 +40,13 @@ #include "soup-client-input-stream.h" #include "soup-logger-private.h" #include "soup-uri-utils-private.h" +#include "soup-http2-utils.h" #include "content-decoder/soup-content-decoder.h" #include "soup-body-input-stream-http2.h" -#include <nghttp2/nghttp2.h> - #define FRAME_HEADER_SIZE 9 -typedef enum { - STATE_NONE, - STATE_WRITE_HEADERS, - STATE_WRITE_DATA, - STATE_WRITE_DONE, - STATE_READ_HEADERS, - STATE_READ_DATA_START, - STATE_READ_DATA, - STATE_READ_DONE, -} SoupHTTP2IOState; - typedef struct { SoupClientMessageIO iface; @@ -127,93 +115,6 @@ typedef struct { static void soup_client_message_io_http2_finished (SoupClientMessageIO *iface, SoupMessage *msg); static ssize_t on_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 *user_data); -static void -NGCHECK (int return_code) -{ - if (return_code == NGHTTP2_ERR_NOMEM) - g_abort (); - else if (return_code < 0) - g_debug ("Unhandled NGHTTP2 Error: %s", nghttp2_strerror (return_code)); -} - -static const char * -frame_type_to_string (nghttp2_frame_type type) -{ - switch (type) { - case NGHTTP2_DATA: - return "DATA"; - case NGHTTP2_HEADERS: - return "HEADERS"; - case NGHTTP2_PRIORITY: - return "PRIORITY"; - case NGHTTP2_RST_STREAM: - return "RST_STREAM"; - case NGHTTP2_SETTINGS: - return "SETTINGS"; - case NGHTTP2_PING: - return "PING"; - case NGHTTP2_GOAWAY: - return "GOAWAY"; - case NGHTTP2_WINDOW_UPDATE: - return "WINDOW_UPDATE"; - /* LCOV_EXCL_START */ - case NGHTTP2_PUSH_PROMISE: - return "PUSH_PROMISE"; - case NGHTTP2_CONTINUATION: - return "CONTINUATION"; - case NGHTTP2_ALTSVC: - return "ALTSVC"; - case NGHTTP2_ORIGIN: - return "ORIGIN"; - default: - g_warn_if_reached (); - return "UNKNOWN"; - /* LCOV_EXCL_STOP */ - } -} - -static const char * -headers_category_to_string (nghttp2_headers_category catergory) -{ - switch (catergory) { - case NGHTTP2_HCAT_REQUEST: - return "REQUEST"; - case NGHTTP2_HCAT_RESPONSE: - return "RESPONSE"; - case NGHTTP2_HCAT_PUSH_RESPONSE: - return "PUSH_RESPONSE"; - case NGHTTP2_HCAT_HEADERS: - return "HEADERS"; - } - g_assert_not_reached (); -} - -static const char * -state_to_string (SoupHTTP2IOState state) -{ - switch (state) { - case STATE_NONE: - return "NONE"; - case STATE_WRITE_HEADERS: - return "WRITE_HEADERS"; - case STATE_WRITE_DATA: - return "WRITE_DATA"; - case STATE_WRITE_DONE: - return "WRITE_DONE"; - case STATE_READ_HEADERS: - return "READ_HEADERS"; - case STATE_READ_DATA_START: - return "READ_DATA_START"; - case STATE_READ_DATA: - return "READ_DATA"; - case STATE_READ_DONE: - return "READ_DONE"; - default: - g_assert_not_reached (); - return ""; - } -} - G_GNUC_PRINTF(3, 0) static void h2_debug (SoupClientMessageIOHTTP2 *io, @@ -236,7 +137,7 @@ h2_debug (SoupClientMessageIOHTTP2 *io, stream_id = data->stream_id; g_assert (io); - g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "[C%" G_GUINT64_FORMAT "-S%u] [%s] %s", io->connection_id, stream_id, data ? state_to_string (data->state) : "-", message); + g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "[C%" G_GUINT64_FORMAT "-S%u] [%s] %s", io->connection_id, stream_id, data ? soup_http2_io_state_to_string (data->state) : "-", message); g_free (message); } @@ -288,20 +189,20 @@ advance_state_from (SoupHTTP2MessageData *data, { if (data->state != from) { g_warning ("Unexpected state changed %s -> %s, expected to be from %s", - state_to_string (data->state), state_to_string (to), - state_to_string (from)); + soup_http2_io_state_to_string (data->state), soup_http2_io_state_to_string (to), + soup_http2_io_state_to_string (from)); } /* State never goes backwards */ if (to < data->state) { g_warning ("Unexpected state changed %s -> %s, expected %s -> %s\n", - state_to_string (data->state), state_to_string (to), - state_to_string (from), state_to_string (to)); + soup_http2_io_state_to_string (data->state), soup_http2_io_state_to_string (to), + soup_http2_io_state_to_string (from), soup_http2_io_state_to_string (to)); return; } h2_debug (data->io, data, "[SESSION] State %s -> %s", - state_to_string (data->state), state_to_string (to)); + soup_http2_io_state_to_string (data->state), soup_http2_io_state_to_string (to)); data->state = to; } @@ -617,7 +518,7 @@ on_begin_frame_callback (nghttp2_session *session, { SoupHTTP2MessageData *data = nghttp2_session_get_stream_user_data (session, hd->stream_id); - h2_debug (user_data, data, "[RECV] [%s] Beginning", frame_type_to_string (hd->type)); + h2_debug (user_data, data, "[RECV] [%s] Beginning", soup_http2_frame_type_to_string (hd->type)); if (!data) return 0; @@ -688,7 +589,7 @@ on_frame_recv_callback (nghttp2_session *session, io->in_callback++; if (frame->hd.stream_id == 0) { - h2_debug (io, NULL, "[RECV] [%s] Received (%u)", frame_type_to_string (frame->hd.type), frame->hd.flags); + h2_debug (io, NULL, "[RECV] [%s] Received (%u)", soup_http2_frame_type_to_string (frame->hd.type), frame->hd.flags); switch (frame->hd.type) { case NGHTTP2_GOAWAY: @@ -711,7 +612,7 @@ on_frame_recv_callback (nghttp2_session *session, } data = nghttp2_session_get_stream_user_data (session, frame->hd.stream_id); - h2_debug (io, data, "[RECV] [%s] Received (%u)", frame_type_to_string (frame->hd.type), frame->hd.flags); + h2_debug (io, data, "[RECV] [%s] Received (%u)", soup_http2_frame_type_to_string (frame->hd.type), frame->hd.flags); if (!data) { if (!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) && frame->hd.type != NGHTTP2_RST_STREAM) @@ -728,7 +629,7 @@ on_frame_recv_callback (nghttp2_session *session, data->metrics->response_header_bytes_received += frame->hd.length + FRAME_HEADER_SIZE; h2_debug (io, data, "[HEADERS] category=%s status=%u", - headers_category_to_string (frame->headers.cat), status); + soup_http2_headers_category_to_string (frame->headers.cat), status); switch (frame->headers.cat) { case NGHTTP2_HCAT_HEADERS: if (!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS)) { @@ -885,7 +786,7 @@ on_frame_send_callback (nghttp2_session *session, case NGHTTP2_HEADERS: g_assert (data); h2_debug (io, data, "[SEND] [HEADERS] category=%s finished=%d", - headers_category_to_string (frame->headers.cat), + soup_http2_headers_category_to_string (frame->headers.cat), (frame->hd.flags & NGHTTP2_FLAG_END_HEADERS) ? 1 : 0); if (data->metrics) @@ -930,7 +831,7 @@ on_frame_send_callback (nghttp2_session *session, break; case NGHTTP2_GOAWAY: - h2_debug (io, data, "[SEND] [%s]", frame_type_to_string (frame->hd.type)); + h2_debug (io, data, "[SEND] [%s]", soup_http2_frame_type_to_string (frame->hd.type)); io->goaway_sent = TRUE; if (io->close_task) { GSource *source; @@ -944,7 +845,7 @@ on_frame_send_callback (nghttp2_session *session, } break; default: - h2_debug (io, data, "[SEND] [%s]", frame_type_to_string (frame->hd.type)); + h2_debug (io, data, "[SEND] [%s]", soup_http2_frame_type_to_string (frame->hd.type)); break; } @@ -985,7 +886,7 @@ on_frame_not_send_callback (nghttp2_session *session, SoupClientMessageIOHTTP2 *io = user_data; SoupHTTP2MessageData *data = nghttp2_session_get_stream_user_data (session, frame->hd.stream_id); - h2_debug (io, data, "[SEND] [%s] Failed: %s", frame_type_to_string (frame->hd.type), + h2_debug (io, data, "[SEND] [%s] Failed: %s", soup_http2_frame_type_to_string (frame->hd.type), nghttp2_strerror (lib_error_code)); if (lib_error_code == NGHTTP2_ERR_SESSION_CLOSING) @@ -1327,24 +1228,6 @@ request_header_is_valid (const char *name) return !g_hash_table_contains (invalid_request_headers, name); } -#define MAKE_NV(NAME, VALUE, VALUELEN) \ - { \ - (uint8_t *)NAME, (uint8_t *)VALUE, strlen (NAME), VALUELEN, \ - NGHTTP2_NV_FLAG_NONE \ - } - -#define MAKE_NV2(NAME, VALUE) \ - { \ - (uint8_t *)NAME, (uint8_t *)VALUE, strlen (NAME), strlen (VALUE), \ - NGHTTP2_NV_FLAG_NONE \ - } - -#define MAKE_NV3(NAME, VALUE, FLAGS) \ - { \ - (uint8_t *)NAME, (uint8_t *)VALUE, strlen (NAME), strlen (VALUE), \ - FLAGS \ - } - static void send_message_request (SoupMessage *msg, SoupClientMessageIOHTTP2 *io, @@ -1871,33 +1754,10 @@ static const SoupClientMessageIOFuncs io_funcs = { soup_client_message_io_http2_owner_changed }; -G_GNUC_PRINTF(1, 0) -static void -debug_nghttp2 (const char *format, - va_list args) -{ - char *message; - gsize len; - - if (g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, "nghttp2")) - return; - - message = g_strdup_vprintf (format, args); - len = strlen (message); - if (len >= 1 && message[len - 1] == '\n') - message[len - 1] = '\0'; - g_log ("nghttp2", G_LOG_LEVEL_DEBUG, "[NGHTTP2] %s", message); - g_free (message); -} - static void soup_client_message_io_http2_init (SoupClientMessageIOHTTP2 *io) { - static gsize nghttp2_debug_init = 0; - if (g_once_init_enter (&nghttp2_debug_init)) { - nghttp2_set_debug_vprintf_callback(debug_nghttp2); - g_once_init_leave (&nghttp2_debug_init, 1); - } + soup_http2_debug_init (); nghttp2_session_callbacks *callbacks; NGCHECK (nghttp2_session_callbacks_new (&callbacks)); diff --git a/libsoup/meson.build b/libsoup/meson.build index a82a49fd..72fa86f0 100644 --- a/libsoup/meson.build +++ b/libsoup/meson.build @@ -70,6 +70,7 @@ soup_sources = [ 'soup-form.c', 'soup-headers.c', 'soup-header-names.c', + 'soup-http2-utils.c', 'soup-init.c', 'soup-io-stream.c', 'soup-logger.c', diff --git a/libsoup/server/http2/soup-server-message-io-http2.c b/libsoup/server/http2/soup-server-message-io-http2.c index c1682e04..a08d53f2 100644 --- a/libsoup/server/http2/soup-server-message-io-http2.c +++ b/libsoup/server/http2/soup-server-message-io-http2.c @@ -20,18 +20,7 @@ #include "soup-message-headers-private.h" #include "soup-server-message-private.h" #include "soup-misc.h" - -#include <nghttp2/nghttp2.h> - -typedef enum { - STATE_NONE, - STATE_READ_HEADERS, - STATE_READ_DATA, - STATE_READ_DONE, - STATE_WRITE_HEADERS, - STATE_WRITE_DATA, - STATE_WRITE_DONE, -} SoupHTTP2IOState; +#include "soup-http2-utils.h" typedef struct { SoupServerMessage *msg; @@ -79,30 +68,6 @@ typedef struct { static void soup_server_message_io_http2_send_response (SoupServerMessageIOHTTP2 *io, SoupMessageIOHTTP2 *msg_io); -static const char * -state_to_string (SoupHTTP2IOState state) -{ - switch (state) { - case STATE_NONE: - return "NONE"; - case STATE_READ_HEADERS: - return "READ_HEADERS"; - case STATE_READ_DATA: - return "READ_DATA"; - case STATE_READ_DONE: - return "READ_DONE"; - case STATE_WRITE_HEADERS: - return "WRITE_HEADERS"; - case STATE_WRITE_DATA: - return "WRITE_DATA"; - case STATE_WRITE_DONE: - return "WRITE_DONE"; - default: - g_assert_not_reached (); - return ""; - } -} - static void advance_state_from (SoupMessageIOHTTP2 *msg_io, SoupHTTP2IOState from, @@ -110,16 +75,8 @@ advance_state_from (SoupMessageIOHTTP2 *msg_io, { if (msg_io->state != from) { g_warning ("Unexpected state changed %s -> %s, expected to be from %s", - state_to_string (msg_io->state), state_to_string (to), - state_to_string (from)); - } - - /* State never goes backwards */ - if (to < msg_io->state) { - g_warning ("Unexpected state changed %s -> %s, expected %s -> %s\n", - state_to_string (msg_io->state), state_to_string (to), - state_to_string (from), state_to_string (to)); - return; + soup_http2_io_state_to_string (msg_io->state), soup_http2_io_state_to_string (to), + soup_http2_io_state_to_string (from)); } msg_io->state = to; @@ -183,7 +140,7 @@ soup_server_message_io_http2_finished (SoupServerMessageIO *iface, SoupMessageIOCompletion completion; g_hash_table_steal_extended (io->messages, msg, NULL, (gpointer *)&msg_io); - completion = msg_io->state < STATE_WRITE_DONE ? SOUP_MESSAGE_IO_INTERRUPTED : SOUP_MESSAGE_IO_COMPLETE; + completion = msg_io->state != STATE_WRITE_DONE ? SOUP_MESSAGE_IO_INTERRUPTED : SOUP_MESSAGE_IO_COMPLETE; completion_cb = msg_io->completion_cb; completion_data = msg_io->completion_data; @@ -588,24 +545,6 @@ on_data_source_read_callback (nghttp2_session *session, return bytes_written; } -#define MAKE_NV(NAME, VALUE, VALUELEN) \ - { \ - (uint8_t *)NAME, (uint8_t *)VALUE, strlen (NAME), VALUELEN, \ - NGHTTP2_NV_FLAG_NONE \ - } - -#define MAKE_NV2(NAME, VALUE) \ - { \ - (uint8_t *)NAME, (uint8_t *)VALUE, strlen (NAME), strlen (VALUE), \ - NGHTTP2_NV_FLAG_NONE \ - } - -#define MAKE_NV3(NAME, VALUE, FLAGS) \ - { \ - (uint8_t *)NAME, (uint8_t *)VALUE, strlen (NAME), strlen (VALUE), \ - FLAGS \ - } - static void soup_server_message_io_http2_send_response (SoupServerMessageIOHTTP2 *io, SoupMessageIOHTTP2 *msg_io) @@ -747,6 +686,8 @@ soup_server_message_io_http2_init (SoupServerMessageIOHTTP2 *io) { nghttp2_session_callbacks *callbacks; + soup_http2_debug_init (); + nghttp2_session_callbacks_new (&callbacks); nghttp2_session_callbacks_set_on_begin_headers_callback (callbacks, on_begin_headers_callback); nghttp2_session_callbacks_set_on_header_callback (callbacks, on_header_callback); diff --git a/libsoup/soup-http2-utils.c b/libsoup/soup-http2-utils.c new file mode 100644 index 00000000..3bacf2c3 --- /dev/null +++ b/libsoup/soup-http2-utils.c @@ -0,0 +1,114 @@ +/* + * Copyright 2022 Igalia, S.L. + */ + +#include "soup-http2-utils.h" +#include <glib.h> + +const char * +soup_http2_io_state_to_string (SoupHTTP2IOState state) +{ + switch (state) { + case STATE_NONE: + return "NONE"; + case STATE_WRITE_HEADERS: + return "WRITE_HEADERS"; + case STATE_WRITE_DATA: + return "WRITE_DATA"; + case STATE_WRITE_DONE: + return "WRITE_DONE"; + case STATE_READ_HEADERS: + return "READ_HEADERS"; + case STATE_READ_DATA_START: + return "READ_DATA_START"; + case STATE_READ_DATA: + return "READ_DATA"; + case STATE_READ_DONE: + return "READ_DONE"; + } + g_assert_not_reached (); + return ""; +} + +const char * +soup_http2_frame_type_to_string (nghttp2_frame_type type) +{ + switch (type) { + case NGHTTP2_DATA: + return "DATA"; + case NGHTTP2_HEADERS: + return "HEADERS"; + case NGHTTP2_PRIORITY: + return "PRIORITY"; + case NGHTTP2_RST_STREAM: + return "RST_STREAM"; + case NGHTTP2_SETTINGS: + return "SETTINGS"; + case NGHTTP2_PING: + return "PING"; + case NGHTTP2_GOAWAY: + return "GOAWAY"; + case NGHTTP2_WINDOW_UPDATE: + return "WINDOW_UPDATE"; + /* LCOV_EXCL_START */ + case NGHTTP2_PUSH_PROMISE: + return "PUSH_PROMISE"; + case NGHTTP2_CONTINUATION: + return "CONTINUATION"; + case NGHTTP2_ALTSVC: + return "ALTSVC"; + case NGHTTP2_ORIGIN: + return "ORIGIN"; + default: + g_warn_if_reached (); + return "UNKNOWN"; + /* LCOV_EXCL_STOP */ + } +} + +const char * +soup_http2_headers_category_to_string (nghttp2_headers_category catergory) +{ + switch (catergory) { + case NGHTTP2_HCAT_REQUEST: + return "REQUEST"; + case NGHTTP2_HCAT_RESPONSE: + return "RESPONSE"; + case NGHTTP2_HCAT_PUSH_RESPONSE: + return "PUSH_RESPONSE"; + case NGHTTP2_HCAT_HEADERS: + return "HEADERS"; + } + g_assert_not_reached (); + return ""; +} + +G_GNUC_PRINTF(1, 0) +static void +debug_nghttp2 (const char *format, + va_list args) +{ + char *message; + gsize len; + + if (g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, "nghttp2")) + return; + + message = g_strdup_vprintf (format, args); + len = strlen (message); + if (len >= 1 && message[len - 1] == '\n') + message[len - 1] = '\0'; + g_log ("nghttp2", G_LOG_LEVEL_DEBUG, "[NGHTTP2] %s", message); + g_free (message); +} + +void +soup_http2_debug_init (void) +{ + static gsize nghttp2_debug_init = 0; + if (g_once_init_enter (&nghttp2_debug_init)) { + nghttp2_set_debug_vprintf_callback(debug_nghttp2); + g_once_init_leave (&nghttp2_debug_init, 1); + } + +} diff --git a/libsoup/soup-http2-utils.h b/libsoup/soup-http2-utils.h new file mode 100644 index 00000000..f3a7c735 --- /dev/null +++ b/libsoup/soup-http2-utils.h @@ -0,0 +1,49 @@ +/* + * Copyright 2022 Igalia, S.L. + */ + +#pragma once + +#include <nghttp2/nghttp2.h> + +#define NGCHECK(stm) \ + G_STMT_START { \ + int return_code = stm; \ + if (return_code == NGHTTP2_ERR_NOMEM) \ + g_abort (); \ + else if (return_code < 0) \ + g_debug ("Unhandled NGHTTP2 Error: %s", nghttp2_strerror (return_code)); \ + } G_STMT_END + +#define MAKE_NV(NAME, VALUE, VALUELEN) \ + { \ + (uint8_t *)NAME, (uint8_t *)VALUE, strlen (NAME), VALUELEN, NGHTTP2_NV_FLAG_NONE \ + } + +#define MAKE_NV2(NAME, VALUE) \ + { \ + (uint8_t *)NAME, (uint8_t *)VALUE, strlen (NAME), strlen (VALUE), NGHTTP2_NV_FLAG_NONE \ + } + +#define MAKE_NV3(NAME, VALUE, FLAGS) \ + { \ + (uint8_t *)NAME, (uint8_t *)VALUE, strlen (NAME), strlen (VALUE), FLAGS \ + } + + +typedef enum { + STATE_NONE, + STATE_WRITE_HEADERS, + STATE_WRITE_DATA, + STATE_WRITE_DONE, + STATE_READ_HEADERS, + STATE_READ_DATA_START, + STATE_READ_DATA, + STATE_READ_DONE, +} SoupHTTP2IOState; + +const char *soup_http2_io_state_to_string (SoupHTTP2IOState state); +const char *soup_http2_frame_type_to_string (nghttp2_frame_type type); +const char *soup_http2_headers_category_to_string (nghttp2_headers_category catergory); + +void soup_http2_debug_init (void); |