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