123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833 |
- /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- // HttpLog.h should generally be included first
- #include "HttpLog.h"
- #include "mozilla/ipc/FileDescriptorSetParent.h"
- #include "mozilla/net/HttpChannelParent.h"
- #include "mozilla/dom/Element.h"
- #include "mozilla/dom/TabParent.h"
- #include "mozilla/net/NeckoParent.h"
- #include "mozilla/UniquePtr.h"
- #include "mozilla/Unused.h"
- #include "HttpChannelParentListener.h"
- #include "nsHttpHandler.h"
- #include "nsNetUtil.h"
- #include "nsISupportsPriority.h"
- #include "nsIAuthPromptProvider.h"
- #include "nsSerializationHelper.h"
- #include "nsISerializable.h"
- #include "nsIAssociatedContentSecurity.h"
- #include "nsIApplicationCacheService.h"
- #include "mozilla/ipc/InputStreamUtils.h"
- #include "mozilla/ipc/IPCStreamUtils.h"
- #include "mozilla/ipc/URIUtils.h"
- #include "SerializedLoadContext.h"
- #include "nsIAuthInformation.h"
- #include "nsIAuthPromptCallback.h"
- #include "nsIContentPolicy.h"
- #include "mozilla/ipc/BackgroundUtils.h"
- #include "nsICachingChannel.h"
- #include "mozilla/LoadInfo.h"
- #include "nsQueryObject.h"
- #include "mozilla/BasePrincipal.h"
- #include "nsCORSListenerProxy.h"
- #include "nsIIPCSerializableInputStream.h"
- #include "nsIPrompt.h"
- #include "nsIWindowWatcher.h"
- #include "nsIDocument.h"
- #include "nsStringStream.h"
- #include "nsIStorageStream.h"
- #include "nsStreamUtils.h"
- using mozilla::BasePrincipal;
- using namespace mozilla::dom;
- using namespace mozilla::ipc;
- namespace mozilla {
- namespace net {
- HttpChannelParent::HttpChannelParent(const PBrowserOrId& iframeEmbedding,
- nsILoadContext* aLoadContext,
- PBOverrideStatus aOverrideStatus)
- : mIPCClosed(false)
- , mStoredStatus(NS_OK)
- , mStoredProgress(0)
- , mStoredProgressMax(0)
- , mSentRedirect1Begin(false)
- , mSentRedirect1BeginFailed(false)
- , mReceivedRedirect2Verify(false)
- , mPBOverride(aOverrideStatus)
- , mLoadContext(aLoadContext)
- , mStatus(NS_OK)
- , mPendingDiversion(false)
- , mDivertingFromChild(false)
- , mDivertedOnStartRequest(false)
- , mSuspendedForDiversion(false)
- , mSuspendAfterSynthesizeResponse(false)
- , mWillSynthesizeResponse(false)
- , mNestedFrameId(0)
- {
- LOG(("Creating HttpChannelParent [this=%p]\n", this));
- // Ensure gHttpHandler is initialized: we need the atom table up and running.
- nsCOMPtr<nsIHttpProtocolHandler> dummyInitializer =
- do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http");
- MOZ_ASSERT(gHttpHandler);
- mHttpHandler = gHttpHandler;
- if (iframeEmbedding.type() == PBrowserOrId::TPBrowserParent) {
- mTabParent = static_cast<dom::TabParent*>(iframeEmbedding.get_PBrowserParent());
- } else {
- mNestedFrameId = iframeEmbedding.get_TabId();
- }
- mEventQ = new ChannelEventQueue(static_cast<nsIParentRedirectingChannel*>(this));
- }
- HttpChannelParent::~HttpChannelParent()
- {
- LOG(("Destroying HttpChannelParent [this=%p]\n", this));
- }
- void
- HttpChannelParent::ActorDestroy(ActorDestroyReason why)
- {
- // We may still have refcount>0 if nsHttpChannel hasn't called OnStopRequest
- // yet, but child process has crashed. We must not try to send any more msgs
- // to child, or IPDL will kill chrome process, too.
- mIPCClosed = true;
- // If this is an intercepted channel, we need to make sure that any resources are
- // cleaned up to avoid leaks.
- if (mParentListener) {
- mParentListener->ClearInterceptedChannel();
- }
- }
- bool
- HttpChannelParent::Init(const HttpChannelCreationArgs& aArgs)
- {
- LOG(("HttpChannelParent::Init [this=%p]\n", this));
- switch (aArgs.type()) {
- case HttpChannelCreationArgs::THttpChannelOpenArgs:
- {
- const HttpChannelOpenArgs& a = aArgs.get_HttpChannelOpenArgs();
- return DoAsyncOpen(a.uri(), a.original(), a.doc(), a.referrer(),
- a.referrerPolicy(), a.apiRedirectTo(), a.topWindowURI(),
- a.loadFlags(), a.requestHeaders(),
- a.requestMethod(), a.uploadStream(),
- a.uploadStreamHasHeaders(), a.priority(), a.classOfService(),
- a.redirectionLimit(), a.allowPipelining(), a.allowSTS(),
- a.thirdPartyFlags(), a.resumeAt(), a.startPos(),
- a.entityID(), a.chooseApplicationCache(),
- a.appCacheClientID(), a.allowSpdy(), a.allowAltSvc(), a.beConservative(),
- a.loadInfo(), a.synthesizedResponseHead(),
- a.synthesizedSecurityInfoSerialization(),
- a.cacheKey(), a.requestContextID(), a.preflightArgs(),
- a.initialRwin(), a.blockAuthPrompt(),
- a.suspendAfterSynthesizeResponse(),
- a.allowStaleCacheContent(), a.contentTypeHint(),
- a.channelId(), a.contentWindowId(), a.preferredAlternativeType(),
- a.launchServiceWorkerStart(),
- a.launchServiceWorkerEnd(),
- a.dispatchFetchEventStart(),
- a.dispatchFetchEventEnd(),
- a.handleFetchEventStart(),
- a.handleFetchEventEnd());
- }
- case HttpChannelCreationArgs::THttpChannelConnectArgs:
- {
- const HttpChannelConnectArgs& cArgs = aArgs.get_HttpChannelConnectArgs();
- return ConnectChannel(cArgs.registrarId(), cArgs.shouldIntercept());
- }
- default:
- NS_NOTREACHED("unknown open type");
- return false;
- }
- }
- //-----------------------------------------------------------------------------
- // HttpChannelParent::nsISupports
- //-----------------------------------------------------------------------------
- NS_IMPL_ADDREF(HttpChannelParent)
- NS_IMPL_RELEASE(HttpChannelParent)
- NS_INTERFACE_MAP_BEGIN(HttpChannelParent)
- NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
- NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
- NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
- NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
- NS_INTERFACE_MAP_ENTRY(nsIParentChannel)
- NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
- NS_INTERFACE_MAP_ENTRY(nsIParentRedirectingChannel)
- NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner)
- NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIParentRedirectingChannel)
- if (aIID.Equals(NS_GET_IID(HttpChannelParent))) {
- foundInterface = static_cast<nsIInterfaceRequestor*>(this);
- } else
- NS_INTERFACE_MAP_END
- //-----------------------------------------------------------------------------
- // HttpChannelParent::nsIInterfaceRequestor
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpChannelParent::GetInterface(const nsIID& aIID, void **result)
- {
- if (aIID.Equals(NS_GET_IID(nsIAuthPromptProvider)) ||
- aIID.Equals(NS_GET_IID(nsISecureBrowserUI))) {
- if (mTabParent) {
- return mTabParent->QueryInterface(aIID, result);
- }
- }
- // Only support nsIAuthPromptProvider in Content process
- if (XRE_IsParentProcess() &&
- aIID.Equals(NS_GET_IID(nsIAuthPromptProvider))) {
- *result = nullptr;
- return NS_OK;
- }
- // Only support nsILoadContext if child channel's callbacks did too
- if (aIID.Equals(NS_GET_IID(nsILoadContext)) && mLoadContext) {
- nsCOMPtr<nsILoadContext> copy = mLoadContext;
- copy.forget(result);
- return NS_OK;
- }
- if (mTabParent && aIID.Equals(NS_GET_IID(nsIPrompt))) {
- nsCOMPtr<Element> frameElement = mTabParent->GetOwnerElement();
- if (frameElement) {
- nsCOMPtr<nsPIDOMWindowOuter> win =frameElement->OwnerDoc()->GetWindow();
- NS_ENSURE_TRUE(win, NS_ERROR_UNEXPECTED);
- nsresult rv;
- nsCOMPtr<nsIWindowWatcher> wwatch =
- do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
- if (NS_WARN_IF(!NS_SUCCEEDED(rv))) {
- return rv;
- }
- nsCOMPtr<nsIPrompt> prompt;
- rv = wwatch->GetNewPrompter(win, getter_AddRefs(prompt));
- if (NS_WARN_IF(!NS_SUCCEEDED(rv))) {
- return rv;
- }
- prompt.forget(result);
- return NS_OK;
- }
- }
- return QueryInterface(aIID, result);
- }
- //-----------------------------------------------------------------------------
- // HttpChannelParent::PHttpChannelParent
- //-----------------------------------------------------------------------------
- void
- HttpChannelParent::InvokeAsyncOpen(nsresult rv)
- {
- if (NS_FAILED(rv)) {
- Unused << SendFailedAsyncOpen(rv);
- return;
- }
- nsCOMPtr<nsILoadInfo> loadInfo;
- rv = mChannel->GetLoadInfo(getter_AddRefs(loadInfo));
- if (NS_FAILED(rv)) {
- Unused << SendFailedAsyncOpen(rv);
- return;
- }
- if (loadInfo && loadInfo->GetEnforceSecurity()) {
- rv = mChannel->AsyncOpen2(mParentListener);
- }
- else {
- rv = mChannel->AsyncOpen(mParentListener, nullptr);
- }
- if (NS_FAILED(rv)) {
- Unused << SendFailedAsyncOpen(rv);
- }
- }
- namespace {
- class InvokeAsyncOpen : public Runnable
- {
- nsMainThreadPtrHandle<nsIInterfaceRequestor> mChannel;
- nsresult mStatus;
- public:
- InvokeAsyncOpen(const nsMainThreadPtrHandle<nsIInterfaceRequestor>& aChannel,
- nsresult aStatus)
- : mChannel(aChannel)
- , mStatus(aStatus)
- {
- }
- NS_IMETHOD Run()
- {
- RefPtr<HttpChannelParent> channel = do_QueryObject(mChannel.get());
- channel->InvokeAsyncOpen(mStatus);
- return NS_OK;
- }
- };
- struct UploadStreamClosure {
- nsMainThreadPtrHandle<nsIInterfaceRequestor> mChannel;
- explicit UploadStreamClosure(const nsMainThreadPtrHandle<nsIInterfaceRequestor>& aChannel)
- : mChannel(aChannel)
- {
- }
- };
- void
- UploadCopyComplete(void* aClosure, nsresult aStatus) {
- // Called on the Stream Transport Service thread by NS_AsyncCopy
- MOZ_ASSERT(!NS_IsMainThread());
- UniquePtr<UploadStreamClosure> closure(static_cast<UploadStreamClosure*>(aClosure));
- nsCOMPtr<nsIRunnable> event = new InvokeAsyncOpen(closure->mChannel, aStatus);
- NS_DispatchToMainThread(event);
- }
- } // anonymous namespace
- bool
- HttpChannelParent::DoAsyncOpen( const URIParams& aURI,
- const OptionalURIParams& aOriginalURI,
- const OptionalURIParams& aDocURI,
- const OptionalURIParams& aReferrerURI,
- const uint32_t& aReferrerPolicy,
- const OptionalURIParams& aAPIRedirectToURI,
- const OptionalURIParams& aTopWindowURI,
- const uint32_t& aLoadFlags,
- const RequestHeaderTuples& requestHeaders,
- const nsCString& requestMethod,
- const OptionalIPCStream& uploadStream,
- const bool& uploadStreamHasHeaders,
- const uint16_t& priority,
- const uint32_t& classOfService,
- const uint8_t& redirectionLimit,
- const bool& allowPipelining,
- const bool& allowSTS,
- const uint32_t& thirdPartyFlags,
- const bool& doResumeAt,
- const uint64_t& startPos,
- const nsCString& entityID,
- const bool& chooseApplicationCache,
- const nsCString& appCacheClientID,
- const bool& allowSpdy,
- const bool& allowAltSvc,
- const bool& beConservative,
- const OptionalLoadInfoArgs& aLoadInfoArgs,
- const OptionalHttpResponseHead& aSynthesizedResponseHead,
- const nsCString& aSecurityInfoSerialization,
- const uint32_t& aCacheKey,
- const nsCString& aRequestContextID,
- const OptionalCorsPreflightArgs& aCorsPreflightArgs,
- const uint32_t& aInitialRwin,
- const bool& aBlockAuthPrompt,
- const bool& aSuspendAfterSynthesizeResponse,
- const bool& aAllowStaleCacheContent,
- const nsCString& aContentTypeHint,
- const nsCString& aChannelId,
- const uint64_t& aContentWindowId,
- const nsCString& aPreferredAlternativeType,
- const TimeStamp& aLaunchServiceWorkerStart,
- const TimeStamp& aLaunchServiceWorkerEnd,
- const TimeStamp& aDispatchFetchEventStart,
- const TimeStamp& aDispatchFetchEventEnd,
- const TimeStamp& aHandleFetchEventStart,
- const TimeStamp& aHandleFetchEventEnd)
- {
- nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
- if (!uri) {
- // URIParams does MOZ_ASSERT if null, but we need to protect opt builds from
- // null deref here.
- return false;
- }
- nsCOMPtr<nsIURI> originalUri = DeserializeURI(aOriginalURI);
- nsCOMPtr<nsIURI> docUri = DeserializeURI(aDocURI);
- nsCOMPtr<nsIURI> referrerUri = DeserializeURI(aReferrerURI);
- nsCOMPtr<nsIURI> apiRedirectToUri = DeserializeURI(aAPIRedirectToURI);
- nsCOMPtr<nsIURI> topWindowUri = DeserializeURI(aTopWindowURI);
- LOG(("HttpChannelParent RecvAsyncOpen [this=%p uri=%s]\n",
- this, uri->GetSpecOrDefault().get()));
- nsresult rv;
- nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
- if (NS_FAILED(rv))
- return SendFailedAsyncOpen(rv);
- nsCOMPtr<nsILoadInfo> loadInfo;
- rv = mozilla::ipc::LoadInfoArgsToLoadInfo(aLoadInfoArgs,
- getter_AddRefs(loadInfo));
- if (NS_FAILED(rv)) {
- return SendFailedAsyncOpen(rv);
- }
- NeckoOriginAttributes attrs;
- rv = loadInfo->GetOriginAttributes(&attrs);
- if (NS_FAILED(rv)) {
- return SendFailedAsyncOpen(rv);
- }
- nsCOMPtr<nsIChannel> channel;
- rv = NS_NewChannelInternal(getter_AddRefs(channel), uri, loadInfo,
- nullptr, nullptr, aLoadFlags, ios);
- if (NS_FAILED(rv))
- return SendFailedAsyncOpen(rv);
- // This cast is safe since this is AsyncOpen specific to http. channel
- // is ensured to be nsHttpChannel.
- mChannel = static_cast<nsHttpChannel *>(channel.get());
- // Set the channelId allocated in child to the parent instance
- mChannel->SetChannelId(aChannelId);
- mChannel->SetTopLevelContentWindowId(aContentWindowId);
- mChannel->SetWarningReporter(this);
- mChannel->SetTimingEnabled(true);
- if (mPBOverride != kPBOverride_Unset) {
- mChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
- }
- if (doResumeAt)
- mChannel->ResumeAt(startPos, entityID);
- if (originalUri)
- mChannel->SetOriginalURI(originalUri);
- if (docUri)
- mChannel->SetDocumentURI(docUri);
- if (referrerUri)
- mChannel->SetReferrerWithPolicyInternal(referrerUri, aReferrerPolicy);
- if (apiRedirectToUri)
- mChannel->RedirectTo(apiRedirectToUri);
- if (topWindowUri)
- mChannel->SetTopWindowURI(topWindowUri);
- if (aLoadFlags != nsIRequest::LOAD_NORMAL)
- mChannel->SetLoadFlags(aLoadFlags);
- for (uint32_t i = 0; i < requestHeaders.Length(); i++) {
- if (requestHeaders[i].mEmpty) {
- mChannel->SetEmptyRequestHeader(requestHeaders[i].mHeader);
- } else {
- mChannel->SetRequestHeader(requestHeaders[i].mHeader,
- requestHeaders[i].mValue,
- requestHeaders[i].mMerge);
- }
- }
- mParentListener = new HttpChannelParentListener(this);
- mChannel->SetNotificationCallbacks(mParentListener);
- mChannel->SetRequestMethod(nsDependentCString(requestMethod.get()));
- if (aCorsPreflightArgs.type() == OptionalCorsPreflightArgs::TCorsPreflightArgs) {
- const CorsPreflightArgs& args = aCorsPreflightArgs.get_CorsPreflightArgs();
- mChannel->SetCorsPreflightParameters(args.unsafeHeaders());
- }
- bool delayAsyncOpen = false;
- nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(uploadStream);
- if (stream) {
- // FIXME: The fast path of using the existing stream currently only applies to streams
- // that have had their entire contents serialized from the child at this point.
- // Once bug 1294446 and bug 1294450 are fixed it is worth revisiting this heuristic.
- nsCOMPtr<nsIIPCSerializableInputStream> completeStream = do_QueryInterface(stream);
- if (!completeStream) {
- delayAsyncOpen = true;
- // buffer size matches PSendStream transfer size.
- const uint32_t kBufferSize = 32768;
- nsCOMPtr<nsIStorageStream> storageStream;
- nsresult rv = NS_NewStorageStream(kBufferSize, UINT32_MAX,
- getter_AddRefs(storageStream));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return SendFailedAsyncOpen(rv);
- }
- nsCOMPtr<nsIInputStream> newUploadStream;
- rv = storageStream->NewInputStream(0, getter_AddRefs(newUploadStream));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return SendFailedAsyncOpen(rv);
- }
- nsCOMPtr<nsIOutputStream> sink;
- rv = storageStream->GetOutputStream(0, getter_AddRefs(sink));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return SendFailedAsyncOpen(rv);
- }
- nsCOMPtr<nsIEventTarget> target =
- do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
- if (NS_FAILED(rv) || !target) {
- return SendFailedAsyncOpen(rv);
- }
- nsCOMPtr<nsIInterfaceRequestor> iir = static_cast<nsIInterfaceRequestor*>(this);
- nsMainThreadPtrHandle<nsIInterfaceRequestor> handle =
- nsMainThreadPtrHandle<nsIInterfaceRequestor>(
- new nsMainThreadPtrHolder<nsIInterfaceRequestor>(iir));
- UniquePtr<UploadStreamClosure> closure(new UploadStreamClosure(handle));
- // Accumulate the stream contents as the child sends it. We will continue with
- // the AsyncOpen process once the full stream has been received.
- rv = NS_AsyncCopy(stream, sink, target, NS_ASYNCCOPY_VIA_READSEGMENTS,
- kBufferSize, // copy segment size
- UploadCopyComplete, closure.release());
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return SendFailedAsyncOpen(rv);
- }
- mChannel->InternalSetUploadStream(newUploadStream);
- } else {
- mChannel->InternalSetUploadStream(stream);
- }
- mChannel->SetUploadStreamHasHeaders(uploadStreamHasHeaders);
- }
- if (aSynthesizedResponseHead.type() == OptionalHttpResponseHead::TnsHttpResponseHead) {
- mParentListener->SetupInterception(aSynthesizedResponseHead.get_nsHttpResponseHead());
- mWillSynthesizeResponse = true;
- mChannel->SetCouldBeSynthesized();
- if (!aSecurityInfoSerialization.IsEmpty()) {
- nsCOMPtr<nsISupports> secInfo;
- NS_DeserializeObject(aSecurityInfoSerialization, getter_AddRefs(secInfo));
- mChannel->OverrideSecurityInfo(secInfo);
- }
- } else {
- nsLoadFlags newLoadFlags;
- mChannel->GetLoadFlags(&newLoadFlags);
- newLoadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
- mChannel->SetLoadFlags(newLoadFlags);
- }
- nsCOMPtr<nsISupportsPRUint32> cacheKey =
- do_CreateInstance(NS_SUPPORTS_PRUINT32_CONTRACTID, &rv);
- if (NS_FAILED(rv)) {
- return SendFailedAsyncOpen(rv);
- }
- rv = cacheKey->SetData(aCacheKey);
- if (NS_FAILED(rv)) {
- return SendFailedAsyncOpen(rv);
- }
- mChannel->SetCacheKey(cacheKey);
- mChannel->PreferAlternativeDataType(aPreferredAlternativeType);
- mChannel->SetAllowStaleCacheContent(aAllowStaleCacheContent);
- mChannel->SetContentType(aContentTypeHint);
- if (priority != nsISupportsPriority::PRIORITY_NORMAL) {
- mChannel->SetPriority(priority);
- }
- if (classOfService) {
- mChannel->SetClassFlags(classOfService);
- }
- mChannel->SetRedirectionLimit(redirectionLimit);
- mChannel->SetAllowPipelining(allowPipelining);
- mChannel->SetAllowSTS(allowSTS);
- mChannel->SetThirdPartyFlags(thirdPartyFlags);
- mChannel->SetAllowSpdy(allowSpdy);
- mChannel->SetAllowAltSvc(allowAltSvc);
- mChannel->SetBeConservative(beConservative);
- mChannel->SetInitialRwin(aInitialRwin);
- mChannel->SetBlockAuthPrompt(aBlockAuthPrompt);
- mChannel->SetLaunchServiceWorkerStart(aLaunchServiceWorkerStart);
- mChannel->SetLaunchServiceWorkerEnd(aLaunchServiceWorkerEnd);
- mChannel->SetDispatchFetchEventStart(aDispatchFetchEventStart);
- mChannel->SetDispatchFetchEventEnd(aDispatchFetchEventEnd);
- mChannel->SetHandleFetchEventStart(aHandleFetchEventStart);
- mChannel->SetHandleFetchEventEnd(aHandleFetchEventEnd);
- nsCOMPtr<nsIApplicationCacheChannel> appCacheChan =
- do_QueryObject(mChannel);
- nsCOMPtr<nsIApplicationCacheService> appCacheService =
- do_GetService(NS_APPLICATIONCACHESERVICE_CONTRACTID);
- bool setChooseApplicationCache = chooseApplicationCache;
- if (appCacheChan && appCacheService) {
- // We might potentially want to drop this flag (that is TRUE by default)
- // after we successfully associate the channel with an application cache
- // reported by the channel child. Dropping it here may be too early.
- appCacheChan->SetInheritApplicationCache(false);
- if (!appCacheClientID.IsEmpty()) {
- nsCOMPtr<nsIApplicationCache> appCache;
- rv = appCacheService->GetApplicationCache(appCacheClientID,
- getter_AddRefs(appCache));
- if (NS_SUCCEEDED(rv)) {
- appCacheChan->SetApplicationCache(appCache);
- setChooseApplicationCache = false;
- }
- }
- if (setChooseApplicationCache) {
- NeckoOriginAttributes neckoAttrs;
- NS_GetOriginAttributes(mChannel, neckoAttrs);
- PrincipalOriginAttributes attrs;
- attrs.InheritFromNecko(neckoAttrs);
- nsCOMPtr<nsIPrincipal> principal =
- BasePrincipal::CreateCodebasePrincipal(uri, attrs);
- bool chooseAppCache = false;
- // This works because we've already called SetNotificationCallbacks and
- // done mPBOverride logic by this point.
- chooseAppCache = NS_ShouldCheckAppCache(principal, NS_UsePrivateBrowsing(mChannel));
- appCacheChan->SetChooseApplicationCache(chooseAppCache);
- }
- }
- nsID requestContextID;
- requestContextID.Parse(aRequestContextID.BeginReading());
- mChannel->SetRequestContextID(requestContextID);
- mSuspendAfterSynthesizeResponse = aSuspendAfterSynthesizeResponse;
- if (!delayAsyncOpen) {
- InvokeAsyncOpen(NS_OK);
- }
- return true;
- }
- bool
- HttpChannelParent::ConnectChannel(const uint32_t& registrarId, const bool& shouldIntercept)
- {
- nsresult rv;
- LOG(("HttpChannelParent::ConnectChannel: Looking for a registered channel "
- "[this=%p, id=%lu]\n", this, registrarId));
- nsCOMPtr<nsIChannel> channel;
- rv = NS_LinkRedirectChannels(registrarId, this, getter_AddRefs(channel));
- if (NS_FAILED(rv)) {
- NS_ERROR("Could not find the http channel to connect its IPC parent");
- // This makes the channel delete itself safely. It's the only thing
- // we can do now, since this parent channel cannot be used and there is
- // no other way to tell the child side there were something wrong.
- Delete();
- return true;
- }
- // It's safe to cast here since the found parent-side real channel is ensured
- // to be http (nsHttpChannel). ConnectChannel called from HttpChannelParent::Init
- // can only be called for http channels. It's bound by ipdl.
- mChannel = static_cast<nsHttpChannel*>(channel.get());
- LOG((" found channel %p, rv=%08x", mChannel.get(), rv));
- nsCOMPtr<nsINetworkInterceptController> controller;
- NS_QueryNotificationCallbacks(channel, controller);
- RefPtr<HttpChannelParentListener> parentListener = do_QueryObject(controller);
- MOZ_ASSERT(parentListener);
- parentListener->SetupInterceptionAfterRedirect(shouldIntercept);
- if (mPBOverride != kPBOverride_Unset) {
- // redirected-to channel may not support PB
- nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryObject(mChannel);
- if (pbChannel) {
- pbChannel->SetPrivate(mPBOverride == kPBOverride_Private ? true : false);
- }
- }
- return true;
- }
- bool
- HttpChannelParent::RecvSetPriority(const uint16_t& priority)
- {
- LOG(("HttpChannelParent::RecvSetPriority [this=%p, priority=%u]\n",
- this, priority));
- if (mChannel) {
- mChannel->SetPriority(priority);
- }
- nsCOMPtr<nsISupportsPriority> priorityRedirectChannel =
- do_QueryInterface(mRedirectChannel);
- if (priorityRedirectChannel)
- priorityRedirectChannel->SetPriority(priority);
- return true;
- }
- bool
- HttpChannelParent::RecvSetClassOfService(const uint32_t& cos)
- {
- if (mChannel) {
- mChannel->SetClassFlags(cos);
- }
- return true;
- }
- bool
- HttpChannelParent::RecvSuspend()
- {
- LOG(("HttpChannelParent::RecvSuspend [this=%p]\n", this));
- if (mChannel) {
- mChannel->Suspend();
- }
- return true;
- }
- bool
- HttpChannelParent::RecvResume()
- {
- LOG(("HttpChannelParent::RecvResume [this=%p]\n", this));
- if (mChannel) {
- mChannel->Resume();
- }
- return true;
- }
- bool
- HttpChannelParent::RecvCancel(const nsresult& status)
- {
- LOG(("HttpChannelParent::RecvCancel [this=%p]\n", this));
- // May receive cancel before channel has been constructed!
- if (mChannel) {
- mChannel->Cancel(status);
- }
- return true;
- }
- bool
- HttpChannelParent::RecvSetCacheTokenCachedCharset(const nsCString& charset)
- {
- if (mCacheEntry)
- mCacheEntry->SetMetaDataElement("charset", charset.get());
- return true;
- }
- bool
- HttpChannelParent::RecvUpdateAssociatedContentSecurity(const int32_t& broken,
- const int32_t& no)
- {
- if (mAssociatedContentSecurity) {
- mAssociatedContentSecurity->SetCountSubRequestsBrokenSecurity(broken);
- mAssociatedContentSecurity->SetCountSubRequestsNoSecurity(no);
- }
- return true;
- }
- bool
- HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
- const RequestHeaderTuples& changedHeaders,
- const uint32_t& loadFlags,
- const OptionalURIParams& aAPIRedirectURI,
- const OptionalCorsPreflightArgs& aCorsPreflightArgs,
- const bool& aChooseAppcache)
- {
- LOG(("HttpChannelParent::RecvRedirect2Verify [this=%p result=%x]\n",
- this, result));
- if (NS_SUCCEEDED(result)) {
- nsCOMPtr<nsIHttpChannel> newHttpChannel =
- do_QueryInterface(mRedirectChannel);
- if (newHttpChannel) {
- nsCOMPtr<nsIURI> apiRedirectUri = DeserializeURI(aAPIRedirectURI);
- if (apiRedirectUri)
- newHttpChannel->RedirectTo(apiRedirectUri);
- for (uint32_t i = 0; i < changedHeaders.Length(); i++) {
- if (changedHeaders[i].mEmpty) {
- newHttpChannel->SetEmptyRequestHeader(changedHeaders[i].mHeader);
- } else {
- newHttpChannel->SetRequestHeader(changedHeaders[i].mHeader,
- changedHeaders[i].mValue,
- changedHeaders[i].mMerge);
- }
- }
- // A successfully redirected channel must have the LOAD_REPLACE flag.
- MOZ_ASSERT(loadFlags & nsIChannel::LOAD_REPLACE);
- if (loadFlags & nsIChannel::LOAD_REPLACE) {
- newHttpChannel->SetLoadFlags(loadFlags);
- }
- if (aCorsPreflightArgs.type() == OptionalCorsPreflightArgs::TCorsPreflightArgs) {
- nsCOMPtr<nsIHttpChannelInternal> newInternalChannel =
- do_QueryInterface(newHttpChannel);
- MOZ_RELEASE_ASSERT(newInternalChannel);
- const CorsPreflightArgs& args = aCorsPreflightArgs.get_CorsPreflightArgs();
- newInternalChannel->SetCorsPreflightParameters(args.unsafeHeaders());
- }
- nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
- do_QueryInterface(newHttpChannel);
- if (appCacheChannel) {
- appCacheChannel->SetChooseApplicationCache(aChooseAppcache);
- }
- }
- }
- if (!mRedirectCallback) {
- // This should according the logic never happen, log the situation.
- if (mReceivedRedirect2Verify)
- LOG(("RecvRedirect2Verify[%p]: Duplicate fire", this));
- if (mSentRedirect1BeginFailed)
- LOG(("RecvRedirect2Verify[%p]: Send to child failed", this));
- if (mSentRedirect1Begin && NS_FAILED(result))
- LOG(("RecvRedirect2Verify[%p]: Redirect failed", this));
- if (mSentRedirect1Begin && NS_SUCCEEDED(result))
- LOG(("RecvRedirect2Verify[%p]: Redirect succeeded", this));
- if (!mRedirectChannel)
- LOG(("RecvRedirect2Verify[%p]: Missing redirect channel", this));
- NS_ERROR("Unexpcted call to HttpChannelParent::RecvRedirect2Verify, "
- "mRedirectCallback null");
- }
- mReceivedRedirect2Verify = true;
- if (mRedirectCallback) {
- LOG(("HttpChannelParent::RecvRedirect2Verify call OnRedirectVerifyCallback"
- " [this=%p result=%x, mRedirectCallback=%p]\n",
- this, result, mRedirectCallback.get()));
- mRedirectCallback->OnRedirectVerifyCallback(result);
- mRedirectCallback = nullptr;
- }
- return true;
- }
- bool
- HttpChannelParent::RecvDocumentChannelCleanup()
- {
- // From now on only using mAssociatedContentSecurity. Free everything else.
- mChannel = nullptr; // Reclaim some memory sooner.
- mCacheEntry = nullptr; // Else we'll block other channels reading same URI
- return true;
- }
- bool
- HttpChannelParent::RecvMarkOfflineCacheEntryAsForeign()
- {
- if (mOfflineForeignMarker) {
- mOfflineForeignMarker->MarkAsForeign();
- mOfflineForeignMarker = 0;
- }
- return true;
- }
- class DivertDataAvailableEvent : public ChannelEvent
- {
- public:
- DivertDataAvailableEvent(HttpChannelParent* aParent,
- const nsCString& data,
- const uint64_t& offset,
- const uint32_t& count)
- : mParent(aParent)
- , mData(data)
- , mOffset(offset)
- , mCount(count)
- {
- }
- void Run()
- {
- mParent->DivertOnDataAvailable(mData, mOffset, mCount);
- }
- private:
- HttpChannelParent* mParent;
- nsCString mData;
- uint64_t mOffset;
- uint32_t mCount;
- };
- bool
- HttpChannelParent::RecvDivertOnDataAvailable(const nsCString& data,
- const uint64_t& offset,
- const uint32_t& count)
- {
- LOG(("HttpChannelParent::RecvDivertOnDataAvailable [this=%p]\n", this));
- MOZ_ASSERT(mParentListener);
- if (NS_WARN_IF(!mDivertingFromChild)) {
- MOZ_ASSERT(mDivertingFromChild,
- "Cannot RecvDivertOnDataAvailable if diverting is not set!");
- FailDiversion(NS_ERROR_UNEXPECTED);
- return false;
- }
- // Drop OnDataAvailables if the parent was canceled already.
- if (NS_FAILED(mStatus)) {
- return true;
- }
- mEventQ->RunOrEnqueue(new DivertDataAvailableEvent(this, data, offset,
- count));
- return true;
- }
- void
- HttpChannelParent::DivertOnDataAvailable(const nsCString& data,
- const uint64_t& offset,
- const uint32_t& count)
- {
- LOG(("HttpChannelParent::DivertOnDataAvailable [this=%p]\n", this));
- MOZ_ASSERT(mParentListener);
- if (NS_WARN_IF(!mDivertingFromChild)) {
- MOZ_ASSERT(mDivertingFromChild,
- "Cannot DivertOnDataAvailable if diverting is not set!");
- FailDiversion(NS_ERROR_UNEXPECTED);
- return;
- }
- // Drop OnDataAvailables if the parent was canceled already.
- if (NS_FAILED(mStatus)) {
- return;
- }
- nsCOMPtr<nsIInputStream> stringStream;
- nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream), data.get(),
- count, NS_ASSIGNMENT_DEPEND);
- if (NS_FAILED(rv)) {
- if (mChannel) {
- mChannel->Cancel(rv);
- }
- mStatus = rv;
- return;
- }
- AutoEventEnqueuer ensureSerialDispatch(mEventQ);
- rv = mParentListener->OnDataAvailable(mChannel, nullptr, stringStream,
- offset, count);
- stringStream->Close();
- if (NS_FAILED(rv)) {
- if (mChannel) {
- mChannel->Cancel(rv);
- }
- mStatus = rv;
- }
- }
- class DivertStopRequestEvent : public ChannelEvent
- {
- public:
- DivertStopRequestEvent(HttpChannelParent* aParent,
- const nsresult& statusCode)
- : mParent(aParent)
- , mStatusCode(statusCode)
- {
- }
- void Run() {
- mParent->DivertOnStopRequest(mStatusCode);
- }
- private:
- HttpChannelParent* mParent;
- nsresult mStatusCode;
- };
- bool
- HttpChannelParent::RecvDivertOnStopRequest(const nsresult& statusCode)
- {
- LOG(("HttpChannelParent::RecvDivertOnStopRequest [this=%p]\n", this));
- MOZ_ASSERT(mParentListener);
- if (NS_WARN_IF(!mDivertingFromChild)) {
- MOZ_ASSERT(mDivertingFromChild,
- "Cannot RecvDivertOnStopRequest if diverting is not set!");
- FailDiversion(NS_ERROR_UNEXPECTED);
- return false;
- }
- mEventQ->RunOrEnqueue(new DivertStopRequestEvent(this, statusCode));
- return true;
- }
- void
- HttpChannelParent::DivertOnStopRequest(const nsresult& statusCode)
- {
- LOG(("HttpChannelParent::DivertOnStopRequest [this=%p]\n", this));
- MOZ_ASSERT(mParentListener);
- if (NS_WARN_IF(!mDivertingFromChild)) {
- MOZ_ASSERT(mDivertingFromChild,
- "Cannot DivertOnStopRequest if diverting is not set!");
- FailDiversion(NS_ERROR_UNEXPECTED);
- return;
- }
- // Honor the channel's status even if the underlying transaction completed.
- nsresult status = NS_FAILED(mStatus) ? mStatus : statusCode;
- // Reset fake pending status in case OnStopRequest has already been called.
- if (mChannel) {
- mChannel->ForcePending(false);
- }
- AutoEventEnqueuer ensureSerialDispatch(mEventQ);
- mParentListener->OnStopRequest(mChannel, nullptr, status);
- }
- class DivertCompleteEvent : public ChannelEvent
- {
- public:
- explicit DivertCompleteEvent(HttpChannelParent* aParent)
- : mParent(aParent)
- {
- }
- void Run() {
- mParent->DivertComplete();
- }
- private:
- HttpChannelParent* mParent;
- };
- bool
- HttpChannelParent::RecvDivertComplete()
- {
- LOG(("HttpChannelParent::RecvDivertComplete [this=%p]\n", this));
- MOZ_ASSERT(mParentListener);
- if (NS_WARN_IF(!mDivertingFromChild)) {
- MOZ_ASSERT(mDivertingFromChild,
- "Cannot RecvDivertComplete if diverting is not set!");
- FailDiversion(NS_ERROR_UNEXPECTED);
- return false;
- }
- mEventQ->RunOrEnqueue(new DivertCompleteEvent(this));
- return true;
- }
- void
- HttpChannelParent::DivertComplete()
- {
- LOG(("HttpChannelParent::DivertComplete [this=%p]\n", this));
- MOZ_ASSERT(mParentListener);
- if (NS_WARN_IF(!mDivertingFromChild)) {
- MOZ_ASSERT(mDivertingFromChild,
- "Cannot DivertComplete if diverting is not set!");
- FailDiversion(NS_ERROR_UNEXPECTED);
- return;
- }
- nsresult rv = ResumeForDiversion();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- FailDiversion(NS_ERROR_UNEXPECTED);
- return;
- }
- mParentListener = nullptr;
- }
- void
- HttpChannelParent::MaybeFlushPendingDiversion()
- {
- if (!mPendingDiversion) {
- return;
- }
- mPendingDiversion = false;
- nsresult rv = SuspendForDiversion();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return;
- }
- if (mDivertListener) {
- DivertTo(mDivertListener);
- }
- return;
- }
- void
- HttpChannelParent::ResponseSynthesized()
- {
- // Suspend now even though the FinishSynthesizeResponse runnable has
- // not executed. We want to suspend after we get far enough to trigger
- // the synthesis, but not actually allow the nsHttpChannel to trigger
- // any OnStartRequests().
- if (mSuspendAfterSynthesizeResponse) {
- mChannel->Suspend();
- }
- mWillSynthesizeResponse = false;
- MaybeFlushPendingDiversion();
- }
- bool
- HttpChannelParent::RecvRemoveCorsPreflightCacheEntry(const URIParams& uri,
- const mozilla::ipc::PrincipalInfo& requestingPrincipal)
- {
- nsCOMPtr<nsIURI> deserializedURI = DeserializeURI(uri);
- if (!deserializedURI) {
- return false;
- }
- nsCOMPtr<nsIPrincipal> principal =
- PrincipalInfoToPrincipal(requestingPrincipal);
- if (!principal) {
- return false;
- }
- nsCORSListenerProxy::RemoveFromCorsPreflightCache(deserializedURI,
- principal);
- return true;
- }
- //-----------------------------------------------------------------------------
- // HttpChannelParent::nsIRequestObserver
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
- {
- LOG(("HttpChannelParent::OnStartRequest [this=%p, aRequest=%p]\n",
- this, aRequest));
- MOZ_RELEASE_ASSERT(!mDivertingFromChild,
- "Cannot call OnStartRequest if diverting is set!");
- // We can't cast here since the new channel can be a redirect to a different
- // schema. We must query the channel implementation through a special method.
- nsHttpChannel *chan = nullptr;
- nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(do_QueryInterface(aRequest));
- if (httpChannelInternal) {
- chan = httpChannelInternal->QueryHttpChannelImpl();
- }
- if (!chan) {
- LOG((" aRequest is not nsHttpChannel"));
- NS_ERROR("Expecting only nsHttpChannel as aRequest in HttpChannelParent::OnStartRequest");
- return NS_ERROR_UNEXPECTED;
- }
- MOZ_ASSERT(mChannel == chan,
- "HttpChannelParent getting OnStartRequest from a different nsHttpChannel instance");
- nsHttpResponseHead *responseHead = chan->GetResponseHead();
- nsHttpRequestHead *requestHead = chan->GetRequestHead();
- bool isFromCache = false;
- chan->IsFromCache(&isFromCache);
- uint32_t expirationTime = nsICacheEntry::NO_EXPIRATION_TIME;
- chan->GetCacheTokenExpirationTime(&expirationTime);
- nsCString cachedCharset;
- chan->GetCacheTokenCachedCharset(cachedCharset);
- bool loadedFromApplicationCache;
- chan->GetLoadedFromApplicationCache(&loadedFromApplicationCache);
- if (loadedFromApplicationCache) {
- mOfflineForeignMarker = chan->GetOfflineCacheEntryAsForeignMarker();
- nsCOMPtr<nsIApplicationCache> appCache;
- chan->GetApplicationCache(getter_AddRefs(appCache));
- nsCString appCacheGroupId;
- nsCString appCacheClientId;
- appCache->GetGroupID(appCacheGroupId);
- appCache->GetClientID(appCacheClientId);
- if (mIPCClosed ||
- !SendAssociateApplicationCache(appCacheGroupId, appCacheClientId))
- {
- return NS_ERROR_UNEXPECTED;
- }
- }
- nsCOMPtr<nsIEncodedChannel> encodedChannel = do_QueryInterface(aRequest);
- if (encodedChannel)
- encodedChannel->SetApplyConversion(false);
- // Keep the cache entry for future use in RecvSetCacheTokenCachedCharset().
- // It could be already released by nsHttpChannel at that time.
- nsCOMPtr<nsISupports> cacheEntry;
- chan->GetCacheToken(getter_AddRefs(cacheEntry));
- mCacheEntry = do_QueryInterface(cacheEntry);
- nsresult channelStatus = NS_OK;
- chan->GetStatus(&channelStatus);
- nsCString secInfoSerialization;
- UpdateAndSerializeSecurityInfo(secInfoSerialization);
- uint8_t redirectCount = 0;
- chan->GetRedirectCount(&redirectCount);
- nsCOMPtr<nsISupports> cacheKey;
- chan->GetCacheKey(getter_AddRefs(cacheKey));
- uint32_t cacheKeyValue = 0;
- if (cacheKey) {
- nsCOMPtr<nsISupportsPRUint32> container = do_QueryInterface(cacheKey);
- if (!container) {
- return NS_ERROR_ILLEGAL_VALUE;
- }
- nsresult rv = container->GetData(&cacheKeyValue);
- if (NS_FAILED(rv)) {
- return rv;
- }
- }
- nsAutoCString altDataType;
- chan->GetAlternativeDataType(altDataType);
- // !!! We need to lock headers and please don't forget to unlock them !!!
- requestHead->Enter();
- nsresult rv = NS_OK;
- if (mIPCClosed ||
- !SendOnStartRequest(channelStatus,
- responseHead ? *responseHead : nsHttpResponseHead(),
- !!responseHead,
- requestHead->Headers(),
- isFromCache,
- mCacheEntry ? true : false,
- expirationTime, cachedCharset, secInfoSerialization,
- chan->GetSelfAddr(), chan->GetPeerAddr(),
- redirectCount,
- cacheKeyValue,
- altDataType))
- {
- rv = NS_ERROR_UNEXPECTED;
- }
- requestHead->Exit();
- return rv;
- }
- NS_IMETHODIMP
- HttpChannelParent::OnStopRequest(nsIRequest *aRequest,
- nsISupports *aContext,
- nsresult aStatusCode)
- {
- LOG(("HttpChannelParent::OnStopRequest: [this=%p aRequest=%p status=%x]\n",
- this, aRequest, aStatusCode));
- MOZ_RELEASE_ASSERT(!mDivertingFromChild,
- "Cannot call OnStopRequest if diverting is set!");
- ResourceTimingStruct timing;
- mChannel->GetDomainLookupStart(&timing.domainLookupStart);
- mChannel->GetDomainLookupEnd(&timing.domainLookupEnd);
- mChannel->GetConnectStart(&timing.connectStart);
- mChannel->GetSecureConnectionStart(&timing.secureConnectionStart);
- mChannel->GetConnectEnd(&timing.connectEnd);
- mChannel->GetRequestStart(&timing.requestStart);
- mChannel->GetResponseStart(&timing.responseStart);
- mChannel->GetResponseEnd(&timing.responseEnd);
- mChannel->GetAsyncOpen(&timing.fetchStart);
- mChannel->GetRedirectStart(&timing.redirectStart);
- mChannel->GetRedirectEnd(&timing.redirectEnd);
- mChannel->GetTransferSize(&timing.transferSize);
- mChannel->GetEncodedBodySize(&timing.encodedBodySize);
- // decodedBodySize can be computed in the child process so it doesn't need
- // to be passed down.
- mChannel->GetProtocolVersion(timing.protocolVersion);
- mChannel->GetCacheReadStart(&timing.cacheReadStart);
- mChannel->GetCacheReadEnd(&timing.cacheReadEnd);
- if (mIPCClosed || !SendOnStopRequest(aStatusCode, timing))
- return NS_ERROR_UNEXPECTED;
- return NS_OK;
- }
- //-----------------------------------------------------------------------------
- // HttpChannelParent::nsIStreamListener
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpChannelParent::OnDataAvailable(nsIRequest *aRequest,
- nsISupports *aContext,
- nsIInputStream *aInputStream,
- uint64_t aOffset,
- uint32_t aCount)
- {
- LOG(("HttpChannelParent::OnDataAvailable [this=%p aRequest=%p]\n",
- this, aRequest));
- MOZ_RELEASE_ASSERT(!mDivertingFromChild,
- "Cannot call OnDataAvailable if diverting is set!");
- nsresult channelStatus = NS_OK;
- mChannel->GetStatus(&channelStatus);
- static uint32_t const kCopyChunkSize = 128 * 1024;
- uint32_t toRead = std::min<uint32_t>(aCount, kCopyChunkSize);
- nsCString data;
- if (!data.SetCapacity(toRead, fallible)) {
- LOG((" out of memory!"));
- return NS_ERROR_OUT_OF_MEMORY;
- }
- while (aCount) {
- nsresult rv = NS_ReadInputStreamToString(aInputStream, data, toRead);
- if (NS_FAILED(rv)) {
- return rv;
- }
- // OnDataAvailable is always preceded by OnStatus/OnProgress calls that set
- // mStoredStatus/mStoredProgress(Max) to appropriate values, unless
- // LOAD_BACKGROUND set. In that case, they'll have garbage values, but
- // child doesn't use them.
- if (mIPCClosed || !SendOnTransportAndData(channelStatus, mStoredStatus,
- mStoredProgress, mStoredProgressMax,
- aOffset, toRead, data)) {
- return NS_ERROR_UNEXPECTED;
- }
- aOffset += toRead;
- aCount -= toRead;
- toRead = std::min<uint32_t>(aCount, kCopyChunkSize);
- }
- return NS_OK;
- }
- //-----------------------------------------------------------------------------
- // HttpChannelParent::nsIProgressEventSink
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpChannelParent::OnProgress(nsIRequest *aRequest,
- nsISupports *aContext,
- int64_t aProgress,
- int64_t aProgressMax)
- {
- // OnStatus has always just set mStoredStatus. If it indicates this precedes
- // OnDataAvailable, store and ODA will send to child.
- if (mStoredStatus == NS_NET_STATUS_RECEIVING_FROM ||
- mStoredStatus == NS_NET_STATUS_READING)
- {
- mStoredProgress = aProgress;
- mStoredProgressMax = aProgressMax;
- } else {
- // Send OnProgress events to the child for data upload progress notifications
- // (i.e. status == NS_NET_STATUS_SENDING_TO) or if the channel has
- // LOAD_BACKGROUND set.
- if (mIPCClosed || !SendOnProgress(aProgress, aProgressMax))
- return NS_ERROR_UNEXPECTED;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpChannelParent::OnStatus(nsIRequest *aRequest,
- nsISupports *aContext,
- nsresult aStatus,
- const char16_t *aStatusArg)
- {
- // If this precedes OnDataAvailable, store and ODA will send to child.
- if (aStatus == NS_NET_STATUS_RECEIVING_FROM ||
- aStatus == NS_NET_STATUS_READING)
- {
- mStoredStatus = aStatus;
- return NS_OK;
- }
- // Otherwise, send to child now
- if (mIPCClosed || !SendOnStatus(aStatus))
- return NS_ERROR_UNEXPECTED;
- return NS_OK;
- }
- //-----------------------------------------------------------------------------
- // HttpChannelParent::nsIParentChannel
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpChannelParent::SetParentListener(HttpChannelParentListener* aListener)
- {
- LOG(("HttpChannelParent::SetParentListener [this=%p aListener=%p]\n",
- this, aListener));
- MOZ_ASSERT(aListener);
- MOZ_ASSERT(!mParentListener, "SetParentListener should only be called for "
- "new HttpChannelParents after a redirect, when "
- "mParentListener is null.");
- mParentListener = aListener;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpChannelParent::NotifyTrackingProtectionDisabled()
- {
- if (!mIPCClosed)
- Unused << SendNotifyTrackingProtectionDisabled();
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpChannelParent::Delete()
- {
- if (!mIPCClosed)
- Unused << DoSendDeleteSelf();
- return NS_OK;
- }
- //-----------------------------------------------------------------------------
- // HttpChannelParent::nsIParentRedirectingChannel
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpChannelParent::StartRedirect(uint32_t registrarId,
- nsIChannel* newChannel,
- uint32_t redirectFlags,
- nsIAsyncVerifyRedirectCallback* callback)
- {
- LOG(("HttpChannelParent::StartRedirect [this=%p, registrarId=%lu "
- "newChannel=%p callback=%p]\n", this, registrarId, newChannel,
- callback));
- if (mIPCClosed)
- return NS_BINDING_ABORTED;
- nsCOMPtr<nsIURI> newURI;
- newChannel->GetURI(getter_AddRefs(newURI));
- URIParams uriParams;
- SerializeURI(newURI, uriParams);
- nsCString secInfoSerialization;
- UpdateAndSerializeSecurityInfo(secInfoSerialization);
- // If the channel is a HTTP channel, we also want to inform the child
- // about the parent's channelId attribute, so that both parent and child
- // share the same ID. Useful for monitoring channel activity in devtools.
- nsAutoCString channelId;
- nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
- if (httpChannel) {
- nsresult rv = httpChannel->GetChannelId(channelId);
- NS_ENSURE_SUCCESS(rv, NS_BINDING_ABORTED);
- }
- nsHttpResponseHead *responseHead = mChannel->GetResponseHead();
- bool result = false;
- if (!mIPCClosed) {
- result = SendRedirect1Begin(registrarId, uriParams, redirectFlags,
- responseHead ? *responseHead
- : nsHttpResponseHead(),
- secInfoSerialization,
- channelId);
- }
- if (!result) {
- // Bug 621446 investigation
- mSentRedirect1BeginFailed = true;
- return NS_BINDING_ABORTED;
- }
- // Bug 621446 investigation
- mSentRedirect1Begin = true;
- // Result is handled in RecvRedirect2Verify above
- mRedirectChannel = newChannel;
- mRedirectCallback = callback;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpChannelParent::CompleteRedirect(bool succeeded)
- {
- LOG(("HttpChannelParent::CompleteRedirect [this=%p succeeded=%d]\n",
- this, succeeded));
- if (succeeded && !mIPCClosed) {
- // TODO: check return value: assume child dead if failed
- Unused << SendRedirect3Complete();
- }
- mRedirectChannel = nullptr;
- return NS_OK;
- }
- //-----------------------------------------------------------------------------
- // HttpChannelParent::ADivertableParentChannel
- //-----------------------------------------------------------------------------
- nsresult
- HttpChannelParent::SuspendForDiversion()
- {
- LOG(("HttpChannelParent::SuspendForDiversion [this=%p]\n", this));
- MOZ_ASSERT(mChannel);
- MOZ_ASSERT(mParentListener);
- // If we're in the process of opening a synthesized response, we must wait
- // to perform the diversion. Some of our diversion listeners clear callbacks
- // which breaks the synthesis process.
- if (mWillSynthesizeResponse) {
- mPendingDiversion = true;
- return NS_OK;
- }
- if (NS_WARN_IF(mDivertingFromChild)) {
- MOZ_ASSERT(!mDivertingFromChild, "Already suspended for diversion!");
- return NS_ERROR_UNEXPECTED;
- }
- // MessageDiversionStarted call will suspend mEventQ as many times as the
- // channel has been suspended, so that channel and this queue are in sync.
- mChannel->MessageDiversionStarted(this);
- nsresult rv = NS_OK;
- // Try suspending the channel. Allow it to fail, since OnStopRequest may have
- // been called and thus the channel may not be pending. If we've already
- // automatically suspended after synthesizing the response, then we don't
- // need to suspend again here.
- if (!mSuspendAfterSynthesizeResponse) {
- // We need to suspend only nsHttpChannel (i.e. we should not suspend
- // mEventQ). Therefore we call mChannel->SuspendInternal() and not
- // mChannel->Suspend().
- // We are suspending only nsHttpChannel here because we want to stop
- // OnDataAvailable until diversion is over. At the same time we should
- // send the diverted OnDataAvailable-s to the listeners and not queue them
- // in mEventQ.
- rv = mChannel->SuspendInternal();
- MOZ_ASSERT(NS_SUCCEEDED(rv) || rv == NS_ERROR_NOT_AVAILABLE);
- mSuspendedForDiversion = NS_SUCCEEDED(rv);
- } else {
- // Take ownership of the automatic suspend that occurred after synthesizing
- // the response.
- mSuspendedForDiversion = true;
- // If mSuspendAfterSynthesizeResponse is true channel has been already
- // suspended. From comment above mSuspendedForDiversion takes the ownership
- // of this suspend, therefore mEventQ should not be suspened so we need to
- // resume it once.
- mEventQ->Resume();
- }
- rv = mParentListener->SuspendForDiversion();
- MOZ_ASSERT(NS_SUCCEEDED(rv));
- // Once this is set, no more OnStart/OnData/OnStop callbacks should be sent
- // to the child.
- mDivertingFromChild = true;
- return NS_OK;
- }
- nsresult
- HttpChannelParent::SuspendMessageDiversion()
- {
- LOG(("HttpChannelParent::SuspendMessageDiversion [this=%p]", this));
- // This only needs to suspend message queue.
- mEventQ->Suspend();
- return NS_OK;
- }
- nsresult
- HttpChannelParent::ResumeMessageDiversion()
- {
- LOG(("HttpChannelParent::SuspendMessageDiversion [this=%p]", this));
- // This only needs to resumes message queue.
- mEventQ->Resume();
- return NS_OK;
- }
- /* private, supporting function for ADivertableParentChannel */
- nsresult
- HttpChannelParent::ResumeForDiversion()
- {
- LOG(("HttpChannelParent::ResumeForDiversion [this=%p]\n", this));
- MOZ_ASSERT(mChannel);
- if (NS_WARN_IF(!mDivertingFromChild)) {
- MOZ_ASSERT(mDivertingFromChild,
- "Cannot ResumeForDiversion if not diverting!");
- return NS_ERROR_UNEXPECTED;
- }
- mChannel->MessageDiversionStop();
- if (mSuspendedForDiversion) {
- // The nsHttpChannel will deliver remaining OnData/OnStop for the transfer.
- nsresult rv = mChannel->ResumeInternal();
- if (NS_WARN_IF(NS_FAILED(rv))) {
- FailDiversion(NS_ERROR_UNEXPECTED, true);
- return rv;
- }
- mSuspendedForDiversion = false;
- }
- if (NS_WARN_IF(mIPCClosed || !DoSendDeleteSelf())) {
- FailDiversion(NS_ERROR_UNEXPECTED);
- return NS_ERROR_UNEXPECTED;
- }
- return NS_OK;
- }
- void
- HttpChannelParent::DivertTo(nsIStreamListener *aListener)
- {
- LOG(("HttpChannelParent::DivertTo [this=%p aListener=%p]\n",
- this, aListener));
- MOZ_ASSERT(mParentListener);
- // If we're in the process of opening a synthesized response, we must wait
- // to perform the diversion. Some of our diversion listeners clear callbacks
- // which breaks the synthesis process.
- if (mWillSynthesizeResponse) {
- // We should already have started pending the diversion when
- // SuspendForDiversion() was called.
- MOZ_ASSERT(mPendingDiversion);
- mDivertListener = aListener;
- return;
- }
- if (NS_WARN_IF(!mDivertingFromChild)) {
- MOZ_ASSERT(mDivertingFromChild,
- "Cannot DivertTo new listener if diverting is not set!");
- return;
- }
- mDivertListener = aListener;
- // Call OnStartRequest and SendDivertMessages asynchronously to avoid
- // reentering client context.
- NS_DispatchToCurrentThread(
- NewRunnableMethod(this, &HttpChannelParent::StartDiversion));
- return;
- }
- void
- HttpChannelParent::StartDiversion()
- {
- LOG(("HttpChannelParent::StartDiversion [this=%p]\n", this));
- if (NS_WARN_IF(!mDivertingFromChild)) {
- MOZ_ASSERT(mDivertingFromChild,
- "Cannot StartDiversion if diverting is not set!");
- return;
- }
- // Fake pending status in case OnStopRequest has already been called.
- if (mChannel) {
- mChannel->ForcePending(true);
- }
- {
- AutoEventEnqueuer ensureSerialDispatch(mEventQ);
- // Call OnStartRequest for the "DivertTo" listener.
- nsresult rv = mDivertListener->OnStartRequest(mChannel, nullptr);
- if (NS_FAILED(rv)) {
- if (mChannel) {
- mChannel->Cancel(rv);
- }
- mStatus = rv;
- }
- }
- mDivertedOnStartRequest = true;
- // After OnStartRequest has been called, setup content decoders if needed.
- //
- // Create a content conversion chain based on mDivertListener and update
- // mDivertListener.
- nsCOMPtr<nsIStreamListener> converterListener;
- mChannel->DoApplyContentConversions(mDivertListener,
- getter_AddRefs(converterListener));
- if (converterListener) {
- mDivertListener = converterListener.forget();
- }
- // Now mParentListener can be diverted to mDivertListener.
- DebugOnly<nsresult> rvdbg = mParentListener->DivertTo(mDivertListener);
- MOZ_ASSERT(NS_SUCCEEDED(rvdbg));
- mDivertListener = nullptr;
- if (NS_WARN_IF(mIPCClosed || !SendFlushedForDiversion())) {
- FailDiversion(NS_ERROR_UNEXPECTED);
- return;
- }
- // The listener chain should now be setup; tell HttpChannelChild to divert
- // the OnDataAvailables and OnStopRequest to this HttpChannelParent.
- if (NS_WARN_IF(mIPCClosed || !SendDivertMessages())) {
- FailDiversion(NS_ERROR_UNEXPECTED);
- return;
- }
- }
- class HTTPFailDiversionEvent : public Runnable
- {
- public:
- HTTPFailDiversionEvent(HttpChannelParent *aChannelParent,
- nsresult aErrorCode,
- bool aSkipResume)
- : mChannelParent(aChannelParent)
- , mErrorCode(aErrorCode)
- , mSkipResume(aSkipResume)
- {
- MOZ_RELEASE_ASSERT(aChannelParent);
- MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
- }
- NS_IMETHOD Run() override
- {
- mChannelParent->NotifyDiversionFailed(mErrorCode, mSkipResume);
- return NS_OK;
- }
- private:
- RefPtr<HttpChannelParent> mChannelParent;
- nsresult mErrorCode;
- bool mSkipResume;
- };
- void
- HttpChannelParent::FailDiversion(nsresult aErrorCode,
- bool aSkipResume)
- {
- MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
- MOZ_RELEASE_ASSERT(mDivertingFromChild);
- MOZ_RELEASE_ASSERT(mParentListener);
- MOZ_RELEASE_ASSERT(mChannel);
- NS_DispatchToCurrentThread(
- new HTTPFailDiversionEvent(this, aErrorCode, aSkipResume));
- }
- void
- HttpChannelParent::NotifyDiversionFailed(nsresult aErrorCode,
- bool aSkipResume)
- {
- LOG(("HttpChannelParent::NotifyDiversionFailed [this=%p aErrorCode=%x]\n",
- this, aErrorCode));
- MOZ_RELEASE_ASSERT(NS_FAILED(aErrorCode));
- MOZ_RELEASE_ASSERT(mDivertingFromChild);
- MOZ_RELEASE_ASSERT(mParentListener);
- MOZ_RELEASE_ASSERT(mChannel);
- mChannel->Cancel(aErrorCode);
- mChannel->ForcePending(false);
- bool isPending = false;
- nsresult rv = mChannel->IsPending(&isPending);
- MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
- // Resume only if we suspended earlier.
- if (mSuspendedForDiversion) {
- mChannel->ResumeInternal();
- }
- // Channel has already sent OnStartRequest to the child, so ensure that we
- // call it here if it hasn't already been called.
- if (!mDivertedOnStartRequest) {
- mChannel->ForcePending(true);
- mParentListener->OnStartRequest(mChannel, nullptr);
- mChannel->ForcePending(false);
- }
- // If the channel is pending, it will call OnStopRequest itself; otherwise, do
- // it here.
- if (!isPending) {
- mParentListener->OnStopRequest(mChannel, nullptr, aErrorCode);
- }
- mParentListener = nullptr;
- mChannel = nullptr;
- if (!mIPCClosed) {
- Unused << DoSendDeleteSelf();
- }
- }
- nsresult
- HttpChannelParent::OpenAlternativeOutputStream(const nsACString & type, nsIOutputStream * *_retval)
- {
- // We need to make sure the child does not call SendDocumentChannelCleanup()
- // before opening the altOutputStream, because that clears mCacheEntry.
- if (!mCacheEntry) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- return mCacheEntry->OpenAlternativeOutputStream(type, _retval);
- }
- NS_IMETHODIMP
- HttpChannelParent::GetAuthPrompt(uint32_t aPromptReason, const nsIID& iid,
- void** aResult)
- {
- nsCOMPtr<nsIAuthPrompt2> prompt =
- new NeckoParent::NestedFrameAuthPrompt(Manager(), mNestedFrameId);
- prompt.forget(aResult);
- return NS_OK;
- }
- void
- HttpChannelParent::UpdateAndSerializeSecurityInfo(nsACString& aSerializedSecurityInfoOut)
- {
- nsCOMPtr<nsISupports> secInfoSupp;
- mChannel->GetSecurityInfo(getter_AddRefs(secInfoSupp));
- if (secInfoSupp) {
- mAssociatedContentSecurity = do_QueryInterface(secInfoSupp);
- nsCOMPtr<nsISerializable> secInfoSer = do_QueryInterface(secInfoSupp);
- if (secInfoSer) {
- NS_SerializeToString(secInfoSer, aSerializedSecurityInfoOut);
- }
- }
- }
- bool
- HttpChannelParent::DoSendDeleteSelf()
- {
- mIPCClosed = true;
- bool rv = SendDeleteSelf();
- return rv;
- }
- bool
- HttpChannelParent::RecvDeletingChannel()
- {
- // We need to ensure that the parent channel will not be sending any more IPC
- // messages after this, as the child is going away. DoSendDeleteSelf will
- // set mIPCClosed = true;
- return DoSendDeleteSelf();
- }
- bool
- HttpChannelParent::RecvFinishInterceptedRedirect()
- {
- // We make sure not to send any more messages until the IPC channel is torn
- // down by the child.
- mIPCClosed = true;
- return SendFinishInterceptedRedirect();
- }
- //-----------------------------------------------------------------------------
- // HttpChannelSecurityWarningReporter
- //-----------------------------------------------------------------------------
- nsresult
- HttpChannelParent::ReportSecurityMessage(const nsAString& aMessageTag,
- const nsAString& aMessageCategory)
- {
- if (mIPCClosed ||
- NS_WARN_IF(!SendReportSecurityMessage(nsString(aMessageTag),
- nsString(aMessageCategory)))) {
- return NS_ERROR_UNEXPECTED;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpChannelParent::IssueWarning(uint32_t aWarning, bool aAsError)
- {
- Unused << SendIssueDeprecationWarning(aWarning, aAsError);
- return NS_OK;
- }
- } // namespace net
- } // namespace mozilla
|