Repository navigation
Expand file tree
/
Copy pathlifecycle_sink.hpp
More file actions
150 lines (119 loc) · 5.99 KB
/
Copy pathlifecycle_sink.hpp
File metadata and controls
150 lines (119 loc) · 5.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
This file is part of libhttpserver
Copyright (C) 2011-2026 Sebastiano Merlino
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the file
LICENSE in the distribution; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
// TASK-118 (plan D5): the interceptor exchange_sink that gives
// after_handler and response_sent their uniform pre-commit firing
// point. v3 handlers commit inside their own task, so the one point
// every commit crosses -- value-shaped, streaming, synthesized, or
// hook-supplied -- is the engine-sink boundary: this wrapper fires the
// mutating after_handler phase BEFORE forwarding the head (for value
// routes this coincides with v2's post-handler point; for streaming
// commits it fires at head-commit time, mid-handler -- the documented
// timing delta), then fires response_sent AFTER the engine accepted
// the head -- a head the engine REFUSED (the framer rejected a field,
// say) never fires response_sent and is recorded as refused so the
// request_completed tail reports the failure verdict. The status/
// fields copies after_handler mutates exist only when the phase can
// run (zero-cost-when-unused). after_handler does not fire on the
// pre-handler short-circuits (the pinned v2 suppression). NOT part of
// the installed surface.
#if !defined(HTTPSERVER_COMPILATION)
#error "httpserver/detail/lifecycle_sink.hpp is internal; only include it when compiling libhttpserver (HTTPSERVER_COMPILATION must be defined)."
#endif
#ifndef SRC_HTTPSERVER_DETAIL_LIFECYCLE_SINK_HPP_
#define SRC_HTTPSERVER_DETAIL_LIFECYCLE_SINK_HPP_
#include <cstdint>
#include <memory>
#include <utility>
#include <httpserver/exchange.hpp>
#include <httpserver/server/hooks.hpp>
namespace httpserver {
namespace detail {
class lifecycle_sink final : public exchange_sink {
public:
// The provenance of the next committed head; decides whether
// after_handler fires.
enum class provenance : std::uint8_t {
handler, // the route handler's own commit
synthesis, // a dispatcher-synthesized head (404/405/500/501)
exception_supply, // a handler_exception hook's response
pre_handler, // request_received/before_handler short-circuit
};
// @p head must outlive this sink (the engine frame owns it first).
// @p engine_refusal, when not null, observes the owning engine
// sink's acceptance verdict: the engine sets it when it refuses
// the committed head (e.g. the framer rejects a field), and this
// sink then records the refusal (see forward). Null (test rigs
// whose stand-in sink never refuses) counts as always-accepted.
lifecycle_sink(exchange_sink& inner, const server::hook_bus& bus,
const http::request_head& head,
const bool* engine_refusal = nullptr,
std::shared_ptr<const server::tls_peer_metadata> tls = {}) noexcept;
// Tags the next commit's provenance; the dispatcher sets it before
// every commit path.
void begin(provenance next) noexcept { next_ = next; }
// True once a head was accepted by the engine sink (a refused
// head never marks it).
bool responded() const noexcept { return responded_; }
// True once the engine sink refused a committed head.
bool refused() const noexcept { return refused_; }
std::uint16_t committed_status() const noexcept { return status_; }
// True after a post-commit abort was forwarded.
bool aborted() const noexcept { return aborted_; }
bool begin_completion() noexcept;
void on_admit(const body_policy& policy) override {
inner_.on_admit(policy);
}
void on_respond(const http::status& s, const http::fields& f) override {
commit(s, f, false);
}
void on_start_response(const http::status& s, const http::fields& f) override {
commit(s, f, true);
}
websocket_upgrade_result on_upgrade(const ws_upgrade_options& options) override;
void on_abort() override;
private:
void commit(const http::status& s, const http::fields& f, bool streaming);
// The commit tail shared by both branches: forwards the head and,
// only when the engine accepted it (a refused head -- the framer
// rejected a field, say -- set the engine's refusal flag), records
// the response and fires response_sent ("after the engine
// accepted the committed head"). A refusal suppresses
// response_sent and is recorded so the request_completed tail can
// report the failure verdict.
void forward(const http::status& s, const http::fields& f, bool streaming);
// The mutating phase over copies of the about-to-be-committed
// head; the mutated values are what get forwarded. Called only
// from on_respond's gated branch (the copies exist exactly when
// the hooks do).
void fire_after(http::status& s, http::fields& f) const;
void fire_sent() const;
exchange_sink& inner_;
const server::hook_bus& bus_;
const http::request_head& head_;
const bool* engine_refusal_ = nullptr;
std::shared_ptr<const server::tls_peer_metadata> tls_;
provenance next_ = provenance::handler;
bool responded_ = false;
bool refused_ = false;
bool aborted_ = false;
bool completed_ = false;
std::uint16_t status_ = 0;
};
} // namespace detail
} // namespace httpserver
#endif // SRC_HTTPSERVER_DETAIL_LIFECYCLE_SINK_HPP_