nsHttpResponseHead.h (10448B)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef nsHttpResponseHead_h__ 7 #define nsHttpResponseHead_h__ 8 9 #include "nsHttpHeaderArray.h" 10 #include "nsHttp.h" 11 #include "nsString.h" 12 #include "mozilla/RecursiveMutex.h" 13 14 #ifdef Status 15 /* Xlib headers insist on this for some reason... Nuke it because 16 it'll override our member name */ 17 typedef Status __StatusTmp; 18 # undef Status 19 typedef __StatusTmp Status; 20 #endif 21 22 class nsIHttpHeaderVisitor; 23 24 // This needs to be forward declared here so we can include only this header 25 // without also including PHttpChannelParams.h 26 namespace IPC { 27 template <typename> 28 struct ParamTraits; 29 } // namespace IPC 30 31 namespace mozilla { 32 namespace net { 33 34 //----------------------------------------------------------------------------- 35 // nsHttpResponseHead represents the status line and headers from an HTTP 36 // response. 37 //----------------------------------------------------------------------------- 38 39 class nsHttpResponseHead { 40 public: 41 nsHttpResponseHead() = default; 42 43 nsHttpResponseHead(const nsHttpResponseHead& aOther); 44 nsHttpResponseHead(nsHttpResponseHead&& aOther); 45 nsHttpResponseHead& operator=(const nsHttpResponseHead& aOther); 46 47 void Enter() const MOZ_CAPABILITY_ACQUIRE(mRecursiveMutex) { 48 mRecursiveMutex.Lock(); 49 } 50 void Exit() const MOZ_CAPABILITY_RELEASE(mRecursiveMutex) { 51 mRecursiveMutex.Unlock(); 52 } 53 void AssertMutexOwned() const { mRecursiveMutex.AssertCurrentThreadIn(); } 54 55 HttpVersion Version() const; 56 uint16_t Status() const; 57 void StatusText(nsACString& aStatusText); 58 int64_t ContentLength(); 59 void ContentType(nsACString& aContentType) const; 60 void ContentCharset(nsACString& aContentCharset); 61 bool Public(); 62 bool Private(); 63 bool NoStore(); 64 bool NoCache(); 65 bool Immutable(); 66 /** 67 * Full length of the entity. For byte-range requests, this may be larger 68 * than ContentLength(), which will only represent the requested part of the 69 * entity. 70 */ 71 int64_t TotalEntitySize(); 72 73 [[nodiscard]] nsresult SetHeader(const nsACString& h, const nsACString& v, 74 bool m = false); 75 [[nodiscard]] nsresult SetHeaderOverride(const nsHttpAtom& h, 76 const nsACString& v); 77 [[nodiscard]] nsresult SetHeader(const nsHttpAtom& h, const nsACString& v, 78 bool m = false); 79 [[nodiscard]] nsresult GetHeader(const nsHttpAtom& h, nsACString& v) const; 80 void ClearHeader(const nsHttpAtom& h); 81 void ClearHeaders(); 82 bool HasHeaderValue(const nsHttpAtom& h, const char* v); 83 bool HasHeader(const nsHttpAtom& h) const; 84 85 void SetContentType(const nsACString& s); 86 void SetContentCharset(const nsACString& s); 87 void SetContentLength(int64_t); 88 89 // write out the response status line and headers as a single text block, 90 // optionally pruning out transient headers (ie. headers that only make 91 // sense the first time the response is handled). 92 // Both functions append to the string supplied string. 93 void Flatten(nsACString&, bool pruneTransients); 94 void FlattenNetworkOriginalHeaders(nsACString& buf); 95 96 // The next 2 functions parse flattened response head and original net 97 // headers. They are used when we are reading an entry from the cache. 98 // 99 // To keep proper order of the original headers we MUST call 100 // ParseCachedOriginalHeaders FIRST and then ParseCachedHead. 101 // 102 // block must be null terminated. 103 [[nodiscard]] nsresult ParseCachedHead(const char* block); 104 [[nodiscard]] nsresult ParseCachedOriginalHeaders(char* block); 105 106 // parse the status line. 107 nsresult ParseStatusLine(const nsACString& line); 108 109 // parse a header line. 110 [[nodiscard]] nsresult ParseHeaderLine(const nsACString& line); 111 112 // cache validation support methods 113 [[nodiscard]] nsresult ComputeFreshnessLifetime(uint32_t*); 114 [[nodiscard]] nsresult ComputeCurrentAge(uint32_t now, uint32_t requestTime, 115 uint32_t* result); 116 bool MustValidate(); 117 bool MustValidateIfExpired(); 118 119 // return true if the response contains a valid Cache-control: 120 // stale-while-revalidate and |now| is less than or equal |expiration + 121 // stale-while-revalidate|. Otherwise false. 122 bool StaleWhileRevalidate(uint32_t now, uint32_t expiration); 123 124 // returns true if the server appears to support byte range requests. 125 bool IsResumable(); 126 127 // returns true if the Expires header has a value in the past relative to the 128 // value of the Date header. 129 bool ExpiresInPast(); 130 131 // update headers... 132 void UpdateHeaders(nsHttpResponseHead* aOther); 133 134 // reset the response head to it's initial state 135 void Reset(); 136 137 [[nodiscard]] nsresult GetLastModifiedValue(uint32_t* result); 138 139 bool operator==(const nsHttpResponseHead& aOther) const; 140 141 // Using this function it is possible to itereate through all headers 142 // automatically under one lock. 143 [[nodiscard]] nsresult VisitHeaders(nsIHttpHeaderVisitor* visitor, 144 nsHttpHeaderArray::VisitorFilter filter); 145 [[nodiscard]] nsresult GetOriginalHeader(const nsHttpAtom& aHeader, 146 nsIHttpHeaderVisitor* aVisitor); 147 148 bool HasContentType() const; 149 bool HasContentCharset(); 150 bool GetContentTypeOptionsHeader(nsACString& aOutput); 151 152 private: 153 [[nodiscard]] nsresult SetHeader_locked(const nsHttpAtom& atom, 154 const nsACString& h, 155 const nsACString& v, bool m = false) 156 MOZ_REQUIRES(mRecursiveMutex); 157 void AssignDefaultStatusText() MOZ_REQUIRES(mRecursiveMutex); 158 void ParseVersion(const char*) MOZ_REQUIRES(mRecursiveMutex); 159 void ParseCacheControl(const char*) MOZ_REQUIRES(mRecursiveMutex); 160 void ParsePragma(const char*) MOZ_REQUIRES(mRecursiveMutex); 161 // Parses a content-length header-value as described in 162 // https://fetch.spec.whatwg.org/#content-length-header 163 nsresult ParseResponseContentLength(const nsACString& aHeaderStr) 164 MOZ_REQUIRES(mRecursiveMutex); 165 166 nsresult ParseStatusLine_locked(const nsACString& line) 167 MOZ_REQUIRES(mRecursiveMutex); 168 [[nodiscard]] nsresult ParseHeaderLine_locked(const nsACString& line, 169 bool originalFromNetHeaders) 170 MOZ_REQUIRES(mRecursiveMutex); 171 172 // these return failure if the header does not exist. 173 [[nodiscard]] nsresult ParseDateHeader(const nsHttpAtom& header, 174 uint32_t* result) const 175 MOZ_REQUIRES(mRecursiveMutex); 176 [[nodiscard]] nsresult GetAgeValue(uint32_t* result); 177 [[nodiscard]] nsresult GetMaxAgeValue(uint32_t* result); 178 [[nodiscard]] nsresult GetStaleWhileRevalidateValue(uint32_t* result); 179 [[nodiscard]] nsresult GetDateValue(uint32_t* result); 180 [[nodiscard]] nsresult GetExpiresValue(uint32_t* result); 181 182 bool ExpiresInPast_locked() const MOZ_REQUIRES(mRecursiveMutex); 183 [[nodiscard]] nsresult GetAgeValue_locked(uint32_t* result) const 184 MOZ_REQUIRES(mRecursiveMutex); 185 [[nodiscard]] nsresult GetExpiresValue_locked(uint32_t* result) const 186 MOZ_REQUIRES(mRecursiveMutex); 187 [[nodiscard]] nsresult GetMaxAgeValue_locked(uint32_t* result) const 188 MOZ_REQUIRES(mRecursiveMutex); 189 [[nodiscard]] nsresult GetStaleWhileRevalidateValue_locked( 190 uint32_t* result) const MOZ_REQUIRES(mRecursiveMutex); 191 192 [[nodiscard]] nsresult GetDateValue_locked(uint32_t* result) const 193 MOZ_REQUIRES(mRecursiveMutex) { 194 return ParseDateHeader(nsHttp::Date, result); 195 } 196 197 [[nodiscard]] nsresult GetLastModifiedValue_locked(uint32_t* result) const 198 MOZ_REQUIRES(mRecursiveMutex) { 199 return ParseDateHeader(nsHttp::Last_Modified, result); 200 } 201 202 bool NoCache_locked() const MOZ_REQUIRES(mRecursiveMutex) { 203 MOZ_ASSERT_IF(mCacheControlNoCache, mHasCacheControl); 204 // Normally we would ignore Pragma: no-cache if Cache-Control is set. 205 // But since all other browsers treat the existence of Pragma: no-cache 206 // as a signal to not-cache even when it conflicts with Cache-Control 207 // it is safer just to do the same. Previous behaviour where Pragma 208 // was ignored when Cache-Control was present resulted in several 209 // web-compat issues (Bug 1937766) 210 // However, the presence of cacheControl immutable indicates that 211 // pragma: no-cache is incorrectly added to the response. 212 return (mPragmaNoCache && !mCacheControlImmutable) || mCacheControlNoCache; 213 } 214 215 private: 216 // All members must be copy-constructable and assignable 217 nsHttpHeaderArray mHeaders MOZ_GUARDED_BY(mRecursiveMutex); 218 HttpVersion mVersion MOZ_GUARDED_BY(mRecursiveMutex){HttpVersion::v1_1}; 219 uint16_t mStatus MOZ_GUARDED_BY(mRecursiveMutex){200}; 220 nsCString mStatusText MOZ_GUARDED_BY(mRecursiveMutex); 221 int64_t mContentLength MOZ_GUARDED_BY(mRecursiveMutex){-1}; 222 nsCString mContentType MOZ_GUARDED_BY(mRecursiveMutex); 223 nsCString mContentCharset MOZ_GUARDED_BY(mRecursiveMutex); 224 bool mHasCacheControl MOZ_GUARDED_BY(mRecursiveMutex){false}; 225 bool mCacheControlPublic MOZ_GUARDED_BY(mRecursiveMutex){false}; 226 bool mCacheControlPrivate MOZ_GUARDED_BY(mRecursiveMutex){false}; 227 bool mCacheControlNoStore MOZ_GUARDED_BY(mRecursiveMutex){false}; 228 bool mCacheControlNoCache MOZ_GUARDED_BY(mRecursiveMutex){false}; 229 bool mCacheControlImmutable MOZ_GUARDED_BY(mRecursiveMutex){false}; 230 bool mCacheControlStaleWhileRevalidateSet MOZ_GUARDED_BY(mRecursiveMutex){ 231 false}; 232 uint32_t mCacheControlStaleWhileRevalidate MOZ_GUARDED_BY(mRecursiveMutex){0}; 233 bool mCacheControlMaxAgeSet MOZ_GUARDED_BY(mRecursiveMutex){false}; 234 uint32_t mCacheControlMaxAge MOZ_GUARDED_BY(mRecursiveMutex){0}; 235 bool mPragmaNoCache MOZ_GUARDED_BY(mRecursiveMutex){false}; 236 237 // We are using RecursiveMutex instead of a Mutex because VisitHeader 238 // function calls nsIHttpHeaderVisitor::VisitHeader while under lock. 239 mutable RecursiveMutex mRecursiveMutex{"nsHttpResponseHead.mRecursiveMutex"}; 240 // During VisitHeader we sould not allow call to SetHeader. 241 bool mInVisitHeaders MOZ_GUARDED_BY(mRecursiveMutex){false}; 242 243 friend struct IPC::ParamTraits<nsHttpResponseHead>; 244 }; 245 246 } // namespace net 247 } // namespace mozilla 248 249 #endif // nsHttpResponseHead_h__