michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* vim: set sw=4 ts=8 et tw=80 : */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef nsHttpHeaderArray_h__ michael@0: #define nsHttpHeaderArray_h__ michael@0: michael@0: #include "nsHttp.h" michael@0: #include "nsTArray.h" michael@0: #include "nsString.h" michael@0: michael@0: class nsIHttpHeaderVisitor; michael@0: michael@0: namespace mozilla { namespace net { michael@0: michael@0: class nsHttpHeaderArray michael@0: { michael@0: public: michael@0: const char *PeekHeader(nsHttpAtom header) const; michael@0: michael@0: // Used by internal setters: to set header from network use SetHeaderFromNet michael@0: nsresult SetHeader(nsHttpAtom header, const nsACString &value, michael@0: bool merge = false); michael@0: michael@0: // Merges supported headers. For other duplicate values, determines if error michael@0: // needs to be thrown or 1st value kept. michael@0: nsresult SetHeaderFromNet(nsHttpAtom header, const nsACString &value); michael@0: michael@0: nsresult GetHeader(nsHttpAtom header, nsACString &value) const; michael@0: void ClearHeader(nsHttpAtom h); michael@0: michael@0: // Find the location of the given header value, or null if none exists. michael@0: const char *FindHeaderValue(nsHttpAtom header, const char *value) const michael@0: { michael@0: return nsHttp::FindToken(PeekHeader(header), value, michael@0: HTTP_HEADER_VALUE_SEPS); michael@0: } michael@0: michael@0: // Determine if the given header value exists. michael@0: bool HasHeaderValue(nsHttpAtom header, const char *value) const michael@0: { michael@0: return FindHeaderValue(header, value) != nullptr; michael@0: } michael@0: michael@0: nsresult VisitHeaders(nsIHttpHeaderVisitor *visitor); michael@0: michael@0: // parse a header line, return the header atom and a pointer to the michael@0: // header value (the substring of the header line -- do not free). michael@0: nsresult ParseHeaderLine(const char *line, michael@0: nsHttpAtom *header=nullptr, michael@0: char **value=nullptr); michael@0: michael@0: void Flatten(nsACString &, bool pruneProxyHeaders=false); michael@0: michael@0: uint32_t Count() const { return mHeaders.Length(); } michael@0: michael@0: const char *PeekHeaderAt(uint32_t i, nsHttpAtom &header) const; michael@0: michael@0: void Clear(); michael@0: michael@0: // Must be copy-constructable and assignable michael@0: struct nsEntry michael@0: { michael@0: nsHttpAtom header; michael@0: nsCString value; michael@0: michael@0: struct MatchHeader { michael@0: bool Equals(const nsEntry &entry, const nsHttpAtom &header) const { michael@0: return entry.header == header; michael@0: } michael@0: }; michael@0: }; michael@0: michael@0: private: michael@0: int32_t LookupEntry(nsHttpAtom header, const nsEntry **) const; michael@0: int32_t LookupEntry(nsHttpAtom header, nsEntry **); michael@0: void MergeHeader(nsHttpAtom header, nsEntry *entry, const nsACString &value); michael@0: michael@0: // Header cannot be merged: only one value possible michael@0: bool IsSingletonHeader(nsHttpAtom header); michael@0: // For some headers we want to track empty values to prevent them being michael@0: // combined with non-empty ones as a CRLF attack vector michael@0: bool TrackEmptyHeader(nsHttpAtom header); michael@0: michael@0: // Subset of singleton headers: should never see multiple, different michael@0: // instances of these, else something fishy may be going on (like CLRF michael@0: // injection) michael@0: bool IsSuspectDuplicateHeader(nsHttpAtom header); michael@0: michael@0: // All members must be copy-constructable and assignable michael@0: nsTArray mHeaders; michael@0: michael@0: friend struct IPC::ParamTraits; michael@0: }; michael@0: michael@0: michael@0: //----------------------------------------------------------------------------- michael@0: // nsHttpHeaderArray : inline functions michael@0: //----------------------------------------------------------------------------- michael@0: michael@0: inline int32_t michael@0: nsHttpHeaderArray::LookupEntry(nsHttpAtom header, const nsEntry **entry) const michael@0: { michael@0: uint32_t index = mHeaders.IndexOf(header, 0, nsEntry::MatchHeader()); michael@0: if (index != UINT32_MAX) michael@0: *entry = &mHeaders[index]; michael@0: return index; michael@0: } michael@0: michael@0: inline int32_t michael@0: nsHttpHeaderArray::LookupEntry(nsHttpAtom header, nsEntry **entry) michael@0: { michael@0: uint32_t index = mHeaders.IndexOf(header, 0, nsEntry::MatchHeader()); michael@0: if (index != UINT32_MAX) michael@0: *entry = &mHeaders[index]; michael@0: return index; michael@0: } michael@0: michael@0: inline bool michael@0: nsHttpHeaderArray::IsSingletonHeader(nsHttpAtom header) michael@0: { michael@0: return header == nsHttp::Content_Type || michael@0: header == nsHttp::Content_Disposition || michael@0: header == nsHttp::Content_Length || michael@0: header == nsHttp::User_Agent || michael@0: header == nsHttp::Referer || michael@0: header == nsHttp::Host || michael@0: header == nsHttp::Authorization || michael@0: header == nsHttp::Proxy_Authorization || michael@0: header == nsHttp::If_Modified_Since || michael@0: header == nsHttp::If_Unmodified_Since || michael@0: header == nsHttp::From || michael@0: header == nsHttp::Location || michael@0: header == nsHttp::Max_Forwards; michael@0: } michael@0: michael@0: inline bool michael@0: nsHttpHeaderArray::TrackEmptyHeader(nsHttpAtom header) michael@0: { michael@0: return header == nsHttp::Content_Length || michael@0: header == nsHttp::Location; michael@0: } michael@0: michael@0: inline void michael@0: nsHttpHeaderArray::MergeHeader(nsHttpAtom header, michael@0: nsEntry *entry, michael@0: const nsACString &value) michael@0: { michael@0: if (value.IsEmpty()) michael@0: return; // merge of empty header = no-op michael@0: michael@0: // Append the new value to the existing value michael@0: if (header == nsHttp::Set_Cookie || michael@0: header == nsHttp::WWW_Authenticate || michael@0: header == nsHttp::Proxy_Authenticate) michael@0: { michael@0: // Special case these headers and use a newline delimiter to michael@0: // delimit the values from one another as commas may appear michael@0: // in the values of these headers contrary to what the spec says. michael@0: entry->value.Append('\n'); michael@0: } else { michael@0: // Delimit each value from the others using a comma (per HTTP spec) michael@0: entry->value.AppendLiteral(", "); michael@0: } michael@0: entry->value.Append(value); michael@0: } michael@0: michael@0: inline bool michael@0: nsHttpHeaderArray::IsSuspectDuplicateHeader(nsHttpAtom header) michael@0: { michael@0: bool retval = header == nsHttp::Content_Length || michael@0: header == nsHttp::Content_Disposition || michael@0: header == nsHttp::Location; michael@0: michael@0: MOZ_ASSERT(!retval || IsSingletonHeader(header), michael@0: "Only non-mergeable headers should be in this list\n"); michael@0: michael@0: return retval; michael@0: } michael@0: michael@0: }} // namespace mozilla::net michael@0: michael@0: #endif