Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
bb868d0
remove non-awaitable request handler
pgit Aug 20, 2026
cfe0e77
remove redundant request handler invocation in NGHttp2Stream and Http…
pgit Aug 20, 2026
fe142ca
HTTP/3: resume a stream blocked mid-write
pgit Aug 20, 2026
04ddcde
add a request handler serving files with mmap()
pgit Aug 20, 2026
100773c
HTTP/3: send a Date header with the response
pgit Aug 20, 2026
2bfc883
ignore out-of-tree build directories
pgit Aug 20, 2026
e4cc39f
HTTP/3: pass the response body to nghttp3 by reference
pgit Aug 20, 2026
bf34a2c
QUIC: prefer AES-128-GCM over AES-256-GCM
pgit Aug 20, 2026
cb7f1f8
QUIC: only install ngtcp2's log callback when tracing
pgit Aug 20, 2026
ded78ee
serve_file: keep file mappings across requests
pgit Aug 20, 2026
62021e9
HTTP/3: write once per receive batch, not once per datagram
pgit Aug 20, 2026
b0a4b68
HTTP/3: arm the write flush once per wake, not once per submission
pgit Aug 21, 2026
c4b4595
HTTP/3: fill a read from every queued chunk, not just the first
pgit Aug 21, 2026
ac2d8fe
HTTP/3: hand an arriving chunk to a waiting reader without parking it…
pgit Aug 21, 2026
ae91d0c
log: change log level from info to debug in eat_request function
pgit Aug 21, 2026
3002243
HTTP/3: let a re-issued EOF adopt a pending FIN without tripping the …
pgit Aug 21, 2026
ed04180
log: log submitted headers, and h3 received headers as one block
pgit Aug 21, 2026
bca74b5
log: add segment counter to udp_on_read for better debugging
pgit Aug 21, 2026
89701fd
HTTP/3: drop the session when the QUIC idle timer fires
pgit Aug 21, 2026
3c71335
HTTP/3: add random UDP packet dropping for testing
pgit Aug 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ docs/_build
gtest-parallel-logs
report.xml
build
build-*
secrets
Testing
*.pcap
Expand Down
23 changes: 23 additions & 0 deletions include/anyhttp/file_handler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include "anyhttp/server.hpp"

#include <filesystem>
#include <string>

namespace anyhttp
{

// =================================================================================================

/**
* Serve a single file from below \p root, mapped into memory with mmap(). The part of the request
* path below \p prefix is taken as the path relative to \p root; anything that would escape
* \p root ("..", a symlink pointing outside) is rejected with 404.
*/
awaitable<void> serve_file(server::Request request, server::Response response,
std::filesystem::path root, std::string prefix);

// =================================================================================================

} // namespace anyhttp
22 changes: 19 additions & 3 deletions include/anyhttp/server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,24 @@ struct Config
std::string listen_address = "::";
uint16_t port = 8080;
bool use_strand = false;

//
// HTTP/3 only: how long a QUIC connection may go without a packet from its peer before it is
// dropped. This is the only way a peer that vanished without a CONNECTION_CLOSE -- a killed
// client, a machine that went to sleep -- is ever noticed, so it also bounds how long its
// session and streams stay around. 30s is what the ngtcp2 examples use.
//
std::chrono::nanoseconds idle_timeout = 30s;

//
// HTTP/3 only, testing aid: probability (0.0 ... 1.0) with which an individual QUIC datagram
// is thrown away instead of being processed (rx) or actually sent (tx). This exercises loss
// recovery -- retransmits, PTO, ACK handling -- without needing a lossy network. Dropping
// happens per QUIC packet, i.e. GRO-coalesced datagrams are dropped individually and TX
// GSO batching is bypassed while `drop_rate_tx` is non-zero.
//
double drop_rate_rx = 0.0;
double drop_rate_tx = 0.0;
};

// =================================================================================================
Expand Down Expand Up @@ -135,8 +153,7 @@ class Response

// =================================================================================================

using RequestHandler = std::function<void(Request, Response)>;
using RequestHandlerCoro = std::function<asio::awaitable<void>(Request, Response)>;
using RequestHandler = std::function<asio::awaitable<void>(Request, Response)>;

class Server
{
Expand All @@ -151,7 +168,6 @@ class Server
executor_type get_executor() const noexcept;

void setRequestHandler(RequestHandler&& handler);
void setRequestHandlerCoro(RequestHandlerCoro&& handler);

asio::ip::tcp::endpoint local_endpoint() const;

Expand Down
6 changes: 0 additions & 6 deletions include/anyhttp/server_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,7 @@ class Server::Impl : public std::enable_shared_from_this<Server::Impl>
}

void setRequestHandler(RequestHandler&& handler) { m_requestHandler = std::move(handler); }
void setRequestHandler(RequestHandlerCoro&& handler)
{
m_requestHandlerCoro = std::move(handler);
}
const RequestHandler& requestHandler() const { return m_requestHandler; }
const RequestHandlerCoro& requestHandlerCoro() const { return m_requestHandlerCoro; }

asio::awaitable<void> udp_receive_loop();
int udp_on_read(Endpoint& ep);
Expand All @@ -110,7 +105,6 @@ class Server::Impl : public std::enable_shared_from_this<Server::Impl>
std::unordered_map<std::string, std::shared_ptr<Http3Session>> m_quic_handlers;

RequestHandler m_requestHandler;
RequestHandlerCoro m_requestHandlerCoro;
bool m_stopped = false;
};

Expand Down
7 changes: 6 additions & 1 deletion src/beast_session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ class ResponseWriter
WriterBase<server::Response::Impl, Stream, http::response_serializer<http::buffer_body>>;

public:
using super::logPrefix;
using super::message;
using super::serializer;
using super::stream;
Expand Down Expand Up @@ -426,6 +427,10 @@ class ResponseWriter
if (message.find(http::field::server) == message.end())
message.set(http::field::server, "anyhttp");

mlogd("{} {}", message.result_int(), message.reason());
for (const auto& header : message)
mlogd(" \x1b[1;34m{}\x1b[0m: {}", header.name_string(), header.value());

//
// TODO: For bundling writing the header and body, we should just post the writing here,
// giving an async_write the chance to add a body to the message first.
Expand Down Expand Up @@ -716,7 +721,7 @@ awaitable<void> ServerSession<Stream>::do_session(Buffer&& buffer)
//
server::Request request_wrapper(std::move(reader));
server::Response response_wrapper(std::move(writer));
if (auto& handler = server().requestHandlerCoro())
if (auto& handler = server().requestHandler())
{
try
{
Expand Down
Loading
Loading