LCOV - code coverage report
Current view: top level - netwerk/protocol/http - nsHttpHeaderArray.h (source / functions) Hit Total Coverage
Test: output.info Lines: 29 82 35.4 %
Date: 2017-07-14 16:53:18 Functions: 13 20 65.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim: set sw=4 ts=8 et tw=80 : */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #ifndef nsHttpHeaderArray_h__
       8             : #define nsHttpHeaderArray_h__
       9             : 
      10             : #include "nsHttp.h"
      11             : #include "nsTArray.h"
      12             : #include "nsString.h"
      13             : 
      14             : class nsIHttpHeaderVisitor;
      15             : 
      16             : // This needs to be forward declared here so we can include only this header
      17             : // without also including PHttpChannelParams.h
      18             : namespace IPC {
      19             :     template <typename> struct ParamTraits;
      20             : } // namespace IPC
      21             : 
      22             : namespace mozilla { namespace net {
      23             : 
      24          77 : class nsHttpHeaderArray
      25             : {
      26             : public:
      27             :     const char *PeekHeader(nsHttpAtom header) const;
      28             : 
      29             :     // For nsHttpResponseHead nsHttpHeaderArray will keep track of the original
      30             :     // headers as they come from the network and the parse headers used in
      31             :     // firefox.
      32             :     // If the original and the firefox header are the same, we will keep just
      33             :     // one copy and marked it as eVarietyResponseNetOriginalAndResponse.
      34             :     // If firefox header representation changes a header coming from the
      35             :     // network (e.g. merged it) or a eVarietyResponseNetOriginalAndResponse
      36             :     // header has been changed by SetHeader method, we will keep the original
      37             :     // header as eVarietyResponseNetOriginal and make a copy for the new header
      38             :     // and mark it as eVarietyResponse.
      39             :     enum HeaderVariety
      40             :     {
      41             :         eVarietyUnknown,
      42             :         // Used only for request header.
      43             :         eVarietyRequestOverride,
      44             :         eVarietyRequestDefault,
      45             :         // Used only for response header.
      46             :         eVarietyResponseNetOriginalAndResponse,
      47             :         eVarietyResponseNetOriginal,
      48             :         eVarietyResponse
      49             :     };
      50             : 
      51             :     // Used by internal setters: to set header from network use SetHeaderFromNet
      52             :     MOZ_MUST_USE nsresult SetHeader(const nsACString &headerName,
      53             :                                     const nsACString &value,
      54             :                                     bool merge, HeaderVariety variety);
      55             :     MOZ_MUST_USE nsresult SetHeader(nsHttpAtom header, const nsACString &value,
      56             :                                     bool merge, HeaderVariety variety);
      57             :     MOZ_MUST_USE nsresult SetHeader(nsHttpAtom header,
      58             :                                     const nsACString &headerName,
      59             :                                     const nsACString &value,
      60             :                                     bool merge, HeaderVariety variety);
      61             : 
      62             :     // Used by internal setters to set an empty header
      63             :     MOZ_MUST_USE nsresult SetEmptyHeader(const nsACString &headerName,
      64             :                                          HeaderVariety variety);
      65             : 
      66             :     // Merges supported headers. For other duplicate values, determines if error
      67             :     // needs to be thrown or 1st value kept.
      68             :     // For the response header we keep the original headers as well.
      69             :     MOZ_MUST_USE nsresult SetHeaderFromNet(nsHttpAtom header,
      70             :                                            const nsACString &headerNameOriginal,
      71             :                                            const nsACString &value,
      72             :                                            bool response);
      73             : 
      74             :     MOZ_MUST_USE nsresult SetResponseHeaderFromCache(nsHttpAtom header,
      75             :                                                      const nsACString &headerNameOriginal,
      76             :                                                      const nsACString &value,
      77             :                                                      HeaderVariety variety);
      78             : 
      79             :     MOZ_MUST_USE nsresult GetHeader(nsHttpAtom header, nsACString &value) const;
      80             :     MOZ_MUST_USE nsresult GetOriginalHeader(nsHttpAtom aHeader,
      81             :                                             nsIHttpHeaderVisitor *aVisitor);
      82             :     void     ClearHeader(nsHttpAtom h);
      83             : 
      84             :     // Find the location of the given header value, or null if none exists.
      85          25 :     const char *FindHeaderValue(nsHttpAtom header, const char *value) const
      86             :     {
      87          25 :         return nsHttp::FindToken(PeekHeader(header), value,
      88          25 :                                  HTTP_HEADER_VALUE_SEPS);
      89             :     }
      90             : 
      91             :     // Determine if the given header value exists.
      92          25 :     bool HasHeaderValue(nsHttpAtom header, const char *value) const
      93             :     {
      94          25 :         return FindHeaderValue(header, value) != nullptr;
      95             :     }
      96             : 
      97             :     bool HasHeader(nsHttpAtom header) const;
      98             : 
      99             :     enum VisitorFilter
     100             :     {
     101             :         eFilterAll,
     102             :         eFilterSkipDefault,
     103             :         eFilterResponse,
     104             :         eFilterResponseOriginal
     105             :     };
     106             : 
     107             :     MOZ_MUST_USE nsresult VisitHeaders(nsIHttpHeaderVisitor *visitor,
     108             :                                        VisitorFilter filter = eFilterAll);
     109             : 
     110             :     // parse a header line, return the header atom and a pointer to the
     111             :     // header value (the substring of the header line -- do not free).
     112             :     static MOZ_MUST_USE nsresult ParseHeaderLine(const nsACString& line,
     113             :                                                  nsHttpAtom *header = nullptr,
     114             :                                                  nsACString *headerNameOriginal = nullptr,
     115             :                                                  nsACString *value = nullptr);
     116             : 
     117             :     void Flatten(nsACString &, bool pruneProxyHeaders, bool pruneTransients);
     118             :     void FlattenOriginalHeader(nsACString &);
     119             : 
     120           0 :     uint32_t Count() const { return mHeaders.Length(); }
     121             : 
     122             :     const char *PeekHeaderAt(uint32_t i, nsHttpAtom &header,
     123             :                              nsACString &headerNameOriginal) const;
     124             : 
     125             :     void Clear();
     126             : 
     127             :     // Must be copy-constructable and assignable
     128         447 :     struct nsEntry
     129             :     {
     130             :         nsHttpAtom header;
     131             :         nsCString headerNameOriginal;
     132             :         nsCString value;
     133             :         HeaderVariety variety = eVarietyUnknown;
     134             : 
     135             :         struct MatchHeader {
     136        1544 :           bool Equals(const nsEntry &aEntry, const nsHttpAtom &aHeader) const {
     137        1544 :             return aEntry.header == aHeader;
     138             :           }
     139             :         };
     140             : 
     141           0 :         bool operator==(const nsEntry& aOther) const
     142             :         {
     143           0 :             return header == aOther.header && value == aOther.value;
     144             :         }
     145             :     };
     146             : 
     147           0 :     bool operator==(const nsHttpHeaderArray& aOther) const
     148             :     {
     149           0 :         return mHeaders == aOther.mHeaders;
     150             :     }
     151             : 
     152             : private:
     153             :     // LookupEntry function will never return eVarietyResponseNetOriginal.
     154             :     // It will ignore original headers from the network.
     155             :     int32_t LookupEntry(nsHttpAtom header, const nsEntry **) const;
     156             :     int32_t LookupEntry(nsHttpAtom header, nsEntry **);
     157             :     MOZ_MUST_USE nsresult MergeHeader(nsHttpAtom header, nsEntry *entry,
     158             :                                       const nsACString &value,
     159             :                                       HeaderVariety variety);
     160             :     MOZ_MUST_USE nsresult SetHeader_internal(nsHttpAtom header,
     161             :                                              const nsACString &headeName,
     162             :                                              const nsACString &value,
     163             :                                              HeaderVariety variety);
     164             : 
     165             :     // Header cannot be merged: only one value possible
     166             :     bool    IsSingletonHeader(nsHttpAtom header);
     167             :     // Header cannot be merged, and subsequent values should be ignored
     168             :     bool    IsIgnoreMultipleHeader(nsHttpAtom header);
     169             :     // For some headers we want to track empty values to prevent them being
     170             :     // combined with non-empty ones as a CRLF attack vector
     171             :     bool    TrackEmptyHeader(nsHttpAtom header);
     172             : 
     173             :     // Subset of singleton headers: should never see multiple, different
     174             :     // instances of these, else something fishy may be going on (like CLRF
     175             :     // injection)
     176             :     bool    IsSuspectDuplicateHeader(nsHttpAtom header);
     177             : 
     178             :     // All members must be copy-constructable and assignable
     179             :     nsTArray<nsEntry> mHeaders;
     180             : 
     181             :     friend struct IPC::ParamTraits<nsHttpHeaderArray>;
     182             :     friend class nsHttpRequestHead;
     183             : };
     184             : 
     185             : 
     186             : //-----------------------------------------------------------------------------
     187             : // nsHttpHeaderArray <private>: inline functions
     188             : //-----------------------------------------------------------------------------
     189             : 
     190             : inline int32_t
     191         196 : nsHttpHeaderArray::LookupEntry(nsHttpAtom header, const nsEntry **entry) const
     192             : {
     193         196 :     uint32_t index = 0;
     194         534 :     while (index != UINT32_MAX) {
     195         196 :         index = mHeaders.IndexOf(header, index, nsEntry::MatchHeader());
     196         196 :         if (index != UINT32_MAX) {
     197          27 :             if ((&mHeaders[index])->variety != eVarietyResponseNetOriginal) {
     198          27 :                 *entry = &mHeaders[index];
     199          27 :                 return index;
     200             :             }
     201           0 :             index++;
     202             :         }
     203             :     }
     204             : 
     205         169 :     return index;
     206             : }
     207             : 
     208             : inline int32_t
     209         105 : nsHttpHeaderArray::LookupEntry(nsHttpAtom header, nsEntry **entry)
     210             : {
     211         105 :     uint32_t index = 0;
     212         299 :     while (index != UINT32_MAX) {
     213         105 :         index = mHeaders.IndexOf(header, index, nsEntry::MatchHeader());
     214         105 :         if (index != UINT32_MAX) {
     215           8 :             if ((&mHeaders[index])->variety != eVarietyResponseNetOriginal) {
     216           8 :                 *entry = &mHeaders[index];
     217           8 :                 return index;
     218             :             }
     219           0 :             index++;
     220             :         }
     221             :     }
     222          97 :     return index;
     223             : }
     224             : 
     225             : inline bool
     226           0 : nsHttpHeaderArray::IsSingletonHeader(nsHttpAtom header)
     227             : {
     228           0 :     return header == nsHttp::Content_Type                ||
     229           0 :            header == nsHttp::Content_Disposition         ||
     230           0 :            header == nsHttp::Content_Length              ||
     231           0 :            header == nsHttp::User_Agent                  ||
     232           0 :            header == nsHttp::Referer                     ||
     233           0 :            header == nsHttp::Host                        ||
     234           0 :            header == nsHttp::Authorization               ||
     235           0 :            header == nsHttp::Proxy_Authorization         ||
     236           0 :            header == nsHttp::If_Modified_Since           ||
     237           0 :            header == nsHttp::If_Unmodified_Since         ||
     238           0 :            header == nsHttp::From                        ||
     239           0 :            header == nsHttp::Location                    ||
     240           0 :            header == nsHttp::Max_Forwards                ||
     241             :            // Ignore-multiple-headers are singletons in the sense that they
     242             :            // shouldn't be merged.
     243           0 :            IsIgnoreMultipleHeader(header);
     244             : }
     245             : 
     246             : // These are headers for which, in the presence of multiple values, we only
     247             : // consider the first.
     248           8 : inline bool nsHttpHeaderArray::IsIgnoreMultipleHeader(nsHttpAtom header)
     249             : {
     250             :     // https://tools.ietf.org/html/rfc6797#section-8:
     251             :     //
     252             :     //     If a UA receives more than one STS header field in an HTTP
     253             :     //     response message over secure transport, then the UA MUST process
     254             :     //     only the first such header field.
     255           8 :     return header == nsHttp::Strict_Transport_Security;
     256             : }
     257             : 
     258             : inline bool
     259           0 : nsHttpHeaderArray::TrackEmptyHeader(nsHttpAtom header)
     260             : {
     261           0 :     return header == nsHttp::Content_Length ||
     262           0 :            header == nsHttp::Location ||
     263           0 :            header == nsHttp::Access_Control_Allow_Origin;
     264             : }
     265             : 
     266             : inline MOZ_MUST_USE nsresult
     267           0 : nsHttpHeaderArray::MergeHeader(nsHttpAtom header,
     268             :                                nsEntry *entry,
     269             :                                const nsACString &value,
     270             :                                nsHttpHeaderArray::HeaderVariety variety)
     271             : {
     272           0 :     if (value.IsEmpty())
     273           0 :         return NS_OK;   // merge of empty header = no-op
     274             : 
     275           0 :     nsCString newValue = entry->value;
     276           0 :     if (!newValue.IsEmpty()) {
     277             :         // Append the new value to the existing value
     278           0 :         if (header == nsHttp::Set_Cookie ||
     279           0 :             header == nsHttp::WWW_Authenticate ||
     280           0 :             header == nsHttp::Proxy_Authenticate)
     281             :         {
     282             :             // Special case these headers and use a newline delimiter to
     283             :             // delimit the values from one another as commas may appear
     284             :             // in the values of these headers contrary to what the spec says.
     285           0 :             newValue.Append('\n');
     286             :         } else {
     287             :             // Delimit each value from the others using a comma (per HTTP spec)
     288           0 :             newValue.AppendLiteral(", ");
     289             :         }
     290             :     }
     291             : 
     292           0 :     newValue.Append(value);
     293           0 :     if (entry->variety == eVarietyResponseNetOriginalAndResponse) {
     294           0 :         MOZ_ASSERT(variety == eVarietyResponse);
     295           0 :         entry->variety = eVarietyResponseNetOriginal;
     296             :         // Copy entry->headerNameOriginal because in SetHeader_internal we are going
     297             :         // to a new one and a realocation can happen.
     298           0 :         nsCString headerNameOriginal = entry->headerNameOriginal;
     299             :         nsresult rv = SetHeader_internal(header, headerNameOriginal,
     300           0 :                                          newValue, eVarietyResponse);
     301           0 :         if (NS_FAILED(rv)) {
     302           0 :             return rv;
     303             :         }
     304             :     } else {
     305           0 :         entry->value = newValue;
     306           0 :         entry->variety = variety;
     307             :     }
     308           0 :     return NS_OK;
     309             : }
     310             : 
     311             : inline bool
     312           0 : nsHttpHeaderArray::IsSuspectDuplicateHeader(nsHttpAtom header)
     313             : {
     314           0 :     bool retval =  header == nsHttp::Content_Length         ||
     315           0 :                      header == nsHttp::Content_Disposition    ||
     316           0 :                      header == nsHttp::Location;
     317             : 
     318           0 :     MOZ_ASSERT(!retval || IsSingletonHeader(header),
     319             :                "Only non-mergeable headers should be in this list\n");
     320             : 
     321           0 :     return retval;
     322             : }
     323             : 
     324             : } // namespace net
     325             : } // namespace mozilla
     326             : 
     327             : #endif

Generated by: LCOV version 1.13