]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1996-2025 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_HTTPHEADER_H | |
10 | #define SQUID_SRC_HTTPHEADER_H | |
11 | ||
12 | #include "anyp/ProtocolVersion.h" | |
13 | #include "base/LookupTable.h" | |
14 | #include "http/RegisteredHeaders.h" | |
15 | /* because we pass a spec by value */ | |
16 | #include "HttpHeaderMask.h" | |
17 | #include "mem/PoolingAllocator.h" | |
18 | #include "sbuf/forward.h" | |
19 | #include "SquidString.h" | |
20 | ||
21 | #include <vector> | |
22 | ||
23 | /* class forward declarations */ | |
24 | class HttpHdrCc; | |
25 | class HttpHdrContRange; | |
26 | class HttpHdrRange; | |
27 | class HttpHdrSc; | |
28 | class Packable; | |
29 | ||
30 | /** Possible owners of http header */ | |
31 | typedef enum { | |
32 | hoNone =0, | |
33 | #if USE_HTCP | |
34 | hoHtcpReply, | |
35 | #endif | |
36 | hoRequest, | |
37 | hoReply, | |
38 | #if USE_OPENSSL | |
39 | hoErrorDetail, | |
40 | #endif | |
41 | hoEnd | |
42 | } http_hdr_owner_type; | |
43 | ||
44 | /** Iteration for headers; use HttpHeaderPos as opaque type, do not interpret */ | |
45 | typedef ssize_t HttpHeaderPos; | |
46 | ||
47 | /* use this and only this to initialize HttpHeaderPos */ | |
48 | #define HttpHeaderInitPos (-1) | |
49 | ||
50 | class HttpHeaderEntry | |
51 | { | |
52 | MEMPROXY_CLASS(HttpHeaderEntry); | |
53 | ||
54 | public: | |
55 | HttpHeaderEntry(Http::HdrType id, const SBuf &name, const char *value); | |
56 | ~HttpHeaderEntry(); | |
57 | static HttpHeaderEntry *parse(const char *field_start, const char *field_end, const http_hdr_owner_type msgType); | |
58 | HttpHeaderEntry *clone() const; | |
59 | void packInto(Packable *p) const; | |
60 | int getInt() const; | |
61 | int64_t getInt64() const; | |
62 | ||
63 | /// expected number of bytes written by packInto(), including ": " and CRLF | |
64 | size_t length() const { return name.length() + 2 + value.size() + 2; } | |
65 | ||
66 | Http::HdrType id; | |
67 | SBuf name; | |
68 | String value; | |
69 | }; | |
70 | ||
71 | class ETag; | |
72 | class TimeOrTag; | |
73 | ||
74 | class HttpHeader | |
75 | { | |
76 | ||
77 | public: | |
78 | explicit HttpHeader(const http_hdr_owner_type owner); | |
79 | HttpHeader(const HttpHeader &other); | |
80 | ~HttpHeader(); | |
81 | ||
82 | HttpHeader &operator =(const HttpHeader &other); | |
83 | ||
84 | /* Interface functions */ | |
85 | void clean(); | |
86 | void append(const HttpHeader * src); | |
87 | /// replaces fields with matching names and adds fresh fields with new names | |
88 | /// assuming `fresh` is a 304 reply | |
89 | void update(const HttpHeader *fresh); | |
90 | /// \returns whether calling update(fresh) would change our set of fields | |
91 | bool needUpdate(const HttpHeader *fresh) const; | |
92 | void compact(); | |
93 | int parse(const char *header_start, size_t len, Http::ContentLengthInterpreter &interpreter); | |
94 | /// Parses headers stored in a buffer. | |
95 | /// \returns 1 and sets hdr_sz on success | |
96 | /// \returns 0 when needs more data | |
97 | /// \returns -1 on error | |
98 | int parse(const char *buf, size_t buf_len, bool atEnd, size_t &hdr_sz, Http::ContentLengthInterpreter &interpreter); | |
99 | void packInto(Packable * p, bool mask_sensitive_info=false) const; | |
100 | HttpHeaderEntry *getEntry(HttpHeaderPos * pos) const; | |
101 | HttpHeaderEntry *findEntry(Http::HdrType id) const; | |
102 | /// deletes all fields with a given name, if any. | |
103 | /// \return #fields deleted | |
104 | int delByName(const SBuf &name); | |
105 | /// \deprecated use SBuf method instead. performance regression: reallocates | |
106 | int delByName(const char *name) { return delByName(SBuf(name)); } | |
107 | int delById(Http::HdrType id); | |
108 | void delAt(HttpHeaderPos pos, int &headers_deleted); | |
109 | void refreshMask(); | |
110 | void addEntry(HttpHeaderEntry * e); | |
111 | String getList(Http::HdrType id) const; | |
112 | bool getList(Http::HdrType id, String *s) const; | |
113 | bool conflictingContentLength() const { return conflictingContentLength_; } | |
114 | String getStrOrList(Http::HdrType id) const; | |
115 | String getByName(const SBuf &name) const; | |
116 | String getByName(const char *name) const; | |
117 | String getById(Http::HdrType id) const; | |
118 | /// returns true iff a [possibly empty] field identified by id is there | |
119 | /// when returning true, also sets the `result` parameter (if it is not nil) | |
120 | bool getByIdIfPresent(Http::HdrType id, String *result) const; | |
121 | /// returns true iff a [possibly empty] named field is there | |
122 | /// when returning true, also sets the `value` parameter (if it is not nil) | |
123 | bool hasNamed(const SBuf &s, String *value = nullptr) const; | |
124 | /// \deprecated use SBuf method instead. | |
125 | bool hasNamed(const char *name, unsigned int namelen, String *value = nullptr) const; | |
126 | /// searches for the first matching key=value pair within the name-identified field | |
127 | /// \returns the value of the found pair or an empty string | |
128 | SBuf getByNameListMember(const char *name, const char *member, const char separator) const; | |
129 | /// searches for the first matching key=value pair within the field | |
130 | /// \returns the value of the found pair or an empty string | |
131 | SBuf getListMember(Http::HdrType id, const char *member, const char separator) const; | |
132 | int has(Http::HdrType id) const; | |
133 | /// Appends "this cache" information to VIA header field. | |
134 | /// Takes the initial VIA value from "from" parameter, if provided. | |
135 | void addVia(const AnyP::ProtocolVersion &ver, const HttpHeader *from = nullptr); | |
136 | void putInt(Http::HdrType id, int number); | |
137 | void putInt64(Http::HdrType id, int64_t number); | |
138 | void putTime(Http::HdrType id, time_t htime); | |
139 | void putStr(Http::HdrType id, const char *str); | |
140 | void putAuth(const char *auth_scheme, const char *realm); | |
141 | void putCc(const HttpHdrCc &cc); | |
142 | void putContRange(const HttpHdrContRange * cr); | |
143 | void putRange(const HttpHdrRange * range); | |
144 | void putSc(HttpHdrSc *sc); | |
145 | void putExt(const char *name, const char *value); | |
146 | ||
147 | /// Ensures that the header has the given field, removing or replacing any | |
148 | /// same-name fields with conflicting values as needed. | |
149 | void updateOrAddStr(Http::HdrType, const SBuf &); | |
150 | ||
151 | int getInt(Http::HdrType id) const; | |
152 | int64_t getInt64(Http::HdrType id) const; | |
153 | time_t getTime(Http::HdrType id) const; | |
154 | const char *getStr(Http::HdrType id) const; | |
155 | const char *getLastStr(Http::HdrType id) const; | |
156 | HttpHdrCc *getCc() const; | |
157 | HttpHdrRange *getRange() const; | |
158 | HttpHdrSc *getSc() const; | |
159 | HttpHdrContRange *getContRange() const; | |
160 | SBuf getAuthToken(Http::HdrType id, const char *auth_scheme) const; | |
161 | ETag getETag(Http::HdrType id) const; | |
162 | TimeOrTag getTimeOrTag(Http::HdrType id) const; | |
163 | int hasListMember(Http::HdrType id, const char *member, const char separator) const; | |
164 | int hasByNameListMember(const char *name, const char *member, const char separator) const; | |
165 | void removeHopByHopEntries(); | |
166 | ||
167 | /// whether the message uses chunked Transfer-Encoding | |
168 | /// optimized implementation relies on us rejecting/removing other codings | |
169 | bool chunked() const { return has(Http::HdrType::TRANSFER_ENCODING); } | |
170 | ||
171 | /// whether message used an unsupported and/or invalid Transfer-Encoding | |
172 | bool unsupportedTe() const { return teUnsupported_; } | |
173 | ||
174 | /* protected, do not use these, use interface functions instead */ | |
175 | std::vector<HttpHeaderEntry*, PoolingAllocator<HttpHeaderEntry*> > entries; /**< parsed fields in raw format */ | |
176 | HttpHeaderMask mask; /**< bit set <=> entry present */ | |
177 | http_hdr_owner_type owner; /**< request or reply */ | |
178 | int len; /**< length when packed, not counting terminating null-byte */ | |
179 | ||
180 | protected: | |
181 | /** \deprecated Public access replaced by removeHopByHopEntries() */ | |
182 | void removeConnectionHeaderEntries(); | |
183 | /// either finds the end of headers or returns false | |
184 | /// If the end was found: | |
185 | /// *parse_start points to the first character after the header delimiter | |
186 | /// *blk_start points to the first header character (i.e. old parse_start value) | |
187 | /// *blk_end points to the first header delimiter character (CR or LF in CR?LF). | |
188 | /// If block starts where it ends, then there are no fields in the header. | |
189 | static bool Isolate(const char **parse_start, size_t l, const char **blk_start, const char **blk_end); | |
190 | bool skipUpdateHeader(const Http::HdrType id) const; | |
191 | ||
192 | private: | |
193 | HttpHeaderEntry *findLastEntry(Http::HdrType id) const; | |
194 | bool conflictingContentLength_; ///< found different Content-Length fields | |
195 | /// unsupported encoding, unnecessary syntax characters, and/or | |
196 | /// invalid field-value found in Transfer-Encoding header | |
197 | bool teUnsupported_ = false; | |
198 | }; | |
199 | ||
200 | int httpHeaderParseQuotedString(const char *start, const int len, String *val); | |
201 | ||
202 | namespace Http { | |
203 | ||
204 | /** | |
205 | * Parses an HTTP quoted-string sequence (RFC 9110, Section 5.6.4). | |
206 | * | |
207 | * \param a brief human-friendly description of the string being parsed | |
208 | * \param start input buffer (an opening double-quote is expected at *start) | |
209 | * \param length is the number of characters in the given buffer | |
210 | * | |
211 | * \returns string contents with open/closing quotes stripped and any quoted-pairs decoded | |
212 | * | |
213 | * Avoid this slow function on performance-sensitive code paths. | |
214 | * TODO: Replace with an efficient, SBuf-friendly implementation. | |
215 | * | |
216 | * \sa httpHeaderParseQuotedString() for a String-friendly function. | |
217 | */ | |
218 | SBuf SlowlyParseQuotedString(const char *description, const char *start, size_t length); | |
219 | ||
220 | } | |
221 | ||
222 | /// quotes string using RFC 7230 quoted-string rules | |
223 | SBuf httpHeaderQuoteString(const char *raw); | |
224 | ||
225 | void httpHeaderCalcMask(HttpHeaderMask * mask, Http::HdrType http_hdr_type_enums[], size_t count); | |
226 | ||
227 | void httpHeaderInitModule(void); | |
228 | ||
229 | #endif /* SQUID_SRC_HTTPHEADER_H */ | |
230 |