1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
3
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 #ifndef mozilla_net_HttpBaseChannel_h
9 #define mozilla_net_HttpBaseChannel_h
10
11 #include <utility>
12
13 #include "mozilla/Atomics.h"
14 #include "mozilla/IntegerPrintfMacros.h"
15 #include "mozilla/Tuple.h"
16 #include "mozilla/dom/DOMTypes.h"
17 #include "mozilla/dom/ReferrerInfo.h"
18 #include "mozilla/net/ChannelEventQueue.h"
19 #include "mozilla/net/DNS.h"
20 #include "mozilla/net/NeckoCommon.h"
21 #include "mozilla/net/PrivateBrowsingChannel.h"
22 #include "nsCOMArray.h"
23 #include "nsCOMPtr.h"
24 #include "nsHashPropertyBag.h"
25 #include "nsHttp.h"
26 #include "nsHttpConnectionInfo.h"
27 #include "nsHttpHandler.h"
28 #include "nsHttpRequestHead.h"
29 #include "nsHttpResponseHead.h"
30 #include "nsIApplicationCache.h"
31 #include "nsIClassOfService.h"
32 #include "nsIClassifiedChannel.h"
33 #include "nsIConsoleReportCollector.h"
34 #include "nsIEncodedChannel.h"
35 #include "nsIForcePendingChannel.h"
36 #include "nsIFormPOSTActionChannel.h"
37 #include "nsIHttpChannel.h"
38 #include "nsIHttpChannelInternal.h"
39 #include "nsILoadInfo.h"
40 #include "nsIProgressEventSink.h"
41 #include "nsIResumableChannel.h"
42 #include "nsISecurityConsoleMessage.h"
43 #include "nsIStringEnumerator.h"
44 #include "nsISupportsPriority.h"
45 #include "nsIThrottledInputChannel.h"
46 #include "nsITimedChannel.h"
47 #include "nsITraceableChannel.h"
48 #include "nsIURI.h"
49 #include "nsIUploadChannel2.h"
50 #include "nsProxyInfo.h"
51 #include "nsStringEnumerator.h"
52 #include "nsTArray.h"
53 #include "nsThreadUtils.h"
54
55 #define HTTP_BASE_CHANNEL_IID \
56 { \
57 0x9d5cde03, 0xe6e9, 0x4612, { \
58 0xbf, 0xef, 0xbb, 0x66, 0xf3, 0xbb, 0x74, 0x46 \
59 } \
60 }
61
62 class nsISecurityConsoleMessage;
63 class nsIPrincipal;
64
65 namespace mozilla {
66
67 namespace dom {
68 class PerformanceStorage;
69 class ContentParent;
70 } // namespace dom
71
72 class LogCollector;
73
74 namespace net {
75 extern mozilla::LazyLogModule gHttpLog;
76
77 class PreferredAlternativeDataTypeParams;
78
79 enum CacheDisposition : uint8_t {
80 kCacheUnresolved = 0,
81 kCacheHit = 1,
82 kCacheHitViaReval = 2,
83 kCacheMissedViaReval = 3,
84 kCacheMissed = 4,
85 kCacheUnknown = 5
86 };
87
88 /*
89 * This class is a partial implementation of nsIHttpChannel. It contains code
90 * shared by nsHttpChannel and HttpChannelChild.
91 * - Note that this class has nothing to do with nsBaseChannel, which is an
92 * earlier effort at a base class for channels that somehow never made it all
93 * the way to the HTTP channel.
94 */
95 class HttpBaseChannel : public nsHashPropertyBag,
96 public nsIEncodedChannel,
97 public nsIHttpChannel,
98 public nsIHttpChannelInternal,
99 public nsIFormPOSTActionChannel,
100 public nsIUploadChannel2,
101 public nsISupportsPriority,
102 public nsIClassOfService,
103 public nsIResumableChannel,
104 public nsITraceableChannel,
105 public PrivateBrowsingChannel<HttpBaseChannel>,
106 public nsITimedChannel,
107 public nsIForcePendingChannel,
108 public nsIConsoleReportCollector,
109 public nsIThrottledInputChannel,
110 public nsIClassifiedChannel {
111 protected:
112 virtual ~HttpBaseChannel();
113
114 public:
115 NS_DECL_ISUPPORTS_INHERITED
116 NS_DECL_NSIUPLOADCHANNEL
117 NS_DECL_NSIFORMPOSTACTIONCHANNEL
118 NS_DECL_NSIUPLOADCHANNEL2
119 NS_DECL_NSITRACEABLECHANNEL
120 NS_DECL_NSITIMEDCHANNEL
121 NS_DECL_NSITHROTTLEDINPUTCHANNEL
122 NS_DECL_NSICLASSIFIEDCHANNEL
123
124 NS_DECLARE_STATIC_IID_ACCESSOR(HTTP_BASE_CHANNEL_IID)
125
126 HttpBaseChannel();
127
128 [[nodiscard]] virtual nsresult Init(nsIURI* aURI, uint32_t aCaps,
129 nsProxyInfo* aProxyInfo,
130 uint32_t aProxyResolveFlags,
131 nsIURI* aProxyURI, uint64_t aChannelId,
132 nsContentPolicyType aContentPolicyType);
133
134 // nsIRequest
135 NS_IMETHOD GetName(nsACString& aName) override;
136 NS_IMETHOD IsPending(bool* aIsPending) override;
137 NS_IMETHOD GetStatus(nsresult* aStatus) override;
138 NS_IMETHOD GetLoadGroup(nsILoadGroup** aLoadGroup) override;
139 NS_IMETHOD SetLoadGroup(nsILoadGroup* aLoadGroup) override;
140 NS_IMETHOD GetLoadFlags(nsLoadFlags* aLoadFlags) override;
141 NS_IMETHOD SetLoadFlags(nsLoadFlags aLoadFlags) override;
142 NS_IMETHOD GetTRRMode(nsIRequest::TRRMode* aTRRMode) override;
143 NS_IMETHOD SetTRRMode(nsIRequest::TRRMode aTRRMode) override;
144 NS_IMETHOD SetDocshellUserAgentOverride();
145
146 // nsIChannel
147 NS_IMETHOD GetOriginalURI(nsIURI** aOriginalURI) override;
148 NS_IMETHOD SetOriginalURI(nsIURI* aOriginalURI) override;
149 NS_IMETHOD GetURI(nsIURI** aURI) override;
150 NS_IMETHOD GetOwner(nsISupports** aOwner) override;
151 NS_IMETHOD SetOwner(nsISupports* aOwner) override;
152 NS_IMETHOD GetLoadInfo(nsILoadInfo** aLoadInfo) override;
153 NS_IMETHOD SetLoadInfo(nsILoadInfo* aLoadInfo) override;
154 NS_IMETHOD GetIsDocument(bool* aIsDocument) override;
155 NS_IMETHOD GetNotificationCallbacks(
156 nsIInterfaceRequestor** aCallbacks) override;
157 NS_IMETHOD SetNotificationCallbacks(
158 nsIInterfaceRequestor* aCallbacks) override;
159 NS_IMETHOD GetContentType(nsACString& aContentType) override;
160 NS_IMETHOD SetContentType(const nsACString& aContentType) override;
161 NS_IMETHOD GetContentCharset(nsACString& aContentCharset) override;
162 NS_IMETHOD SetContentCharset(const nsACString& aContentCharset) override;
163 NS_IMETHOD GetContentDisposition(uint32_t* aContentDisposition) override;
164 NS_IMETHOD SetContentDisposition(uint32_t aContentDisposition) override;
165 NS_IMETHOD GetContentDispositionFilename(
166 nsAString& aContentDispositionFilename) override;
167 NS_IMETHOD SetContentDispositionFilename(
168 const nsAString& aContentDispositionFilename) override;
169 NS_IMETHOD GetContentDispositionHeader(
170 nsACString& aContentDispositionHeader) override;
171 NS_IMETHOD GetContentLength(int64_t* aContentLength) override;
172 NS_IMETHOD SetContentLength(int64_t aContentLength) override;
173 NS_IMETHOD Open(nsIInputStream** aResult) override;
174 NS_IMETHOD GetBlockAuthPrompt(bool* aValue) override;
175 NS_IMETHOD SetBlockAuthPrompt(bool aValue) override;
176 NS_IMETHOD GetCanceled(bool* aCanceled) override;
177
178 // nsIEncodedChannel
179 NS_IMETHOD GetApplyConversion(bool* value) override;
180 NS_IMETHOD SetApplyConversion(bool value) override;
181 NS_IMETHOD GetContentEncodings(nsIUTF8StringEnumerator** aEncodings) override;
182 NS_IMETHOD DoApplyContentConversions(nsIStreamListener* aNextListener,
183 nsIStreamListener** aNewNextListener,
184 nsISupports* aCtxt) override;
185
186 // HttpBaseChannel::nsIHttpChannel
187 NS_IMETHOD GetRequestMethod(nsACString& aMethod) override;
188 NS_IMETHOD SetRequestMethod(const nsACString& aMethod) override;
189 NS_IMETHOD GetReferrerInfo(nsIReferrerInfo** aReferrerInfo) override;
190 NS_IMETHOD SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) override;
191 NS_IMETHOD SetReferrerInfoWithoutClone(
192 nsIReferrerInfo* aReferrerInfo) override;
193 NS_IMETHOD GetRequestHeader(const nsACString& aHeader,
194 nsACString& aValue) override;
195 NS_IMETHOD SetRequestHeader(const nsACString& aHeader,
196 const nsACString& aValue, bool aMerge) override;
197 NS_IMETHOD SetEmptyRequestHeader(const nsACString& aHeader) override;
198 NS_IMETHOD VisitRequestHeaders(nsIHttpHeaderVisitor* visitor) override;
199 NS_IMETHOD VisitNonDefaultRequestHeaders(
200 nsIHttpHeaderVisitor* visitor) override;
201 NS_IMETHOD GetResponseHeader(const nsACString& header,
202 nsACString& value) override;
203 NS_IMETHOD SetResponseHeader(const nsACString& header,
204 const nsACString& value, bool merge) override;
205 NS_IMETHOD VisitResponseHeaders(nsIHttpHeaderVisitor* visitor) override;
206 NS_IMETHOD GetOriginalResponseHeader(const nsACString& aHeader,
207 nsIHttpHeaderVisitor* aVisitor) override;
208 NS_IMETHOD VisitOriginalResponseHeaders(
209 nsIHttpHeaderVisitor* aVisitor) override;
210 NS_IMETHOD GetAllowPipelining(bool* value) override; // deprecated
211 NS_IMETHOD SetAllowPipelining(bool value) override; // deprecated
212 NS_IMETHOD GetAllowSTS(bool* value) override;
213 NS_IMETHOD SetAllowSTS(bool value) override;
214 NS_IMETHOD GetRedirectionLimit(uint32_t* value) override;
215 NS_IMETHOD SetRedirectionLimit(uint32_t value) override;
216 NS_IMETHOD IsNoStoreResponse(bool* value) override;
217 NS_IMETHOD IsNoCacheResponse(bool* value) override;
218 NS_IMETHOD IsPrivateResponse(bool* value) override;
219 NS_IMETHOD GetResponseStatus(uint32_t* aValue) override;
220 NS_IMETHOD GetResponseStatusText(nsACString& aValue) override;
221 NS_IMETHOD GetRequestSucceeded(bool* aValue) override;
222 NS_IMETHOD RedirectTo(nsIURI* newURI) override;
223 NS_IMETHOD UpgradeToSecure() override;
224 NS_IMETHOD GetRequestContextID(uint64_t* aRCID) override;
225 NS_IMETHOD GetTransferSize(uint64_t* aTransferSize) override;
226 NS_IMETHOD GetRequestSize(uint64_t* aRequestSize) override;
227 NS_IMETHOD GetDecodedBodySize(uint64_t* aDecodedBodySize) override;
228 NS_IMETHOD GetEncodedBodySize(uint64_t* aEncodedBodySize) override;
229 NS_IMETHOD SetRequestContextID(uint64_t aRCID) override;
230 NS_IMETHOD GetIsMainDocumentChannel(bool* aValue) override;
231 NS_IMETHOD SetIsMainDocumentChannel(bool aValue) override;
232 NS_IMETHOD GetProtocolVersion(nsACString& aProtocolVersion) override;
233 NS_IMETHOD GetChannelId(uint64_t* aChannelId) override;
234 NS_IMETHOD SetChannelId(uint64_t aChannelId) override;
235 NS_IMETHOD GetTopLevelContentWindowId(uint64_t* aContentWindowId) override;
236 NS_IMETHOD SetTopLevelContentWindowId(uint64_t aContentWindowId) override;
237 NS_IMETHOD GetTopLevelOuterContentWindowId(uint64_t* aWindowId) override;
238 NS_IMETHOD SetTopLevelOuterContentWindowId(uint64_t aWindowId) override;
239
240 NS_IMETHOD GetFlashPluginState(
241 nsIHttpChannel::FlashPluginState* aState) override;
242
243 using nsIClassifiedChannel::IsThirdPartyTrackingResource;
244
SetSource(UniqueProfilerBacktrace aSource)245 virtual void SetSource(UniqueProfilerBacktrace aSource) override {
246 mSource = std::move(aSource);
247 }
248
249 // nsIHttpChannelInternal
250 NS_IMETHOD GetDocumentURI(nsIURI** aDocumentURI) override;
251 NS_IMETHOD SetDocumentURI(nsIURI* aDocumentURI) override;
252 NS_IMETHOD GetRequestVersion(uint32_t* major, uint32_t* minor) override;
253 NS_IMETHOD GetResponseVersion(uint32_t* major, uint32_t* minor) override;
254 NS_IMETHOD SetCookie(const nsACString& aCookieHeader) override;
255 NS_IMETHOD GetThirdPartyFlags(uint32_t* aForce) override;
256 NS_IMETHOD SetThirdPartyFlags(uint32_t aForce) override;
257 NS_IMETHOD GetForceAllowThirdPartyCookie(bool* aForce) override;
258 NS_IMETHOD SetForceAllowThirdPartyCookie(bool aForce) override;
259 NS_IMETHOD GetChannelIsForDownload(bool* aChannelIsForDownload) override;
260 NS_IMETHOD SetChannelIsForDownload(bool aChannelIsForDownload) override;
261 NS_IMETHOD SetCacheKeysRedirectChain(nsTArray<nsCString>* cacheKeys) override;
262 NS_IMETHOD GetLocalAddress(nsACString& addr) override;
263 NS_IMETHOD GetLocalPort(int32_t* port) override;
264 NS_IMETHOD GetRemoteAddress(nsACString& addr) override;
265 NS_IMETHOD GetRemotePort(int32_t* port) override;
266 NS_IMETHOD GetOnlyConnect(bool* aOnlyConnect) override;
267 NS_IMETHOD SetConnectOnly() override;
268 NS_IMETHOD GetAllowSpdy(bool* aAllowSpdy) override;
269 NS_IMETHOD SetAllowSpdy(bool aAllowSpdy) override;
270 NS_IMETHOD GetAllowAltSvc(bool* aAllowAltSvc) override;
271 NS_IMETHOD SetAllowAltSvc(bool aAllowAltSvc) override;
272 NS_IMETHOD GetBeConservative(bool* aBeConservative) override;
273 NS_IMETHOD SetBeConservative(bool aBeConservative) override;
274 NS_IMETHOD GetIsTRRServiceChannel(bool* aTRR) override;
275 NS_IMETHOD SetIsTRRServiceChannel(bool aTRR) override;
276 NS_IMETHOD GetIsResolvedByTRR(bool* aResolvedByTRR) override;
277 NS_IMETHOD GetTlsFlags(uint32_t* aTlsFlags) override;
278 NS_IMETHOD SetTlsFlags(uint32_t aTlsFlags) override;
279 NS_IMETHOD GetApiRedirectToURI(nsIURI** aApiRedirectToURI) override;
280 [[nodiscard]] virtual nsresult AddSecurityMessage(
281 const nsAString& aMessageTag, const nsAString& aMessageCategory);
282 NS_IMETHOD TakeAllSecurityMessages(
283 nsCOMArray<nsISecurityConsoleMessage>& aMessages) override;
284 NS_IMETHOD GetResponseTimeoutEnabled(bool* aEnable) override;
285 NS_IMETHOD SetResponseTimeoutEnabled(bool aEnable) override;
286 NS_IMETHOD GetInitialRwin(uint32_t* aRwin) override;
287 NS_IMETHOD SetInitialRwin(uint32_t aRwin) override;
288 NS_IMETHOD ForcePending(bool aForcePending) override;
289 NS_IMETHOD GetLastModifiedTime(PRTime* lastModifiedTime) override;
290 NS_IMETHOD GetCorsIncludeCredentials(bool* aInclude) override;
291 NS_IMETHOD SetCorsIncludeCredentials(bool aInclude) override;
292 NS_IMETHOD GetCorsMode(uint32_t* aCorsMode) override;
293 NS_IMETHOD SetCorsMode(uint32_t aCorsMode) override;
294 NS_IMETHOD GetRedirectMode(uint32_t* aRedirectMode) override;
295 NS_IMETHOD SetRedirectMode(uint32_t aRedirectMode) override;
296 NS_IMETHOD GetFetchCacheMode(uint32_t* aFetchCacheMode) override;
297 NS_IMETHOD SetFetchCacheMode(uint32_t aFetchCacheMode) override;
298 NS_IMETHOD GetTopWindowURI(nsIURI** aTopWindowURI) override;
299 NS_IMETHOD SetTopWindowURIIfUnknown(nsIURI* aTopWindowURI) override;
300 NS_IMETHOD GetProxyURI(nsIURI** proxyURI) override;
301 virtual void SetCorsPreflightParameters(
302 const nsTArray<nsCString>& unsafeHeaders) override;
303 virtual void SetAltDataForChild(bool aIsForChild) override;
DisableAltDataCache()304 virtual void DisableAltDataCache() override { mDisableAltDataCache = true; };
305
306 NS_IMETHOD GetConnectionInfoHashKey(
307 nsACString& aConnectionInfoHashKey) override;
308 NS_IMETHOD GetIntegrityMetadata(nsAString& aIntegrityMetadata) override;
309 NS_IMETHOD SetIntegrityMetadata(const nsAString& aIntegrityMetadata) override;
310 NS_IMETHOD GetLastRedirectFlags(uint32_t* aValue) override;
311 NS_IMETHOD SetLastRedirectFlags(uint32_t aValue) override;
312 NS_IMETHOD GetNavigationStartTimeStamp(TimeStamp* aTimeStamp) override;
313 NS_IMETHOD SetNavigationStartTimeStamp(TimeStamp aTimeStamp) override;
314 NS_IMETHOD CancelByURLClassifier(nsresult aErrorCode) override;
315 virtual void SetIPv4Disabled(void) override;
316 virtual void SetIPv6Disabled(void) override;
317 NS_IMETHOD GetCrossOriginOpenerPolicy(
318 nsILoadInfo::CrossOriginOpenerPolicy* aCrossOriginOpenerPolicy) override;
319 NS_IMETHOD ComputeCrossOriginOpenerPolicy(
320 nsILoadInfo::CrossOriginOpenerPolicy aInitiatorPolicy,
321 nsILoadInfo::CrossOriginOpenerPolicy* aOutPolicy) override;
322 NS_IMETHOD HasCrossOriginOpenerPolicyMismatch(bool* aIsMismatch) override;
323 NS_IMETHOD GetResponseEmbedderPolicy(
324 nsILoadInfo::CrossOriginEmbedderPolicy* aOutPolicy) override;
GetHasNonEmptySandboxingFlag()325 virtual bool GetHasNonEmptySandboxingFlag() override {
326 return mHasNonEmptySandboxingFlag;
327 }
SetHasNonEmptySandboxingFlag(bool aHasNonEmptySandboxingFlag)328 virtual void SetHasNonEmptySandboxingFlag(
329 bool aHasNonEmptySandboxingFlag) override {
330 mHasNonEmptySandboxingFlag = aHasNonEmptySandboxingFlag;
331 }
332
CleanRedirectCacheChainIfNecessary()333 inline void CleanRedirectCacheChainIfNecessary() {
334 mRedirectedCachekeys = nullptr;
335 }
336 NS_IMETHOD HTTPUpgrade(const nsACString& aProtocolName,
337 nsIHttpUpgradeListener* aListener) override;
338 void DoDiagnosticAssertWhenOnStopNotCalledOnDestroy() override;
339
340 // nsISupportsPriority
341 NS_IMETHOD GetPriority(int32_t* value) override;
342 NS_IMETHOD AdjustPriority(int32_t delta) override;
343
344 // nsIClassOfService
GetClassFlags(uint32_t * outFlags)345 NS_IMETHOD GetClassFlags(uint32_t* outFlags) override {
346 *outFlags = mClassOfService;
347 return NS_OK;
348 }
349
350 // nsIResumableChannel
351 NS_IMETHOD GetEntityID(nsACString& aEntityID) override;
352
353 // nsIConsoleReportCollector
354 void AddConsoleReport(uint32_t aErrorFlags, const nsACString& aCategory,
355 nsContentUtils::PropertiesFile aPropertiesFile,
356 const nsACString& aSourceFileURI, uint32_t aLineNumber,
357 uint32_t aColumnNumber, const nsACString& aMessageName,
358 const nsTArray<nsString>& aStringParams) override;
359
360 void FlushReportsToConsole(
361 uint64_t aInnerWindowID,
362 ReportAction aAction = ReportAction::Forget) override;
363
364 void FlushReportsToConsoleForServiceWorkerScope(
365 const nsACString& aScope,
366 ReportAction aAction = ReportAction::Forget) override;
367
368 void FlushConsoleReports(
369 dom::Document* aDocument,
370 ReportAction aAction = ReportAction::Forget) override;
371
372 void FlushConsoleReports(
373 nsILoadGroup* aLoadGroup,
374 ReportAction aAction = ReportAction::Forget) override;
375
376 void FlushConsoleReports(nsIConsoleReportCollector* aCollector) override;
377
378 void StealConsoleReports(
379 nsTArray<net::ConsoleReportCollected>& aReports) override;
380
381 void ClearConsoleReports() override;
382
383 class nsContentEncodings : public nsStringEnumeratorBase {
384 public:
385 NS_DECL_ISUPPORTS
386 NS_DECL_NSIUTF8STRINGENUMERATOR
387
388 using nsStringEnumeratorBase::GetNext;
389
390 nsContentEncodings(nsIHttpChannel* aChannel, const char* aEncodingHeader);
391
392 private:
393 virtual ~nsContentEncodings() = default;
394
395 [[nodiscard]] nsresult PrepareForNext(void);
396
397 // We do not own the buffer. The channel owns it.
398 const char* mEncodingHeader;
399 const char* mCurStart; // points to start of current header
400 const char* mCurEnd; // points to end of current header
401
402 // Hold a ref to our channel so that it can't go away and take the
403 // header with it.
404 nsCOMPtr<nsIHttpChannel> mChannel;
405
406 bool mReady;
407 };
408
GetResponseHead()409 nsHttpResponseHead* GetResponseHead() const { return mResponseHead.get(); }
GetRequestHead()410 nsHttpRequestHead* GetRequestHead() { return &mRequestHead; }
GetResponseTrailers()411 nsHttpHeaderArray* GetResponseTrailers() const {
412 return mResponseTrailers.get();
413 }
414
GetSelfAddr()415 const NetAddr& GetSelfAddr() { return mSelfAddr; }
GetPeerAddr()416 const NetAddr& GetPeerAddr() { return mPeerAddr; }
417
418 [[nodiscard]] nsresult OverrideSecurityInfo(nsISupports* aSecurityInfo);
419
420 public: /* Necko internal use only... */
GetAltDataLength()421 int64_t GetAltDataLength() { return mAltDataLength; }
422 bool IsNavigation();
423
IsDeliveringAltData()424 bool IsDeliveringAltData() const { return mDeliveringAltData; }
425
426 static void PropagateReferenceIfNeeded(nsIURI* aURI,
427 nsCOMPtr<nsIURI>& aRedirectURI);
428
429 // Return whether upon a redirect code of httpStatus for method, the
430 // request method should be rewritten to GET.
431 static bool ShouldRewriteRedirectToGET(
432 uint32_t httpStatus, nsHttpRequestHead::ParsedMethodType method);
433
434 // Like nsIEncodedChannel::DoApplyConversions except context is set to
435 // mListenerContext.
436 [[nodiscard]] nsresult DoApplyContentConversions(
437 nsIStreamListener* aNextListener, nsIStreamListener** aNewNextListener);
438
439 // Callback on STS thread called by CopyComplete when NS_AsyncCopy()
440 // is finished. This function works as a proxy function to dispatch
441 // |EnsureUploadStreamIsCloneableComplete| to main thread.
442 virtual void OnCopyComplete(nsresult aStatus);
443
444 void AddClassificationFlags(uint32_t aFlags, bool aIsThirdParty);
445
446 void SetFlashPluginState(nsIHttpChannel::FlashPluginState aState);
447
ChannelId()448 const uint64_t& ChannelId() const { return mChannelId; }
449
InternalSetUploadStream(nsIInputStream * uploadStream)450 void InternalSetUploadStream(nsIInputStream* uploadStream) {
451 mUploadStream = uploadStream;
452 }
453
InternalSetUploadStreamLength(uint64_t aLength)454 void InternalSetUploadStreamLength(uint64_t aLength) {
455 mReqContentLength = aLength;
456 }
457
SetUploadStreamHasHeaders(bool hasHeaders)458 void SetUploadStreamHasHeaders(bool hasHeaders) {
459 mUploadStreamHasHeaders = hasHeaders;
460 }
461
462 virtual nsresult SetReferrerHeader(const nsACString& aReferrer,
463 bool aRespectBeforeConnect = true) {
464 if (aRespectBeforeConnect) {
465 ENSURE_CALLED_BEFORE_CONNECT();
466 }
467 return mRequestHead.SetHeader(nsHttp::Referer, aReferrer);
468 }
469
ClearReferrerHeader()470 nsresult ClearReferrerHeader() {
471 ENSURE_CALLED_BEFORE_CONNECT();
472 return mRequestHead.ClearHeader(nsHttp::Referer);
473 }
474
SetTopWindowURI(nsIURI * aTopWindowURI)475 void SetTopWindowURI(nsIURI* aTopWindowURI) { mTopWindowURI = aTopWindowURI; }
476
477 // Set referrerInfo and compute the referrer header if neccessary.
478 // Pass true for aSetOriginal if this is a new referrer and should
479 // overwrite the 'original' value, false if this is a mutation (like
480 // stripping the path).
481 nsresult SetReferrerInfoInternal(nsIReferrerInfo* aReferrerInfo, bool aClone,
482 bool aCompute, bool aRespectBeforeConnect);
483
484 struct ReplacementChannelConfig {
485 ReplacementChannelConfig() = default;
486 explicit ReplacementChannelConfig(
487 const dom::ReplacementChannelConfigInit& aInit);
488
489 uint32_t redirectFlags = 0;
490 uint32_t classOfService = 0;
491 Maybe<bool> privateBrowsing = Nothing();
492 Maybe<nsCString> method;
493 nsCOMPtr<nsIReferrerInfo> referrerInfo;
494 Maybe<dom::TimedChannelInfo> timedChannel;
495 nsCOMPtr<nsIInputStream> uploadStream;
496 uint64_t uploadStreamLength;
497 bool uploadStreamHasHeaders;
498 Maybe<nsCString> contentType;
499 Maybe<nsCString> contentLength;
500
501 dom::ReplacementChannelConfigInit Serialize(dom::ContentParent* aParent);
502 };
503
504 enum class ReplacementReason {
505 Redirect,
506 InternalRedirect,
507 DocumentChannel,
508 };
509
510 // Create a ReplacementChannelConfig object that can be used to duplicate the
511 // current channel.
512 ReplacementChannelConfig CloneReplacementChannelConfig(
513 bool aPreserveMethod, uint32_t aRedirectFlags, ReplacementReason aReason);
514
515 static void ConfigureReplacementChannel(nsIChannel*,
516 const ReplacementChannelConfig&,
517 ReplacementReason);
518
519 // Called before we create the redirect target channel.
520 already_AddRefed<nsILoadInfo> CloneLoadInfoForRedirect(
521 nsIURI* aNewURI, uint32_t aRedirectFlags);
522
523 // True if we've already applied content conversion to the data
524 // passed to mListener.
HasAppliedConversion()525 bool HasAppliedConversion() { return mHasAppliedConversion; }
526
527 protected:
528 nsresult GetTopWindowURI(nsIURI* aURIBeingLoaded, nsIURI** aTopWindowURI);
529
530 // Handle notifying listener, removing from loadgroup if request failed.
531 void DoNotifyListener();
532 virtual void DoNotifyListenerCleanup() = 0;
533
534 // drop reference to listener, its callbacks, and the progress sink
535 virtual void ReleaseListeners();
536
537 // Call AsyncAbort().
538 virtual void DoAsyncAbort(nsresult aStatus) = 0;
539
540 // This is fired only when a cookie is created due to the presence of
541 // Set-Cookie header in the response header of any network request.
542 // This notification will come only after the "http-on-examine-response"
543 // was fired.
544 void NotifySetCookie(const nsACString& aCookie);
545
546 mozilla::dom::PerformanceStorage* GetPerformanceStorage();
547 void MaybeReportTimingData();
548 nsIURI* GetReferringPage();
549 nsPIDOMWindowInner* GetInnerDOMWindow();
550
551 void AddCookiesToRequest();
552 [[nodiscard]] virtual nsresult SetupReplacementChannel(
553 nsIURI*, nsIChannel*, bool preserveMethod, uint32_t redirectFlags);
554
555 // bundle calling OMR observers and marking flag into one function
CallOnModifyRequestObservers()556 inline void CallOnModifyRequestObservers() {
557 gHttpHandler->OnModifyRequest(this);
558 MOZ_ASSERT(!mRequestObserversCalled);
559 mRequestObserversCalled = true;
560 }
561
562 // Helper function to simplify getting notification callbacks.
563 template <class T>
GetCallback(nsCOMPtr<T> & aResult)564 void GetCallback(nsCOMPtr<T>& aResult) {
565 NS_QueryNotificationCallbacks(mCallbacks, mLoadGroup,
566 NS_GET_TEMPLATE_IID(T),
567 getter_AddRefs(aResult));
568 }
569
570 // Redirect tracking
571 // Checks whether or not aURI and mOriginalURI share the same domain.
572 virtual bool SameOriginWithOriginalUri(nsIURI* aURI);
573
574 // GetPrincipal Returns the channel's URI principal.
575 nsIPrincipal* GetURIPrincipal();
576
577 [[nodiscard]] bool BypassServiceWorker() const;
578
579 // Returns true if this channel should intercept the network request and
580 // prepare for a possible synthesized response instead.
581 bool ShouldIntercept(nsIURI* aURI = nullptr);
582
583 // Callback on main thread when NS_AsyncCopy() is finished populating
584 // the new mUploadStream.
585 void EnsureUploadStreamIsCloneableComplete(nsresult aStatus);
586
587 #ifdef DEBUG
588 // Check if mPrivateBrowsingId matches between LoadInfo and LoadContext.
589 void AssertPrivateBrowsingId();
590 #endif
591
592 static void CallTypeSniffers(void* aClosure, const uint8_t* aData,
593 uint32_t aCount);
594
595 nsresult CheckRedirectLimit(uint32_t aRedirectFlags) const;
596
597 bool MaybeWaitForUploadStreamLength(nsIStreamListener* aListener,
598 nsISupports* aContext);
599
600 void MaybeFlushConsoleReports();
601
602 bool IsBrowsingContextDiscarded() const;
603
604 nsresult ProcessCrossOriginEmbedderPolicyHeader();
605
606 nsresult ProcessCrossOriginResourcePolicyHeader();
607
608 nsresult ComputeCrossOriginOpenerPolicyMismatch();
609
610 nsresult ValidateMIMEType();
611
612 friend class PrivateBrowsingChannel<HttpBaseChannel>;
613 friend class InterceptFailedOnStop;
614
615 protected:
616 // this section is for main-thread-only object
617 // all the references need to be proxy released on main thread.
618 nsCOMPtr<nsIURI> mURI;
619 nsCOMPtr<nsIURI> mOriginalURI;
620 nsCOMPtr<nsIURI> mDocumentURI;
621 nsCOMPtr<nsILoadGroup> mLoadGroup;
622 nsCOMPtr<nsILoadInfo> mLoadInfo;
623 nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
624 nsCOMPtr<nsIProgressEventSink> mProgressSink;
625 nsCOMPtr<nsIReferrerInfo> mReferrerInfo;
626 nsCOMPtr<nsIApplicationCache> mApplicationCache;
627 nsCOMPtr<nsIURI> mAPIRedirectToURI;
628 nsCOMPtr<nsIURI> mProxyURI;
629 nsCOMPtr<nsIPrincipal> mPrincipal;
630 nsCOMPtr<nsIURI> mTopWindowURI;
631 nsCOMPtr<nsIStreamListener> mListener;
632 // An instance of nsHTTPCompressConv
633 nsCOMPtr<nsIStreamListener> mCompressListener;
634 nsCOMPtr<nsIEventTarget> mCurrentThread;
635
636 private:
637 // Proxy release all members above on main thread.
638 void ReleaseMainThreadOnlyReferences();
639
640 void ExplicitSetUploadStreamLength(uint64_t aContentLength,
641 bool aStreamHasHeaders);
642
643 void MaybeResumeAsyncOpen();
644
645 protected:
646 nsCString mSpec; // ASCII encoded URL spec
647 nsCString mContentTypeHint;
648 nsCString mContentCharsetHint;
649 nsCString mUserSetCookieHeader;
650 // HTTP Upgrade Data
651 nsCString mUpgradeProtocol;
652 // Resumable channel specific data
653 nsCString mEntityID;
654 // The initiator type (for this resource) - how was the resource referenced in
655 // the HTML file.
656 nsString mInitiatorType;
657 // Holds the name of the preferred alt-data type for each contentType.
658 nsTArray<PreferredAlternativeDataTypeParams> mPreferredCachedAltDataTypes;
659 // Holds the name of the alternative data type the channel returned.
660 nsCString mAvailableCachedAltDataType;
661 nsString mIntegrityMetadata;
662
663 // Classified channel's matched information
664 nsCString mMatchedList;
665 nsCString mMatchedProvider;
666 nsCString mMatchedFullHash;
667
668 nsTArray<nsCString> mMatchedTrackingLists;
669 nsTArray<nsCString> mMatchedTrackingFullHashes;
670
671 nsCOMPtr<nsISupports> mOwner;
672
673 nsHttpRequestHead mRequestHead;
674 // Upload throttling.
675 nsCOMPtr<nsIInputChannelThrottleQueue> mThrottleQueue;
676 nsCOMPtr<nsIInputStream> mUploadStream;
677 nsCOMPtr<nsIRunnable> mUploadCloneableCallback;
678 UniquePtr<nsHttpResponseHead> mResponseHead;
679 UniquePtr<nsHttpHeaderArray> mResponseTrailers;
680 RefPtr<nsHttpConnectionInfo> mConnectionInfo;
681 nsCOMPtr<nsIProxyInfo> mProxyInfo;
682 nsCOMPtr<nsISupports> mSecurityInfo;
683 nsCOMPtr<nsIHttpUpgradeListener> mUpgradeProtocolCallback;
684 UniquePtr<nsString> mContentDispositionFilename;
685 nsCOMPtr<nsIConsoleReportCollector> mReportCollector;
686
687 RefPtr<nsHttpHandler> mHttpHandler; // keep gHttpHandler alive
688 UniquePtr<nsTArray<nsCString>> mRedirectedCachekeys;
689 nsCOMPtr<nsIRequestContext> mRequestContext;
690
691 NetAddr mSelfAddr;
692 NetAddr mPeerAddr;
693
694 nsTArray<std::pair<nsString, nsString>> mSecurityConsoleMessages;
695 nsTArray<nsCString> mUnsafeHeaders;
696
697 // A time value equal to the starting time of the fetch that initiates the
698 // redirect.
699 mozilla::TimeStamp mRedirectStartTimeStamp;
700 // A time value equal to the time immediately after receiving the last byte of
701 // the response of the last redirect.
702 mozilla::TimeStamp mRedirectEndTimeStamp;
703
704 PRTime mChannelCreationTime;
705 TimeStamp mChannelCreationTimestamp;
706 TimeStamp mAsyncOpenTime;
707 TimeStamp mCacheReadStart;
708 TimeStamp mCacheReadEnd;
709 TimeStamp mLaunchServiceWorkerStart;
710 TimeStamp mLaunchServiceWorkerEnd;
711 TimeStamp mDispatchFetchEventStart;
712 TimeStamp mDispatchFetchEventEnd;
713 TimeStamp mHandleFetchEventStart;
714 TimeStamp mHandleFetchEventEnd;
715 // copied from the transaction before we null out mTransaction
716 // so that the timing can still be queried from OnStopRequest
717 TimingStruct mTransactionTimings;
718
719 // Gets computed during ComputeCrossOriginOpenerPolicyMismatch so we have
720 // the channel's policy even if we don't know policy initiator.
721 nsILoadInfo::CrossOriginOpenerPolicy mComputedCrossOriginOpenerPolicy;
722
723 uint64_t mStartPos;
724 uint64_t mTransferSize;
725 uint64_t mRequestSize;
726 uint64_t mDecodedBodySize;
727 uint64_t mEncodedBodySize;
728 uint64_t mRequestContextID;
729 // ID of the top-level document's inner window this channel is being
730 // originated from.
731 uint64_t mContentWindowId;
732 uint64_t mTopLevelOuterContentWindowId;
733 int64_t mAltDataLength;
734 uint64_t mChannelId;
735 uint64_t mReqContentLength;
736
737 Atomic<nsresult, ReleaseAcquire> mStatus;
738
739 // Use Release-Acquire ordering to ensure the OMT ODA is ignored while channel
740 // is canceled on main thread.
741 Atomic<bool, ReleaseAcquire> mCanceled;
742 Atomic<uint32_t, ReleaseAcquire> mFirstPartyClassificationFlags;
743 Atomic<uint32_t, ReleaseAcquire> mThirdPartyClassificationFlags;
744 Atomic<uint32_t, ReleaseAcquire> mFlashPluginState;
745
746 UniqueProfilerBacktrace mSource;
747
748 uint32_t mLoadFlags;
749 uint32_t mCaps;
750 uint32_t mClassOfService;
751
752 uint32_t mUpgradeToSecure : 1;
753 uint32_t mApplyConversion : 1;
754 // Set to true if DoApplyContentConversions has been applied to
755 // our default mListener.
756 uint32_t mHasAppliedConversion : 1;
757 uint32_t mIsPending : 1;
758 uint32_t mWasOpened : 1;
759 // if 1 all "http-on-{opening|modify|etc}-request" observers have been called
760 uint32_t mRequestObserversCalled : 1;
761 uint32_t mResponseHeadersModified : 1;
762 uint32_t mAllowSTS : 1;
763 uint32_t mThirdPartyFlags : 3;
764 uint32_t mUploadStreamHasHeaders : 1;
765 uint32_t mInheritApplicationCache : 1;
766 uint32_t mChooseApplicationCache : 1;
767 uint32_t mLoadedFromApplicationCache : 1;
768 uint32_t mChannelIsForDownload : 1;
769 uint32_t mTracingEnabled : 1;
770 // True if timing collection is enabled
771 uint32_t mTimingEnabled : 1;
772 uint32_t mReportTiming : 1;
773 uint32_t mAllowSpdy : 1;
774 uint32_t mAllowAltSvc : 1;
775 // !!! This is also used by the URL classifier to exempt channels from
776 // classification. If this is changed or removed, make sure we also update
777 // NS_ShouldClassifyChannel accordingly !!!
778 uint32_t mBeConservative : 1;
779 // If the current channel is used to as a TRR connection.
780 uint32_t mIsTRRServiceChannel : 1;
781 // If the request was performed to a TRR resolved IP address.
782 // Will be false if loading the resource does not create a connection
783 // (for example when it's loaded from the cache).
784 uint32_t mResolvedByTRR : 1;
785 uint32_t mResponseTimeoutEnabled : 1;
786 // A flag that should be false only if a cross-domain redirect occurred
787 uint32_t mAllRedirectsSameOrigin : 1;
788
789 // Is 1 if no redirects have occured or if all redirects
790 // pass the Resource Timing timing-allow-check
791 uint32_t mAllRedirectsPassTimingAllowCheck : 1;
792
793 // True if this channel was intercepted and could receive a synthesized
794 // response.
795 uint32_t mResponseCouldBeSynthesized : 1;
796
797 uint32_t mBlockAuthPrompt : 1;
798
799 // If true, we behave as if the LOAD_FROM_CACHE flag has been set.
800 // Used to enforce that flag's behavior but not expose it externally.
801 uint32_t mAllowStaleCacheContent : 1;
802
803 // If true, we prefer the LOAD_FROM_CACHE flag over LOAD_BYPASS_CACHE or
804 // LOAD_BYPASS_LOCAL_CACHE.
805 uint32_t mPreferCacheLoadOverBypass : 1;
806
807 // True iff this request has been calculated in its request context as
808 // a non tail request. We must remove it again when this channel is done.
809 uint32_t mAddedAsNonTailRequest : 1;
810
811 // True if AsyncOpen() is called when the stream length is still unknown.
812 // AsyncOpen() will be retriggered when InputStreamLengthHelper execs the
813 // callback, passing the stream length value.
814 uint32_t mAsyncOpenWaitingForStreamLength : 1;
815
816 // Defaults to true. This is set to false when it is no longer possible
817 // to upgrade the request to a secure channel.
818 uint32_t mUpgradableToSecure : 1;
819
820 // True if the docshell's sandboxing flag set is not empty.
821 uint32_t mHasNonEmptySandboxingFlag : 1;
822
823 // An opaque flags for non-standard behavior of the TLS system.
824 // It is unlikely this will need to be set outside of telemetry studies
825 // relating to the TLS implementation.
826 uint32_t mTlsFlags;
827
828 // Current suspension depth for this channel object
829 uint32_t mSuspendCount;
830
831 // Per channel transport window override (0 means no override)
832 uint32_t mInitialRwin;
833
834 uint32_t mProxyResolveFlags;
835
836 uint32_t mContentDispositionHint;
837
838 uint32_t mCorsMode;
839 uint32_t mRedirectMode;
840
841 // If this channel was created as the result of a redirect, then this value
842 // will reflect the redirect flags passed to the SetupReplacementChannel()
843 // method.
844 uint32_t mLastRedirectFlags;
845
846 int16_t mPriority;
847 uint8_t mRedirectionLimit;
848
849 // Performance tracking
850 // Number of redirects that has occurred.
851 int8_t mRedirectCount;
852 // Number of internal redirects that has occurred.
853 int8_t mInternalRedirectCount;
854
855 bool mAsyncOpenTimeOverriden;
856 bool mForcePending;
857
858 // true if the channel is deliving alt-data.
859 bool mDeliveringAltData;
860
861 bool mCorsIncludeCredentials;
862
863 // These parameters are used to ensure that we do not call OnStartRequest and
864 // OnStopRequest more than once.
865 bool mOnStartRequestCalled;
866 bool mOnStopRequestCalled;
867
868 // Defaults to false. Is set to true at the begining of OnStartRequest.
869 // Used to ensure methods can't be called before OnStartRequest.
870 bool mAfterOnStartRequestBegun;
871
872 bool mRequireCORSPreflight;
873
874 // This flag will be true if the consumer is requesting alt-data AND the
875 // consumer is in the child process.
876 bool mAltDataForChild;
877
878 // This flag will be true if the consumer cannot process alt-data. This
879 // is used in the webextension StreamFilter handler. If true, we bypass
880 // using alt-data for the request.
881 bool mDisableAltDataCache;
882
883 bool mForceMainDocumentChannel;
884 // This is set true if the channel is waiting for the
885 // InputStreamLengthHelper::GetAsyncLength callback.
886 bool mPendingInputStreamLengthOperation;
887
888 bool EnsureRequestContextID();
889 bool EnsureRequestContext();
890
891 // Adds/removes this channel as a non-tailed request in its request context
892 // these helpers ensure we add it only once and remove it only when added
893 // via mAddedAsNonTailRequest member tracking.
894 void AddAsNonTailRequest();
895 void RemoveAsNonTailRequest();
896
897 void EnsureTopLevelOuterContentWindowId();
898
899 // True if this is a navigation to a page with a different cross origin
900 // opener policy ( see ComputeCrossOriginOpenerPolicyMismatch )
901 uint32_t mHasCrossOriginOpenerPolicyMismatch : 1;
902 };
903
NS_DEFINE_STATIC_IID_ACCESSOR(HttpBaseChannel,HTTP_BASE_CHANNEL_IID)904 NS_DEFINE_STATIC_IID_ACCESSOR(HttpBaseChannel, HTTP_BASE_CHANNEL_IID)
905
906 // Share some code while working around C++'s absurd inability to handle casting
907 // of member functions between base/derived types.
908 // - We want to store member function pointer to call at resume time, but one
909 // such function--HandleAsyncAbort--we want to share between the
910 // nsHttpChannel/HttpChannelChild. Can't define it in base class, because
911 // then we'd have to cast member function ptr between base/derived class
912 // types. Sigh...
913 template <class T>
914 class HttpAsyncAborter {
915 public:
916 explicit HttpAsyncAborter(T* derived)
917 : mThis(derived), mCallOnResume(nullptr) {}
918
919 // Aborts channel: calls OnStart/Stop with provided status, removes channel
920 // from loadGroup.
921 [[nodiscard]] nsresult AsyncAbort(nsresult status);
922
923 // Does most the actual work.
924 void HandleAsyncAbort();
925
926 // AsyncCall calls a member function asynchronously (via an event).
927 // retval isn't refcounted and is set only when event was successfully
928 // posted, the event is returned for the purpose of cancelling when needed
929 [[nodiscard]] virtual nsresult AsyncCall(
930 void (T::*funcPtr)(), nsRunnableMethod<T>** retval = nullptr);
931
932 private:
933 T* mThis;
934
935 protected:
936 // Function to be called at resume time
937 std::function<nsresult(T*)> mCallOnResume;
938 };
939
940 template <class T>
AsyncAbort(nsresult status)941 [[nodiscard]] nsresult HttpAsyncAborter<T>::AsyncAbort(nsresult status) {
942 MOZ_LOG(gHttpLog, LogLevel::Debug,
943 ("HttpAsyncAborter::AsyncAbort [this=%p status=%" PRIx32 "]\n", mThis,
944 static_cast<uint32_t>(status)));
945
946 mThis->mStatus = status;
947
948 // if this fails? Callers ignore our return value anyway....
949 return AsyncCall(&T::HandleAsyncAbort);
950 }
951
952 // Each subclass needs to define its own version of this (which just calls this
953 // base version), else we wind up casting base/derived member function ptrs
954 template <class T>
HandleAsyncAbort()955 inline void HttpAsyncAborter<T>::HandleAsyncAbort() {
956 MOZ_ASSERT(!mCallOnResume, "How did that happen?");
957
958 if (mThis->mSuspendCount) {
959 MOZ_LOG(
960 gHttpLog, LogLevel::Debug,
961 ("Waiting until resume to do async notification [this=%p]\n", mThis));
962 mCallOnResume = [](T* self) {
963 self->HandleAsyncAbort();
964 return NS_OK;
965 };
966 return;
967 }
968
969 mThis->DoNotifyListener();
970
971 // finally remove ourselves from the load group.
972 if (mThis->mLoadGroup)
973 mThis->mLoadGroup->RemoveRequest(mThis, nullptr, mThis->mStatus);
974 }
975
976 template <class T>
AsyncCall(void (T::* funcPtr)(),nsRunnableMethod<T> ** retval)977 nsresult HttpAsyncAborter<T>::AsyncCall(void (T::*funcPtr)(),
978 nsRunnableMethod<T>** retval) {
979 nsresult rv;
980
981 RefPtr<nsRunnableMethod<T>> event =
982 NewRunnableMethod("net::HttpAsyncAborter::AsyncCall", mThis, funcPtr);
983 rv = NS_DispatchToCurrentThread(event);
984 if (NS_SUCCEEDED(rv) && retval) {
985 *retval = event;
986 }
987
988 return rv;
989 }
990
991 class ProxyReleaseRunnable final : public mozilla::Runnable {
992 public:
ProxyReleaseRunnable(nsTArray<nsCOMPtr<nsISupports>> && aDoomed)993 explicit ProxyReleaseRunnable(nsTArray<nsCOMPtr<nsISupports>>&& aDoomed)
994 : Runnable("ProxyReleaseRunnable"), mDoomed(std::move(aDoomed)) {}
995
996 NS_IMETHOD
Run()997 Run() override {
998 mDoomed.Clear();
999 return NS_OK;
1000 }
1001
1002 private:
1003 virtual ~ProxyReleaseRunnable() = default;
1004
1005 nsTArray<nsCOMPtr<nsISupports>> mDoomed;
1006 };
1007
1008 } // namespace net
1009 } // namespace mozilla
1010
1011 #endif // mozilla_net_HttpBaseChannel_h
1012