0
Fork 0
mirror of https://github.com/ninenines/cowboy.git synced 2025-07-14 12:20:24 +00:00

WIP fixes for Chromium

This commit is contained in:
Loïc Hoguin 2025-05-13 14:20:11 +02:00
parent ee534f4e2b
commit 46c53cd4fb
No known key found for this signature in database
GPG key ID: 8A9DF795F6FED764
6 changed files with 94 additions and 7 deletions

View file

@ -95,8 +95,12 @@ start_quic(Ref, TransOpts, ProtoOpts) ->
end,
SocketOpts = [
{alpn, ["h3"]}, %% @todo Why not binary?
{peer_unidi_stream_count, 3}, %% We only need control and QPACK enc/dec.
{peer_bidi_stream_count, 100}
{peer_unidi_stream_count, 100}, %% We only need control and QPACK enc/dec.
{peer_bidi_stream_count, 100},
%% For WebTransport. @todo Also increase default unidi stream count.
%% @todo We probably don't want it enabled if WT isn't used.
{datagram_send_enabled, 1},
{datagram_receive_enabled, 1}
|SocketOpts2],
_ListenerPid = spawn(fun() ->
{ok, Listener} = quicer:listen(Port, SocketOpts),

View file

@ -716,9 +716,10 @@ commands(State, Stream, [Error = {internal_error, _, _}|_Tail]) ->
reset_stream(State, Stream, Error);
%% Use a different protocol within the stream (CONNECT :protocol).
%% @todo Make sure we error out when the feature is disabled.
commands(State0=#state{http3_machine=HTTP3Machine0}, Stream0=#stream{id=StreamID},
commands(State0, Stream0=#stream{id=StreamID},
[{switch_protocol, Headers, cowboy_webtransport, WTState=#{}}|Tail]) ->
State = info(stream_store(State0, Stream0), StreamID, {headers, 200, Headers}),
#state{http3_machine=HTTP3Machine0} = State,
Stream1 = #stream{state=StreamState} = stream_get(State, StreamID),
%% The stream becomes a WT session at that point. It is the
%% parent stream of all streams in this WT session. The
@ -864,7 +865,7 @@ webtransport_event(State, SessionID, Event) ->
ok.
webtransport_commands(State, SessionID, Commands) ->
Session = #stream{status=webtransport_session} = stream_get(SessionID, State),
Session = #stream{status=webtransport_session} = stream_get(State, SessionID),
wt_commands(State, Session, Commands).
wt_commands(State, _, []) ->

View file

@ -34,6 +34,7 @@
-export_type([opts/0]).
-record(state, {
id :: cow_http3:stream_id(),
parent :: pid(),
opts = #{} :: opts(),
handler :: module(),
@ -72,7 +73,7 @@ upgrade(Req=#{version := 'HTTP/3', pid := Pid, streamid := StreamID}, Env, Handl
FilterFun -> FilterFun(Req)
end,
%% @todo add parent, ref, streamid here directly
State = #state{parent=Pid, opts=Opts, handler=Handler, req=FilteredReq},
State = #state{id=StreamID, parent=Pid, opts=Opts, handler=Handler, req=FilteredReq},
%% @todo Must check is_upgrade_request (rename, not an upgrade)
%% and also ensure that all the relevant settings are enabled (quic and h3)
@ -179,8 +180,8 @@ handler_call_result(State0, HandlerState, Commands) ->
commands([], State, []) ->
{ok, State};
commands([], State=#state{parent=Pid}, Commands) ->
Pid ! {'$webtransport_commands', lists:reverse(Commands)},
commands([], State=#state{id=SessionID, parent=Pid}, Commands) ->
Pid ! {'$webtransport_commands', SessionID, lists:reverse(Commands)},
{ok, State};
%% {open_stream, OpenStreamRef, StreamType, InitialData}.
commands([Command={open_stream, _, _, _}|Tail], State, Acc) ->

View file

@ -53,6 +53,7 @@ init_http3(Ref, ProtoOpts, Config) ->
},
{ok, Listener} = cowboy:start_quic(Ref, TransOpts, ProtoOpts),
{ok, {_, Port}} = quicer:sockname(Listener),
ct:pal("port ~p", [Port]),
%% @todo Keep listener information around in a better place.
persistent_term:put({cowboy_test_quic, Ref}, Listener),
[{ref, Ref}, {type, quic}, {protocol, http3}, {port, Port}, {opts, TransOpts}|Config].

View file

@ -0,0 +1,59 @@
%% Copyright (c) Loïc Hoguin <essen@ninenines.eu>
%%
%% Permission to use, copy, modify, and/or distribute this software for any
%% purpose with or without fee is hereby granted, provided that the above
%% copyright notice and this permission notice appear in all copies.
%%
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-module(draft_h3_webtransport_SUITE).
-compile(export_all).
-compile(nowarn_export_all).
-import(ct_helper, [config/2]).
-import(ct_helper, [doc/1]).
all() ->
[{group, enabled}].
groups() ->
Tests = ct_helper:all(?MODULE),
[{enabled, [], Tests}]. %% @todo Enable parallel when all is better.
init_per_group(Name = enabled, Config) ->
cowboy_test:init_http3(Name, #{
enable_connect_protocol => true,
h3_datagram => true,
enable_webtransport => true, %% For compatibility with draft-02.
webtransport_max_sessions => 10,
env => #{dispatch => cowboy_router:compile(init_routes(Config))}
}, Config).
end_per_group(Name, _) ->
cowboy_test:stop_group(Name).
init_routes(_) -> [
{"localhost", [
{"/wt", wt_echo_h, []}
]}
].
%% Temporary.
%% To start Chromium the command line is roughly:
%% chromium --ignore-certificate-errors-spki-list=LeLykt63i2FRAm+XO91yBoSjKfrXnAFygqe5xt0zgDA= --ignore-certificate-errors --user-data-dir=/tmp/chromium-wt --allow-insecure-localhost --webtransport-developer-mode --enable-quic https://googlechrome.github.io/samples/webtransport/client.html
%%
%% To find the SPKI the command is roughly:
%% openssl x509 -in ~/ninenines/cowboy/test/rfc9114_SUITE_data/server.pem -pubkey -noout | \
%% openssl pkey -pubin -outform der | \
%% openssl dgst -sha256 -binary | \
%% openssl enc -base64
run(_Config) ->
timer:sleep(infinity).

View file

@ -0,0 +1,21 @@
%% This module echoes client events back,
%% including creating new streams.
-module(wt_echo_h).
%% @todo -behavior(cowboy_webtransport).
-export([init/2]).
-export([webtransport_handle/2]).
init(Req, _) ->
{cowboy_webtransport, Req, undefined}.
%% @todo WT handle {stream_open,4,bidi}
%% @todo WT handle {stream_data,4,nofin,<<>>} %% skip?
webtransport_handle(Event = {stream_data, StreamID, IsFin, Data}, HandlerState) ->
ct:pal("WT handle ~p~n", [Event]),
{[{send, StreamID, Data}], HandlerState};
webtransport_handle(Event, HandlerState) ->
ct:pal("WT handle ~p~n", [Event]),
{[], HandlerState}.