-
-
Notifications
You must be signed in to change notification settings - Fork 191
Expand file tree
/
Copy pathhook_handle.cpp
More file actions
162 lines (142 loc) · 5.58 KB
/
Copy pathhook_handle.cpp
File metadata and controls
162 lines (142 loc) · 5.58 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
151
152
153
154
155
156
157
158
159
160
161
162
/*
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 Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
*/
// Out-of-line bodies for hook_handle and peer_address.
//
// hook_handle's destructor + remove() + move ops need the complete
// type of detail::webserver_impl (the per-phase vectors live there),
// so the bodies live here, not in the public header. Same pattern as
// http_response's move/dtor.
#include "httpserver/hook_handle.hpp"
#include <exception>
#include <memory>
#include <mutex>
#include <optional>
#include <shared_mutex>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "httpserver/hook_action.hpp"
#include "httpserver/http_response.hpp"
#include "httpserver/hook_context.hpp"
#include "httpserver/detail/resource_hook_table.hpp"
#include "httpserver/detail/webserver_impl.hpp"
namespace httpserver {
// ---- hook_handle ---------------------------------------------------------
hook_handle::hook_handle(hook_handle&& other) noexcept
: impl_(other.impl_),
slot_id_(other.slot_id_),
phase_(other.phase_),
armed_(other.armed_),
table_weak_(std::move(other.table_weak_)) {
// Disarm the source so its destructor is a no-op.
other.armed_ = false;
other.impl_ = nullptr;
other.table_weak_.reset();
}
hook_handle& hook_handle::operator=(hook_handle&& other) noexcept {
if (this != &other) {
// Remove any registration this object currently owns before
// taking over the source's. remove() is idempotent and
// noexcept, so this is safe even if `armed_` is already false.
remove();
impl_ = other.impl_;
slot_id_ = other.slot_id_;
phase_ = other.phase_;
armed_ = other.armed_;
table_weak_ = std::move(other.table_weak_);
other.armed_ = false;
other.impl_ = nullptr;
other.table_weak_.reset();
}
return *this;
}
hook_handle::~hook_handle() {
if (armed_) {
remove();
}
}
// Drain a per-route registration. Called by hook_handle::remove
// when impl_ == nullptr (handles produced by http_resource::add_hook).
// Disarm BEFORE the table call mirrors the server-wide discipline in
// hook_handle::remove. If the resource owning the table has been
// destroyed, the weak_ptr is expired and this is a no-op (the
// contract: "if the resource is destroyed before the handle, remove()
// is a no-op").
static void remove_per_route(std::weak_ptr<detail::resource_hook_table>& weak,
hook_phase phase,
std::uint64_t slot_id) noexcept {
auto table = weak.lock();
weak.reset();
if (table) {
table->remove_slot(phase, slot_id);
}
}
void hook_handle::remove() noexcept {
if (!armed_) {
return;
}
// Handles produced by http_resource::add_hook have
// impl_ == nullptr and carry a (possibly-expired) weak_ptr to
// the resource's hook table. Handles produced by webserver::add_hook
// have a non-null impl_ and a default-constructed (empty) weak_ptr.
if (impl_ == nullptr) {
const auto phase = phase_;
const auto id = slot_id_;
armed_ = false;
remove_per_route(table_weak_, phase, id);
return;
}
// Snapshot the source state and disarm BEFORE delegating the erase,
// so any exception (very unlikely, but remove() is declared noexcept
// and std::terminate is the observable outcome anyway) does not leave
// the handle in a half-removed state. hook_bus::remove is the single
// owner of the erase-and-gate-clear logic (scan the phase vector,
// erase, clear the any_hooks_ gate if the vector empties -- but not
// out from under a still-wired alias slot).
auto* impl = impl_;
const auto phase = phase_;
const auto id = slot_id_;
armed_ = false;
impl_ = nullptr;
impl->hooks_.remove(phase, id);
}
hook_handle hook_handle::detach() && noexcept {
// Construct a disarmed handle from the same data; do NOT call the
// private armed-ctor because the spec says detach() leaves the
// underlying registration in place (no impl interaction).
hook_handle out;
out.impl_ = impl_;
out.slot_id_ = slot_id_;
out.phase_ = phase_;
// detached: registration persists in the phase vector; destructor
// is disabled. This disarmed state is semantically distinct from a
// default-constructed (never-registered) handle: both have armed_==false,
// but here the backing slot is intentionally left alive.
out.armed_ = false;
out.table_weak_ = table_weak_;
// Disarm the source so its destructor is also a no-op.
armed_ = false;
impl_ = nullptr;
table_weak_.reset();
return out;
}
// ---- peer_address::to_string ---------------------------------------------
//
// Defined in src/peer_address.cpp. See the rationale comment at the
// top of that file.
} // namespace httpserver