]>
Commit | Line | Data |
---|---|---|
1c2b4465 | 1 | /* |
b8ae064d | 2 | * Copyright (C) 1996-2023 The Squid Software Foundation and contributors |
1c2b4465 CT |
3 | * |
4 | * Squid software is distributed under GPLv2+ license and includes | |
5 | * contributions from numerous individuals and organizations. | |
6 | * Please see the COPYING and CONTRIBUTORS files for details. | |
7 | */ | |
8 | ||
ff9d9458 FC |
9 | #ifndef SQUID_SRC_HTTPUPGRADEPROTOCOLACCESS_H |
10 | #define SQUID_SRC_HTTPUPGRADEPROTOCOLACCESS_H | |
1c2b4465 CT |
11 | |
12 | #include "acl/forward.h" | |
13 | #include "sbuf/SBuf.h" | |
14 | ||
a7b75c64 | 15 | #include <deque> |
1c2b4465 CT |
16 | #include <map> |
17 | ||
18 | /// a reference to a protocol name[/version] string; no 0-termination is assumed | |
19 | class ProtocolView | |
20 | { | |
21 | public: | |
22 | ProtocolView(const char * const start, const size_t len); | |
23 | explicit ProtocolView(const SBuf &proto); | |
24 | ||
25 | SBuf name; ///< everything up to (but excluding) the first slash('/') | |
26 | SBuf version; ///< everything after the name, including the slash('/') | |
27 | }; | |
28 | ||
29 | std::ostream &operator <<(std::ostream &, const ProtocolView &); | |
30 | ||
31 | // HTTP is not explicit about case sensitivity of Upgrade protocol strings, but | |
32 | // there are bug reports showing different case variants used for WebSocket. We | |
33 | // conservatively preserve the received case and compare case-sensitively. | |
34 | ||
35 | /// Either b has no version restrictions or both have the same version. | |
36 | /// For example, "ws/1" is in "ws" but "ws" is not in "ws/1". | |
37 | inline bool | |
38 | vAinB(const ProtocolView &a, const ProtocolView &b) | |
39 | { | |
40 | // Optimization: Do not assert(a.name == b.name). | |
41 | return b.version.isEmpty() || (a.version == b.version); | |
42 | } | |
43 | ||
a7b75c64 FC |
44 | class ConfigParser; |
45 | ||
1c2b4465 CT |
46 | /// Allows or blocks HTTP Upgrade protocols (see http_upgrade_request_protocols) |
47 | class HttpUpgradeProtocolAccess | |
48 | { | |
49 | public: | |
50 | HttpUpgradeProtocolAccess() = default; | |
51 | ~HttpUpgradeProtocolAccess(); | |
52 | HttpUpgradeProtocolAccess(HttpUpgradeProtocolAccess &&) = delete; // no copying of any kind | |
53 | ||
54 | /// \returns the ACLs matching the given "name[/version]" protocol (or nil) | |
55 | const acl_access *findGuard(const SBuf &proto) const; | |
56 | ||
57 | /// parses a single allow/deny rule | |
58 | void configureGuard(ConfigParser&); | |
59 | ||
60 | /// iterates over all configured rules, calling the given visitor | |
61 | template <typename Visitor> inline void forEach(const Visitor &) const; | |
62 | ||
63 | /// iterates over rules applicable to the given protocol, calling visitor; | |
64 | /// breaks iteration if the visitor returns true | |
65 | template <typename Visitor> inline void forApplicable(const ProtocolView &, const Visitor &) const; | |
66 | ||
67 | private: | |
68 | /// a single configured access rule for an explicitly named protocol | |
69 | class NamedGuard | |
70 | { | |
71 | public: | |
72 | NamedGuard(const char *rawProtocol, acl_access*); | |
73 | NamedGuard(const NamedGuard &&) = delete; // no copying of any kind | |
74 | ~NamedGuard(); | |
75 | ||
76 | const SBuf protocol; ///< configured protocol name (and version) | |
77 | const ProtocolView proto; ///< optimization: compiled this->protocol | |
78 | acl_access *guard = nullptr; ///< configured access rule; never nil | |
79 | }; | |
80 | ||
81 | /// maps HTTP Upgrade protocol name/version to the ACLs guarding its usage | |
82 | typedef std::deque<NamedGuard> NamedGuards; | |
83 | ||
84 | /// pseudonym to specify rules for "all other protocols" | |
f8de3912 | 85 | inline static const SBuf &ProtoOther(); |
1c2b4465 CT |
86 | |
87 | /// rules governing upgrades to explicitly named protocols | |
88 | NamedGuards namedGuards; | |
89 | ||
90 | /// OTHER rules governing unnamed protocols | |
91 | acl_access *other = nullptr; | |
92 | }; | |
93 | ||
94 | template <typename Visitor> | |
95 | inline void | |
96 | HttpUpgradeProtocolAccess::forEach(const Visitor &visitor) const | |
97 | { | |
98 | for (const auto &namedGuard: namedGuards) | |
99 | visitor(namedGuard.protocol, namedGuard.guard); | |
100 | if (other) | |
f8de3912 | 101 | visitor(ProtoOther(), other); |
1c2b4465 CT |
102 | } |
103 | ||
104 | template <typename Visitor> | |
105 | inline void | |
106 | HttpUpgradeProtocolAccess::forApplicable(const ProtocolView &offer, const Visitor &visitor) const | |
107 | { | |
108 | auto seenApplicable = false; | |
109 | for (const auto &namedGuard: namedGuards) { | |
110 | if (offer.name != namedGuard.proto.name) | |
111 | continue; | |
112 | if (vAinB(offer, namedGuard.proto) && visitor(namedGuard.protocol, namedGuard.guard)) | |
113 | return; | |
114 | seenApplicable = true; // may already be true | |
115 | } | |
116 | if (!seenApplicable && other) // OTHER is applicable if named rules were not | |
f8de3912 FC |
117 | (void)visitor(ProtoOther(), other); |
118 | } | |
119 | ||
120 | inline const SBuf & | |
121 | HttpUpgradeProtocolAccess::ProtoOther() | |
122 | { | |
123 | static const auto proto = new SBuf("OTHER"); | |
124 | return *proto; | |
1c2b4465 CT |
125 | } |
126 | ||
ff9d9458 | 127 | #endif /* SQUID_SRC_HTTPUPGRADEPROTOCOLACCESS_H */ |
1c2b4465 | 128 |