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