]> git.ipfire.org Git - thirdparty/squid.git/blob - src/HttpUpgradeProtocolAccess.h
Bug 5428: Warn if pkg-config is not found (#1902)
[thirdparty/squid.git] / src / HttpUpgradeProtocolAccess.h
1 /*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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
9 #ifndef SQUID_SRC_HTTPUPGRADEPROTOCOLACCESS_H
10 #define SQUID_SRC_HTTPUPGRADEPROTOCOLACCESS_H
11
12 #include "acl/forward.h"
13 #include "sbuf/SBuf.h"
14
15 #include <deque>
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
44 class ConfigParser;
45
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"
85 inline static const SBuf &ProtoOther();
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)
101 visitor(ProtoOther(), other);
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
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;
125 }
126
127 #endif /* SQUID_SRC_HTTPUPGRADEPROTOCOLACCESS_H */
128