]>
Commit | Line | Data |
---|---|---|
985c86bc | 1 | /* |
77b1029d | 2 | * Copyright (C) 1996-2020 The Squid Software Foundation and contributors |
bbc27441 AJ |
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. | |
985c86bc | 7 | */ |
8 | ||
bbc27441 AJ |
9 | /* DEBUG: section 73 HTTP Request */ |
10 | ||
582c2af2 | 11 | #include "squid.h" |
f35c0145 | 12 | #include "http/RequestMethod.h" |
3580c04e | 13 | #include "SquidConfig.h" |
985c86bc | 14 | #include "wordlist.h" |
15 | ||
c2a7cefd AJ |
16 | static Http::MethodType & |
17 | operator++ (Http::MethodType &aMethod) | |
985c86bc | 18 | { |
19 | int tmp = (int)aMethod; | |
c2a7cefd | 20 | aMethod = (Http::MethodType)(++tmp); |
985c86bc | 21 | return aMethod; |
22 | } | |
23 | ||
c2a7cefd | 24 | /** |
7a4fa6a0 AJ |
25 | * Construct a HttpRequestMethod from a C-string such as "GET" |
26 | * Assumes the string is either nul-terminated or contains whitespace | |
27 | * | |
28 | * \deprecated use SBuf constructor instead | |
985c86bc | 29 | */ |
f9688132 AJ |
30 | void |
31 | HttpRequestMethod::HttpRequestMethodXXX(char const *begin) | |
985c86bc | 32 | { |
f9688132 AJ |
33 | // XXX: performance regression due to this method no longer being a constructor |
34 | // ensure the members are empty/default values before any of the early-return | |
35 | // optimizations can be used. | |
36 | theMethod = Http::METHOD_NONE; | |
37 | theImage.clear(); | |
38 | ||
985c86bc | 39 | if (begin == NULL) |
40 | return; | |
41 | ||
7a4fa6a0 | 42 | char const *end = begin + strcspn(begin, w_space); |
26ac0430 | 43 | |
7f06a3d8 | 44 | if (end == begin) |
26ac0430 | 45 | return; |
26ac0430 | 46 | |
7f06a3d8 | 47 | // TODO: Optimize this linear search. |
c2a7cefd | 48 | for (++theMethod; theMethod < Http::METHOD_ENUM_END; ++theMethod) { |
9b77743c AJ |
49 | // RFC 2616 section 5.1.1 - Method names are case-sensitive |
50 | // NP: this is not a HTTP_VIOLATIONS case since there is no MUST/SHOULD involved. | |
7f06a3d8 | 51 | if (0 == image().caseCmp(begin, end-begin)) { |
9b77743c AJ |
52 | |
53 | // relaxed parser allows mixed-case and corrects them on output | |
54 | if (Config.onoff.relaxed_header_parser) | |
55 | return; | |
56 | ||
7f06a3d8 | 57 | if (0 == image().cmp(begin, end-begin)) |
9b77743c | 58 | return; |
60745f24 | 59 | } |
985c86bc | 60 | } |
61 | ||
60745f24 | 62 | // if method not found and method string is not null then it is other method |
c2a7cefd | 63 | theMethod = Http::METHOD_OTHER; |
7f06a3d8 | 64 | theImage.assign(begin, end-begin); |
985c86bc | 65 | } |
66 | ||
7a4fa6a0 AJ |
67 | /** |
68 | * Construct a HttpRequestMethod from an SBuf string such as "GET" | |
f9688132 | 69 | * or from a range of chars such as "FOO" from buffer "GETFOOBARBAZ" |
7a4fa6a0 | 70 | * |
f9688132 | 71 | * Assumes the s parameter contains only the characters representing the method name |
7a4fa6a0 AJ |
72 | */ |
73 | HttpRequestMethod::HttpRequestMethod(const SBuf &s) : theMethod(Http::METHOD_NONE) | |
74 | { | |
75 | if (s.isEmpty()) | |
76 | return; | |
77 | ||
7a4fa6a0 AJ |
78 | // TODO: Optimize this linear search. |
79 | for (++theMethod; theMethod < Http::METHOD_ENUM_END; ++theMethod) { | |
80 | // RFC 2616 section 5.1.1 - Method names are case-sensitive | |
81 | // NP: this is not a HTTP_VIOLATIONS case since there is no MUST/SHOULD involved. | |
82 | if (0 == image().caseCmp(s)) { | |
83 | ||
84 | // relaxed parser allows mixed-case and corrects them on output | |
85 | if (Config.onoff.relaxed_header_parser) | |
86 | return; | |
87 | ||
88 | if (0 == image().cmp(s)) | |
89 | return; | |
90 | } | |
91 | } | |
92 | ||
93 | // if method not found and method string is not null then it is other method | |
94 | theMethod = Http::METHOD_OTHER; | |
95 | theImage = s; | |
96 | } | |
97 | ||
7f06a3d8 | 98 | const SBuf & |
c2a7cefd | 99 | HttpRequestMethod::image() const |
985c86bc | 100 | { |
7f06a3d8 | 101 | static const SBuf methodOther("METHOD_OTHER"); |
c2a7cefd | 102 | if (Http::METHOD_OTHER != theMethod) { |
7f06a3d8 | 103 | return Http::MethodType_sb[theMethod]; |
c2a7cefd | 104 | } else { |
7f06a3d8 AJ |
105 | if (!theImage.isEmpty()) { |
106 | return theImage; | |
c2a7cefd | 107 | } else { |
7f06a3d8 | 108 | return methodOther; |
985c86bc | 109 | } |
c2a7cefd AJ |
110 | } |
111 | } | |
985c86bc | 112 | |
c2a7cefd AJ |
113 | bool |
114 | HttpRequestMethod::isHttpSafe() const | |
115 | { | |
116 | // Only a few methods are defined as safe. All others are "unsafe" | |
985c86bc | 117 | |
c2a7cefd AJ |
118 | // NOTE: |
119 | // All known RFCs which register methods are listed in comments. | |
ffb82151 | 120 | // if there is one not listed which defines methods, it needs |
c2a7cefd | 121 | // checking and adding. If only to say it is known to define none. |
985c86bc | 122 | |
ffb82151 | 123 | switch (theMethod) { |
f53969cc | 124 | // RFC 2068 - none |
985c86bc | 125 | |
f53969cc | 126 | // RFC 2616 section 9.1.1 |
c2a7cefd AJ |
127 | case Http::METHOD_GET: |
128 | case Http::METHOD_HEAD: | |
129 | case Http::METHOD_OPTIONS: | |
985c86bc | 130 | |
f53969cc | 131 | // RFC 3253 section 3.6 |
c2a7cefd | 132 | case Http::METHOD_REPORT: |
985c86bc | 133 | |
f53969cc SM |
134 | // RFC 3648 - none |
135 | // RFC 3744 - none | |
136 | // RFC 4437 - none | |
137 | // RFC 4791 - none | |
985c86bc | 138 | |
f53969cc | 139 | // RFC 4918 section 9.1 |
c2a7cefd | 140 | case Http::METHOD_PROPFIND: |
985c86bc | 141 | |
f53969cc | 142 | // RFC 5323 section 2 |
c2a7cefd | 143 | case Http::METHOD_SEARCH: |
985c86bc | 144 | |
f1554620 SM |
145 | // RFC 5789 - none |
146 | // RFC 5842 - none | |
985c86bc | 147 | |
c27e1e37 AJ |
148 | // RFC 7540 section 11.6 |
149 | case Http::METHOD_PRI: | |
150 | ||
c2a7cefd | 151 | return true; |
60745f24 | 152 | |
c2a7cefd AJ |
153 | default: |
154 | return false; | |
914b89a2 | 155 | } |
60745f24 | 156 | } |
157 | ||
26ac0430 | 158 | bool |
c2a7cefd | 159 | HttpRequestMethod::isIdempotent() const |
60745f24 | 160 | { |
c2a7cefd AJ |
161 | // Only a few methods are defined as idempotent. |
162 | ||
163 | // NOTE: | |
164 | // All known RFCs which register methods are listed in comments. | |
ffb82151 | 165 | // if there is one not listed which defines methods, it needs |
c2a7cefd AJ |
166 | // checking and adding. If only to say it is known to define none. |
167 | ||
ffb82151 | 168 | switch (theMethod) { |
f53969cc | 169 | // RFC 2068 - TODO check LINK/UNLINK definition |
c2a7cefd | 170 | |
f53969cc | 171 | // RFC 2616 section 9.1.2 |
c2a7cefd AJ |
172 | case Http::METHOD_GET: |
173 | case Http::METHOD_HEAD: | |
174 | case Http::METHOD_PUT: | |
175 | case Http::METHOD_DELETE: | |
176 | case Http::METHOD_OPTIONS: | |
177 | case Http::METHOD_TRACE: | |
178 | ||
f53969cc SM |
179 | // RFC 3253 - TODO check |
180 | // RFC 3648 - TODO check | |
181 | // RFC 3744 - TODO check | |
182 | // RFC 4437 - TODO check | |
183 | // RFC 4791 - TODO check | |
c2a7cefd | 184 | |
f53969cc | 185 | // RFC 4918 section 9 |
c2a7cefd AJ |
186 | case Http::METHOD_PROPFIND: |
187 | case Http::METHOD_PROPPATCH: | |
188 | case Http::METHOD_MKCOL: | |
189 | case Http::METHOD_COPY: | |
190 | case Http::METHOD_MOVE: | |
191 | case Http::METHOD_UNLOCK: | |
192 | ||
f1554620 SM |
193 | // RFC 5323 - TODO check |
194 | // RFC 5789 - TODO check | |
195 | // RFC 5842 - TODO check | |
c1520b67 | 196 | |
c27e1e37 AJ |
197 | // RFC 7540 section 11.6 |
198 | case Http::METHOD_PRI: | |
199 | ||
c2a7cefd | 200 | return true; |
60745f24 | 201 | |
c2a7cefd | 202 | default: |
60745f24 | 203 | return false; |
c2a7cefd AJ |
204 | } |
205 | } | |
60745f24 | 206 | |
c2a7cefd AJ |
207 | bool |
208 | HttpRequestMethod::respMaybeCacheable() const | |
209 | { | |
210 | // Only a few methods are defined as cacheable. | |
211 | // All other methods from the below RFC are "MUST NOT cache" | |
ffb82151 | 212 | switch (theMethod) { |
f53969cc | 213 | // RFC 2616 section 9 |
c2a7cefd AJ |
214 | case Http::METHOD_GET: |
215 | case Http::METHOD_HEAD: | |
216 | return true; | |
217 | #if WHEN_POST_CACHE_SUPPORTED | |
218 | case Http::METHOD_POST: // Special case. | |
219 | // RFC 2616 specifies POST as possibly cacheable | |
220 | // However, Squid does not implement the required checks yet | |
221 | return true; | |
222 | #endif | |
60745f24 | 223 | |
c2a7cefd AJ |
224 | // RFC 4918 section 9 |
225 | #if WHEN_PROPFIND_CACHE_SUPPORTED | |
226 | case Http::METHOD_PROPFIND: // Special case. | |
227 | // RFC 4918 specifies PROPFIND as possibly cacheable | |
228 | // However, Squid does not implement the required checks yet | |
229 | return true; | |
230 | #endif | |
26ac0430 | 231 | |
c2a7cefd AJ |
232 | // RFC 5323 section 2 - defines no cacheable methods |
233 | ||
234 | // RFC 3253 | |
235 | #if WHEN_CC_NOCACHE_DOES_REVALIDATES_IS_CONFIRMED | |
236 | case Http::METHOD_CHECKOUT: | |
237 | case Http::METHOD_CHECKIN: | |
238 | case Http::METHOD_UNCHECKOUT: | |
239 | case Http::METHOD_MKWORKSPACE: | |
240 | case Http::METHOD_VERSION_CONTROL: | |
241 | case Http::METHOD_UPDATE: | |
242 | case Http::METHOD_LABEL: | |
243 | case Http::METHOD_MERGE: | |
244 | case Http::METHOD_BASELINE_CONTROL: | |
245 | case Http::METHOD_MKACTIVITY: | |
246 | // RFC 3253 defines these methods using "MUST include Cache-Control: no-cache". | |
247 | // | |
248 | // XXX: follow RFC 2616 definition of "no-cache" meaning "MAY cache, always revalidate" | |
249 | // XXX: or treat as unregistered/undefined methods ?? | |
250 | // However, Squid may not implement the required revalidation checks yet | |
251 | return ??; | |
252 | #endif | |
26ac0430 | 253 | |
f53969cc SM |
254 | // Special Squid method tokens are not cacheable. |
255 | // RFC 2616 defines all unregistered or unspecified methods as non-cacheable | |
256 | // until such time as an RFC defines them cacheable. | |
c2a7cefd AJ |
257 | default: |
258 | return false; | |
259 | } | |
60745f24 | 260 | } |
c1520b67 | 261 | |
26ac0430 | 262 | bool |
c2a7cefd | 263 | HttpRequestMethod::shouldInvalidate() const |
c1520b67 | 264 | { |
c1520b67 | 265 | switch (theMethod) { |
f53969cc | 266 | /* RFC 2616 section 13.10 - "MUST invalidate" */ |
c2a7cefd AJ |
267 | case Http::METHOD_POST: |
268 | case Http::METHOD_PUT: | |
269 | case Http::METHOD_DELETE: | |
26ac0430 | 270 | return true; |
c1520b67 | 271 | |
f53969cc | 272 | /* Squid extension to force invalidation */ |
c2a7cefd | 273 | case Http::METHOD_PURGE: |
26ac0430 | 274 | return true; |
c1520b67 | 275 | |
f53969cc SM |
276 | /* |
277 | * RFC 2616 sayeth, in section 13.10, final paragraph: | |
278 | * A cache that passes through requests for methods it does not | |
279 | * understand SHOULD invalidate any entities referred to by the | |
280 | * Request-URI. | |
281 | */ | |
c2a7cefd | 282 | case Http::METHOD_OTHER: |
26ac0430 | 283 | return true; |
c2a7cefd AJ |
284 | |
285 | default: | |
286 | // Methods which are known but not required to invalidate. | |
287 | return false; | |
26ac0430 | 288 | } |
c2a7cefd | 289 | } |
c1520b67 | 290 | |
c2a7cefd AJ |
291 | bool |
292 | HttpRequestMethod::purgesOthers() const | |
293 | { | |
294 | if (shouldInvalidate()) | |
295 | return true; | |
296 | ||
297 | switch (theMethod) { | |
f53969cc | 298 | /* common sense suggests purging is not required? */ |
c2a7cefd AJ |
299 | case Http::METHOD_GET: // XXX: but we do purge HEAD on successful GET |
300 | case Http::METHOD_HEAD: | |
301 | case Http::METHOD_NONE: | |
302 | case Http::METHOD_CONNECT: | |
303 | case Http::METHOD_TRACE: | |
304 | case Http::METHOD_OPTIONS: | |
305 | case Http::METHOD_PROPFIND: | |
306 | case Http::METHOD_COPY: | |
307 | case Http::METHOD_LOCK: | |
308 | case Http::METHOD_UNLOCK: | |
309 | case Http::METHOD_SEARCH: | |
310 | return false; | |
311 | ||
312 | default: | |
313 | return true; | |
314 | } | |
c1520b67 | 315 | } |
f53969cc | 316 |