/*
+ * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
*
- * SQUID Web Proxy Cache http://www.squid-cache.org/
- * ----------------------------------------------------------
- *
- * Squid is the result of efforts by numerous individuals from
- * the Internet community; see the CONTRIBUTORS file for full
- * details. Many organizations have provided support for Squid's
- * development; see the SPONSORS file for full details. Squid is
- * Copyrighted (C) 2001 by the Regents of the University of
- * California; see the COPYRIGHT file for full details. Squid
- * incorporates software developed and/or copyrighted by other
- * sources; see the CREDITS file for full details.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
- *
+ * 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_HTTPHEADER_H
#define SQUID_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 "MemPool.h"
+#include "mem/forward.h"
+#include "sbuf/forward.h"
#include "SquidString.h"
#include <vector>
class HttpHdrContRange;
class HttpHdrRange;
class HttpHdrSc;
-class Packer;
-class StoreEntry;
-
-/* constant attributes of http header fields */
-
-/// recognized or "known" header fields; and the RFC which defines them (or not)
-typedef enum {
- HDR_BAD_HDR = -1,
- HDR_ACCEPT = 0, /**< RFC 2608, 2616 */
- HDR_ACCEPT_CHARSET, /**< RFC 2608, 2616 */
- HDR_ACCEPT_ENCODING, /**< RFC 2608, 2616 */
- /*HDR_ACCEPT_FEATURES,*/ /* experimental RFC 2295 */
- HDR_ACCEPT_LANGUAGE, /**< RFC 2608, 2616 */
- HDR_ACCEPT_RANGES, /**< RFC 2608, 2616 */
- HDR_AGE, /**< RFC 2608, 2616 */
- HDR_ALLOW, /**< RFC 2608, 2616 */
- /*HDR_ALTERNATES,*/ /* deprecated RFC 2068, 2295 */
- HDR_AUTHORIZATION, /**< RFC 2608, 2616, 4559 */
- HDR_CACHE_CONTROL, /**< RFC 2608, 2616 */
- HDR_CONNECTION, /**< RFC 2608, 2616 */
- HDR_CONTENT_BASE, /**< RFC 2608 */
- HDR_CONTENT_DISPOSITION, /**< RFC 2183, 2616 */
- HDR_CONTENT_ENCODING, /**< RFC 2608, 2616 */
- HDR_CONTENT_LANGUAGE, /**< RFC 2608, 2616 */
- HDR_CONTENT_LENGTH, /**< RFC 2608, 2616 */
- HDR_CONTENT_LOCATION, /**< RFC 2608, 2616 */
- HDR_CONTENT_MD5, /**< RFC 2608, 2616 */
- HDR_CONTENT_RANGE, /**< RFC 2608, 2616 */
- HDR_CONTENT_TYPE, /**< RFC 2608, 2616 */
- /*HDR_CONTENT_VERSION,*/ /* deprecated RFC 2608 header. */
- HDR_COOKIE, /**< de-facto and RFC 2965 header we may need to erase */
- HDR_COOKIE2, /**< obsolete RFC 2965 header we may need to erase */
- HDR_DATE, /**< RFC 2608, 2616 */
- /*HDR_DAV,*/ /* RFC 2518 */
- /*HDR_DEPTH,*/ /* RFC 2518 */
- /*HDR_DERIVED_FROM,*/ /* deprecated RFC 2608 */
- /*HDR_DESTINATION,*/ /* RFC 2518 */
- HDR_ETAG, /**< RFC 2608, 2616 */
- HDR_EXPECT, /**< RFC 2616, 2616 */
- HDR_EXPIRES, /**< RFC 2608, 2616 */
- HDR_FROM, /**< RFC 2608, 2616 */
- HDR_HOST, /**< RFC 2608, 2616 */
- HDR_HTTP2_SETTINGS, /**< HTTP/2.0 upgrade header. see draft-ietf-httpbis-http2-04 */
- /*HDR_IF,*/ /* RFC 2518 */
- HDR_IF_MATCH, /**< RFC 2608, 2616 */
- HDR_IF_MODIFIED_SINCE, /**< RFC 2608, 2616 */
- HDR_IF_NONE_MATCH, /**< RFC 2608, 2616 */
- HDR_IF_RANGE, /**< RFC 2608, 2616 */
- /*HDR_IF_UNMODIFIED_SINCE,*/ /**< RFC 2608, 2616 */
- HDR_KEEP_ALIVE, /**< obsolete HTTP/1.0 header we may need to erase */
- HDR_KEY, /**< experimental RFC Draft draft-fielding-http-key-02 */
- HDR_LAST_MODIFIED, /**< RFC 2608, 2616 */
- HDR_LINK, /**< RFC 2068 */
- HDR_LOCATION, /**< RFC 2608, 2616 */
- /*HDR_LOCK_TOKEN,*/ /* RFC 2518 */
- HDR_MAX_FORWARDS, /**< RFC 2608, 2616 */
- HDR_MIME_VERSION, /**< RFC 2626 */
- HDR_NEGOTIATE, /**< experimental RFC 2295. Why only this one from 2295? */
- /*HDR_OVERWRITE,*/ /* RFC 2518 */
- HDR_ORIGIN, /* CORS Draft specification (see http://www.w3.org/TR/cors/) */
- HDR_PRAGMA, /**< deprecated RFC 2068,2616 header we may need to erase */
- HDR_PROXY_AUTHENTICATE, /**< RFC 2608, 2616, 2617 */
- HDR_PROXY_AUTHENTICATION_INFO, /**< RFC 2617 */
- HDR_PROXY_AUTHORIZATION, /**< RFC 2608, 2616, 2617 */
- HDR_PROXY_CONNECTION, /**< obsolete Netscape header we may need to erase. */
- HDR_PROXY_SUPPORT, /**< RFC 4559 */
- HDR_PUBLIC, /**< RFC 2608 */
- HDR_RANGE, /**< RFC 2608, 2616 */
- HDR_REFERER, /**< RFC 2608, 2616 */
- HDR_REQUEST_RANGE, /**< some clients use this, sigh */
- HDR_RETRY_AFTER, /**< RFC 2608, 2616 */
- HDR_SERVER, /**< RFC 2608, 2616 */
- HDR_SET_COOKIE, /**< de-facto standard header we may need to erase */
- HDR_SET_COOKIE2, /**< obsolete RFC 2965 header we may need to erase */
- /*HDR_STATUS_URI,*/ /* RFC 2518 */
- /*HDR_TCN,*/ /* experimental RFC 2295 */
- HDR_TE, /**< RFC 2616 */
- /*HDR_TIMEOUT,*/ /* RFC 2518 */
- HDR_TITLE, /* obsolete draft suggested header */
- HDR_TRAILER, /**< RFC 2616 */
- HDR_TRANSFER_ENCODING, /**< RFC 2608, 2616 */
- HDR_TRANSLATE, /**< IIS custom header we may need to erase */
- HDR_UNLESS_MODIFIED_SINCE, /**< IIS custom header we may need to erase */
- HDR_UPGRADE, /**< RFC 2608, 2616 */
- /*HDR_URI,*/ /* obsolete RFC 2068 header */
- HDR_USER_AGENT, /**< RFC 2608, 2616 */
- /*HDR_VARIANT_VARY,*/ /* experimental RFC 2295 */
- HDR_VARY, /**< RFC 2608, 2616 */
- HDR_VIA, /**< RFC 2608, 2616 */
- HDR_WARNING, /**< RFC 2608, 2616 */
- HDR_WWW_AUTHENTICATE, /**< RFC 2608, 2616, 2617, 4559 */
- HDR_AUTHENTICATION_INFO, /**< RFC 2617 */
- HDR_X_CACHE, /**< Squid custom header */
- HDR_X_CACHE_LOOKUP, /**< Squid custom header. temporary hack that became de-facto. TODO remove */
- HDR_X_FORWARDED_FOR, /**< Squid custom header */
- HDR_X_REQUEST_URI, /**< Squid custom header appended if ADD_X_REQUEST_URI is defined */
- HDR_X_SQUID_ERROR, /**< Squid custom header on generated error responses */
-#if X_ACCELERATOR_VARY
- HDR_X_ACCELERATOR_VARY, /**< obsolete Squid custom header. */
-#endif
-#if USE_ADAPTATION
- HDR_X_NEXT_SERVICES, /**< Squid custom ICAP header */
-#endif
- HDR_SURROGATE_CAPABILITY, /**< Edge Side Includes (ESI) header */
- HDR_SURROGATE_CONTROL, /**< Edge Side Includes (ESI) header */
- HDR_FRONT_END_HTTPS, /**< MS Exchange custom header we may have to add */
- HDR_OTHER, /**< internal tag value for "unknown" headers */
- HDR_ENUM_END
-} http_hdr_type;
-
-/** possible types for http header fields */
-typedef enum {
- ftInvalid = HDR_ENUM_END, /**< to catch nasty errors with hdr_id<->fld_type clashes */
- ftInt,
- ftInt64,
- ftStr,
- ftDate_1123,
- ftETag,
- ftPCc,
- ftPContRange,
- ftPRange,
- ftPSc,
- ftDate_1123_or_ETag
-} field_type;
+class Packable;
/** Possible owners of http header */
typedef enum {
#endif
hoRequest,
hoReply,
-#if USE_SSL
+#if USE_OPENSSL
hoErrorDetail,
#endif
hoEnd
} http_hdr_owner_type;
-// currently a POD
-class HttpHeaderFieldAttrs
-{
-public:
- const char *name;
- http_hdr_type id;
- field_type type;
-};
-
/** Iteration for headers; use HttpHeaderPos as opaque type, do not interpret */
typedef ssize_t HttpHeaderPos;
class HttpHeaderEntry
{
+ MEMPROXY_CLASS(HttpHeaderEntry);
public:
- HttpHeaderEntry(http_hdr_type id, const char *name, const char *value);
+ HttpHeaderEntry(Http::HdrType id, const SBuf &name, const char *value);
~HttpHeaderEntry();
static HttpHeaderEntry *parse(const char *field_start, const char *field_end);
HttpHeaderEntry *clone() const;
- void packInto(Packer *p) const;
+ void packInto(Packable *p) const;
int getInt() const;
int64_t getInt64() const;
- MEMPROXY_CLASS(HttpHeaderEntry);
- http_hdr_type id;
- String name;
+
+ Http::HdrType id;
+ SBuf name;
String value;
};
-MEMPROXY_CLASS_INLINE(HttpHeaderEntry);
-
class ETag;
class TimeOrTag;
/* Interface functions */
void clean();
void append(const HttpHeader * src);
- void update (HttpHeader const *fresh, HttpHeaderMask const *denied_mask);
+ bool update(HttpHeader const *fresh);
void compact();
- int reset();
- int parse(const char *header_start, const char *header_end);
- void packInto(Packer * p, bool mask_sensitive_info=false) const;
+ int parse(const char *header_start, size_t len);
+ /// 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);
+ void packInto(Packable * p, bool mask_sensitive_info=false) const;
HttpHeaderEntry *getEntry(HttpHeaderPos * pos) const;
- HttpHeaderEntry *findEntry(http_hdr_type id) const;
- int delByName(const char *name);
- int delById(http_hdr_type id);
+ 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);
void insertEntry(HttpHeaderEntry * e);
- String getList(http_hdr_type id) const;
- bool getList(http_hdr_type id, String *s) const;
- String getStrOrList(http_hdr_type id) const;
+ 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;
- /// sets value and returns true iff a [possibly empty] named field is there
- bool getByNameIfPresent(const char *name, String &value) 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 = 0) const;
+ /// \deprecated use SBuf method instead.
+ bool hasNamed(const char *name, unsigned int namelen, String *value = 0) const;
String getByNameListMember(const char *name, const char *member, const char separator) const;
- String getListMember(http_hdr_type id, const char *member, const char separator) const;
- int has(http_hdr_type id) const;
- void putInt(http_hdr_type id, int number);
- void putInt64(http_hdr_type id, int64_t number);
- void putTime(http_hdr_type id, time_t htime);
- void insertTime(http_hdr_type id, time_t htime);
- void putStr(http_hdr_type id, const char *str);
+ String 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 = 0);
+ 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 putSc(HttpHdrSc *sc);
void putWarning(const int code, const char *const text); ///< add a Warning header
void putExt(const char *name, const char *value);
- int getInt(http_hdr_type id) const;
- int64_t getInt64(http_hdr_type id) const;
- time_t getTime(http_hdr_type id) const;
- const char *getStr(http_hdr_type id) const;
- const char *getLastStr(http_hdr_type id) const;
+ 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;
- const char *getAuth(http_hdr_type id, const char *auth_scheme) const;
- ETag getETag(http_hdr_type id) const;
- TimeOrTag getTimeOrTag(http_hdr_type id) const;
- int hasListMember(http_hdr_type id, const char *member, const char separator) const;
+ const char *getAuth(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();
inline bool chunked() const; ///< whether message uses chunked Transfer-Encoding
/* protected, do not use these, use interface functions instead */
- std::vector<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 */
+ std::vector<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 needUpdate(const HttpHeader *fresh) const;
+ bool skipUpdateHeader(const Http::HdrType id) const;
+ void updateWarnings();
private:
- HttpHeaderEntry *findLastEntry(http_hdr_type id) const;
+ HttpHeaderEntry *findLastEntry(Http::HdrType id) const;
+ bool conflictingContentLength_; ///< found different Content-Length fields
};
int httpHeaderParseQuotedString(const char *start, const int len, String *val);
-int httpHeaderHasByNameListMember(const HttpHeader * hdr, const char *name, const char *member, const char separator);
-void httpHeaderUpdate(HttpHeader * old, const HttpHeader * fresh, const HttpHeaderMask * denied_mask);
-void httpHeaderCalcMask(HttpHeaderMask * mask, http_hdr_type http_hdr_type_enums[], size_t count);
+
+/// 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);
inline bool
HttpHeader::chunked() const
{
- return has(HDR_TRANSFER_ENCODING) &&
- hasListMember(HDR_TRANSFER_ENCODING, "chunked", ',');
+ return has(Http::HdrType::TRANSFER_ENCODING) &&
+ hasListMember(Http::HdrType::TRANSFER_ENCODING, "chunked", ',');
}
void httpHeaderInitModule(void);
-void httpHeaderCleanModule(void);
#endif /* SQUID_HTTPHEADER_H */
+