]> git.ipfire.org Git - thirdparty/squid.git/blob - src/HttpHeader.h
c0e2deadf77cf09b27493794dd076e50a8388f85
[thirdparty/squid.git] / src / HttpHeader.h
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