From 4cbdfdd293c687212f9ce64e608de838ec74a592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Sun, 5 Feb 2017 13:45:35 +0100 Subject: Fix sending of large files with HTTP/2 Also finish implementing the relevant test, getting rid of todos. --- src/cowboy_http2.erl | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cowboy_http2.erl b/src/cowboy_http2.erl index ead3ff5..e816c93 100644 --- a/src/cowboy_http2.erl +++ b/src/cowboy_http2.erl @@ -441,8 +441,13 @@ commands(State=#state{socket=Socket, transport=Transport}, Stream=#stream{id=Str %% implementation necessarily varies between HTTP/1.1 and HTTP/2. commands(State=#state{socket=Socket, transport=Transport}, Stream=#stream{id=StreamID, local=nofin}, [{sendfile, IsFin, Offset, Bytes, Path}|Tail]) -> - Transport:send(Socket, cow_http2:data_header(StreamID, IsFin, Bytes)), - Transport:sendfile(Socket, Path, Offset, Bytes), + %% @todo We currently have a naive implementation without a + %% scheduler to prioritize frames that need to be sent. + %% A future update will need to queue such data frames + %% and only send them when there is nothing currently + %% being sent. We would probably also benefit from doing + %% asynchronous sends. + sendfile(Socket, Transport, StreamID, IsFin, Offset, Bytes, Path, 16384), commands(State, Stream#stream{local=IsFin}, Tail); %% @todo sendfile when local!=nofin %% Send a push promise. @@ -513,6 +518,19 @@ send_data(Socket, Transport, StreamID, IsFin, Data, Length) -> Transport:send(Socket, cow_http2:data(StreamID, IsFin, Data)) end. +%% @todo This is currently awfully slow. But at least it's correct. +sendfile(Socket, Transport, StreamID, IsFin, Offset, Bytes, Path, Length) -> + if + Length < Bytes -> + Transport:send(Socket, cow_http2:data_header(StreamID, nofin, Length)), + Transport:sendfile(Socket, Path, Offset, Length), + sendfile(Socket, Transport, StreamID, IsFin, + Offset + Length, Bytes - Length, Path, Length); + true -> + Transport:send(Socket, cow_http2:data_header(StreamID, IsFin, Bytes)), + Transport:sendfile(Socket, Path, Offset, Bytes) + end. + -spec terminate(#state{}, _) -> no_return(). terminate(#state{socket=Socket, transport=Transport, streams=Streams, children=Children}, Reason) -> -- cgit v1.2.3