12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824 |
- /* -*- 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/net/HttpBaseChannel.h"
- #include "nsHttpHandler.h"
- #include "nsHttpChannel.h"
- #include "nsMimeTypes.h"
- #include "nsNetCID.h"
- #include "nsNetUtil.h"
- #include "nsICachingChannel.h"
- #include "nsIDOMDocument.h"
- #include "nsIPrincipal.h"
- #include "nsIScriptError.h"
- #include "nsISeekableStream.h"
- #include "nsIStorageStream.h"
- #include "nsITimedChannel.h"
- #include "nsIEncodedChannel.h"
- #include "nsIApplicationCacheChannel.h"
- #include "nsIMutableArray.h"
- #include "nsEscape.h"
- #include "nsStreamListenerWrapper.h"
- #include "nsISecurityConsoleMessage.h"
- #include "nsURLHelper.h"
- #include "nsICookieService.h"
- #include "nsIStreamConverterService.h"
- #include "nsCRT.h"
- #include "nsContentUtils.h"
- #include "nsIScriptSecurityManager.h"
- #include "nsIObserverService.h"
- #include "nsProxyRelease.h"
- #include "nsPIDOMWindow.h"
- #include "nsIDocShell.h"
- #include "nsINetworkInterceptController.h"
- #include "mozilla/dom/Performance.h"
- #include "mozIThirdPartyUtil.h"
- #include "nsStreamUtils.h"
- #include "nsContentSecurityManager.h"
- #include "nsIChannelEventSink.h"
- #include "nsILoadGroupChild.h"
- #include "mozilla/ConsoleReportCollector.h"
- #include "LoadInfo.h"
- #include "nsNullPrincipal.h"
- #include "nsISSLSocketControl.h"
- #include "nsIURL.h"
- #include "nsIConsoleService.h"
- #include "mozilla/BinarySearch.h"
- #include "nsIHttpHeaderVisitor.h"
- #include "nsIXULRuntime.h"
- #include "nsICacheInfoChannel.h"
- #include "nsIDOMWindowUtils.h"
- #include <algorithm>
- #include "HttpBaseChannel.h"
- namespace mozilla {
- namespace net {
- HttpBaseChannel::HttpBaseChannel()
- : mStartPos(UINT64_MAX)
- , mStatus(NS_OK)
- , mLoadFlags(LOAD_NORMAL)
- , mCaps(0)
- , mClassOfService(0)
- , mPriority(PRIORITY_NORMAL)
- , mRedirectionLimit(gHttpHandler->RedirectionLimit())
- , mApplyConversion(true)
- , mCanceled(false)
- , mIsPending(false)
- , mWasOpened(false)
- , mRequestObserversCalled(false)
- , mResponseHeadersModified(false)
- , mAllowPipelining(true)
- , mAllowSTS(true)
- , mThirdPartyFlags(0)
- , mUploadStreamHasHeaders(false)
- , mInheritApplicationCache(true)
- , mChooseApplicationCache(false)
- , mLoadedFromApplicationCache(false)
- , mChannelIsForDownload(false)
- , mTracingEnabled(true)
- , mTimingEnabled(false)
- , mAllowSpdy(true)
- , mAllowAltSvc(true)
- , mBeConservative(false)
- , mResponseTimeoutEnabled(true)
- , mAllRedirectsSameOrigin(true)
- , mAllRedirectsPassTimingAllowCheck(true)
- , mResponseCouldBeSynthesized(false)
- , mBlockAuthPrompt(false)
- , mAllowStaleCacheContent(false)
- , mSuspendCount(0)
- , mInitialRwin(0)
- , mProxyResolveFlags(0)
- , mProxyURI(nullptr)
- , mContentDispositionHint(UINT32_MAX)
- , mHttpHandler(gHttpHandler)
- , mReferrerPolicy(REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE)
- , mRedirectCount(0)
- , mInternalRedirectCount(0)
- , mForcePending(false)
- , mCorsIncludeCredentials(false)
- , mCorsMode(nsIHttpChannelInternal::CORS_MODE_NO_CORS)
- , mRedirectMode(nsIHttpChannelInternal::REDIRECT_MODE_FOLLOW)
- , mFetchCacheMode(nsIHttpChannelInternal::FETCH_CACHE_MODE_DEFAULT)
- , mOnStartRequestCalled(false)
- , mOnStopRequestCalled(false)
- , mAfterOnStartRequestBegun(false)
- , mTransferSize(0)
- , mDecodedBodySize(0)
- , mEncodedBodySize(0)
- , mContentWindowId(0)
- , mRequireCORSPreflight(false)
- , mReportCollector(new ConsoleReportCollector())
- , mForceMainDocumentChannel(false)
- {
- LOG(("Creating HttpBaseChannel @%x\n", this));
- // Subfields of unions cannot be targeted in an initializer list.
- #ifdef MOZ_VALGRIND
- // Zero the entire unions so that Valgrind doesn't complain when we send them
- // to another process.
- memset(&mSelfAddr, 0, sizeof(NetAddr));
- memset(&mPeerAddr, 0, sizeof(NetAddr));
- #endif
- mSelfAddr.raw.family = PR_AF_UNSPEC;
- mPeerAddr.raw.family = PR_AF_UNSPEC;
- mRequestContextID.Clear();
- }
- HttpBaseChannel::~HttpBaseChannel()
- {
- LOG(("Destroying HttpBaseChannel @%x\n", this));
- NS_ReleaseOnMainThread(mLoadInfo.forget());
- // Make sure we don't leak
- CleanRedirectCacheChainIfNecessary();
- }
- nsresult
- HttpBaseChannel::Init(nsIURI *aURI,
- uint32_t aCaps,
- nsProxyInfo *aProxyInfo,
- uint32_t aProxyResolveFlags,
- nsIURI *aProxyURI,
- const nsID& aChannelId,
- nsContentPolicyType aContentPolicyType)
- {
- LOG(("HttpBaseChannel::Init [this=%p]\n", this));
- NS_PRECONDITION(aURI, "null uri");
- mURI = aURI;
- mOriginalURI = aURI;
- mDocumentURI = nullptr;
- mCaps = aCaps;
- mProxyResolveFlags = aProxyResolveFlags;
- mProxyURI = aProxyURI;
- mChannelId = aChannelId;
- // Construct connection info object
- nsAutoCString host;
- int32_t port = -1;
- bool isHTTPS = false;
- nsresult rv = mURI->GetAsciiHost(host);
- if (NS_FAILED(rv)) return rv;
- // Reject the URL if it doesn't specify a host
- if (host.IsEmpty())
- return NS_ERROR_MALFORMED_URI;
- rv = mURI->GetPort(&port);
- if (NS_FAILED(rv)) return rv;
- LOG(("host=%s port=%d\n", host.get(), port));
- rv = mURI->GetAsciiSpec(mSpec);
- if (NS_FAILED(rv)) return rv;
- LOG(("uri=%s\n", mSpec.get()));
- // Assert default request method
- MOZ_ASSERT(mRequestHead.EqualsMethod(nsHttpRequestHead::kMethod_Get));
- // Set request headers
- nsAutoCString hostLine;
- rv = nsHttpHandler::GenerateHostPort(host, port, hostLine);
- if (NS_FAILED(rv)) return rv;
- rv = mRequestHead.SetHeader(nsHttp::Host, hostLine);
- if (NS_FAILED(rv)) return rv;
- rv = gHttpHandler->AddStandardRequestHeaders(&mRequestHead, aContentPolicyType);
- if (NS_FAILED(rv)) return rv;
- nsAutoCString type;
- if (aProxyInfo && NS_SUCCEEDED(aProxyInfo->GetType(type)) &&
- !type.EqualsLiteral("unknown"))
- mProxyInfo = aProxyInfo;
- return rv;
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsISupports
- //-----------------------------------------------------------------------------
- NS_IMPL_ADDREF(HttpBaseChannel)
- NS_IMPL_RELEASE(HttpBaseChannel)
- NS_INTERFACE_MAP_BEGIN(HttpBaseChannel)
- NS_INTERFACE_MAP_ENTRY(nsIRequest)
- NS_INTERFACE_MAP_ENTRY(nsIChannel)
- NS_INTERFACE_MAP_ENTRY(nsIEncodedChannel)
- NS_INTERFACE_MAP_ENTRY(nsIHttpChannel)
- NS_INTERFACE_MAP_ENTRY(nsIHttpChannelInternal)
- NS_INTERFACE_MAP_ENTRY(nsIForcePendingChannel)
- NS_INTERFACE_MAP_ENTRY(nsIUploadChannel)
- NS_INTERFACE_MAP_ENTRY(nsIFormPOSTActionChannel)
- NS_INTERFACE_MAP_ENTRY(nsIUploadChannel2)
- NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
- NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
- NS_INTERFACE_MAP_ENTRY(nsIPrivateBrowsingChannel)
- NS_INTERFACE_MAP_ENTRY(nsITimedChannel)
- NS_INTERFACE_MAP_ENTRY(nsIConsoleReportCollector)
- NS_INTERFACE_MAP_ENTRY(nsIThrottledInputChannel)
- NS_INTERFACE_MAP_END_INHERITING(nsHashPropertyBag)
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsIRequest
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpBaseChannel::GetName(nsACString& aName)
- {
- aName = mSpec;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::IsPending(bool *aIsPending)
- {
- NS_ENSURE_ARG_POINTER(aIsPending);
- *aIsPending = mIsPending || mForcePending;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetStatus(nsresult *aStatus)
- {
- NS_ENSURE_ARG_POINTER(aStatus);
- *aStatus = mStatus;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetLoadGroup(nsILoadGroup **aLoadGroup)
- {
- NS_ENSURE_ARG_POINTER(aLoadGroup);
- *aLoadGroup = mLoadGroup;
- NS_IF_ADDREF(*aLoadGroup);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetLoadGroup(nsILoadGroup *aLoadGroup)
- {
- MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
- if (!CanSetLoadGroup(aLoadGroup)) {
- return NS_ERROR_FAILURE;
- }
- mLoadGroup = aLoadGroup;
- mProgressSink = nullptr;
- UpdatePrivateBrowsing();
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
- {
- NS_ENSURE_ARG_POINTER(aLoadFlags);
- *aLoadFlags = mLoadFlags;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
- {
- bool synthesized = false;
- nsresult rv = GetResponseSynthesized(&synthesized);
- NS_ENSURE_SUCCESS(rv, rv);
- // If this channel is marked as awaiting a synthesized response,
- // modifying certain load flags can interfere with the implementation
- // of the network interception logic. This takes care of a couple
- // known cases that attempt to mark channels as anonymous due
- // to cross-origin redirects; since the response is entirely synthesized
- // this is an unnecessary precaution.
- // This should be removed when bug 1201683 is fixed.
- if (synthesized && aLoadFlags != mLoadFlags) {
- aLoadFlags &= ~LOAD_ANONYMOUS;
- }
- mLoadFlags = aLoadFlags;
- mForceMainDocumentChannel = (aLoadFlags & LOAD_DOCUMENT_URI);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetDocshellUserAgentOverride()
- {
- // This sets the docshell specific user agent override, it will be overwritten
- // by UserAgentOverrides.jsm if site-specific user agent overrides are set.
- nsresult rv;
- nsCOMPtr<nsILoadContext> loadContext;
- NS_QueryNotificationCallbacks(this, loadContext);
- if (!loadContext) {
- return NS_OK;
- }
- nsCOMPtr<mozIDOMWindowProxy> domWindow;
- loadContext->GetAssociatedWindow(getter_AddRefs(domWindow));
- if (!domWindow) {
- return NS_OK;
- }
- auto* pDomWindow = nsPIDOMWindowOuter::From(domWindow);
- nsIDocShell* docshell = pDomWindow->GetDocShell();
- if (!docshell) {
- return NS_OK;
- }
- nsString customUserAgent;
- docshell->GetCustomUserAgent(customUserAgent);
- if (customUserAgent.IsEmpty()) {
- return NS_OK;
- }
- NS_ConvertUTF16toUTF8 utf8CustomUserAgent(customUserAgent);
- rv = SetRequestHeader(NS_LITERAL_CSTRING("User-Agent"), utf8CustomUserAgent, false);
- if (NS_FAILED(rv)) return rv;
- return NS_OK;
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsIChannel
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpBaseChannel::GetOriginalURI(nsIURI **aOriginalURI)
- {
- NS_ENSURE_ARG_POINTER(aOriginalURI);
- *aOriginalURI = mOriginalURI;
- NS_ADDREF(*aOriginalURI);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetOriginalURI(nsIURI *aOriginalURI)
- {
- ENSURE_CALLED_BEFORE_CONNECT();
- NS_ENSURE_ARG_POINTER(aOriginalURI);
- mOriginalURI = aOriginalURI;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetURI(nsIURI **aURI)
- {
- NS_ENSURE_ARG_POINTER(aURI);
- *aURI = mURI;
- NS_ADDREF(*aURI);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetOwner(nsISupports **aOwner)
- {
- NS_ENSURE_ARG_POINTER(aOwner);
- *aOwner = mOwner;
- NS_IF_ADDREF(*aOwner);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetOwner(nsISupports *aOwner)
- {
- mOwner = aOwner;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetLoadInfo(nsILoadInfo *aLoadInfo)
- {
- mLoadInfo = aLoadInfo;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetLoadInfo(nsILoadInfo **aLoadInfo)
- {
- NS_IF_ADDREF(*aLoadInfo = mLoadInfo);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetNotificationCallbacks(nsIInterfaceRequestor **aCallbacks)
- {
- *aCallbacks = mCallbacks;
- NS_IF_ADDREF(*aCallbacks);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetNotificationCallbacks(nsIInterfaceRequestor *aCallbacks)
- {
- MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
- if (!CanSetCallbacks(aCallbacks)) {
- return NS_ERROR_FAILURE;
- }
- mCallbacks = aCallbacks;
- mProgressSink = nullptr;
- UpdatePrivateBrowsing();
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetContentType(nsACString& aContentType)
- {
- if (!mResponseHead) {
- aContentType.Truncate();
- return NS_ERROR_NOT_AVAILABLE;
- }
- mResponseHead->ContentType(aContentType);
- if (!aContentType.IsEmpty()) {
- return NS_OK;
- }
- aContentType.AssignLiteral(UNKNOWN_CONTENT_TYPE);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetContentType(const nsACString& aContentType)
- {
- if (mListener || mWasOpened) {
- if (!mResponseHead)
- return NS_ERROR_NOT_AVAILABLE;
- nsAutoCString contentTypeBuf, charsetBuf;
- bool hadCharset;
- net_ParseContentType(aContentType, contentTypeBuf, charsetBuf, &hadCharset);
- mResponseHead->SetContentType(contentTypeBuf);
- // take care not to stomp on an existing charset
- if (hadCharset)
- mResponseHead->SetContentCharset(charsetBuf);
- } else {
- // We are being given a content-type hint.
- bool dummy;
- net_ParseContentType(aContentType, mContentTypeHint, mContentCharsetHint,
- &dummy);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetContentCharset(nsACString& aContentCharset)
- {
- if (!mResponseHead)
- return NS_ERROR_NOT_AVAILABLE;
- mResponseHead->ContentCharset(aContentCharset);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetContentCharset(const nsACString& aContentCharset)
- {
- if (mListener) {
- if (!mResponseHead)
- return NS_ERROR_NOT_AVAILABLE;
- mResponseHead->SetContentCharset(aContentCharset);
- } else {
- // Charset hint
- mContentCharsetHint = aContentCharset;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetContentDisposition(uint32_t *aContentDisposition)
- {
- nsresult rv;
- nsCString header;
- rv = GetContentDispositionHeader(header);
- if (NS_FAILED(rv)) {
- if (mContentDispositionHint == UINT32_MAX)
- return rv;
- *aContentDisposition = mContentDispositionHint;
- return NS_OK;
- }
- *aContentDisposition = NS_GetContentDispositionFromHeader(header, this);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetContentDisposition(uint32_t aContentDisposition)
- {
- mContentDispositionHint = aContentDisposition;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetContentDispositionFilename(nsAString& aContentDispositionFilename)
- {
- aContentDispositionFilename.Truncate();
- nsresult rv;
- nsCString header;
- rv = GetContentDispositionHeader(header);
- if (NS_FAILED(rv)) {
- if (!mContentDispositionFilename)
- return rv;
- aContentDispositionFilename = *mContentDispositionFilename;
- return NS_OK;
- }
- return NS_GetFilenameFromDisposition(aContentDispositionFilename,
- header, mURI);
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetContentDispositionFilename(const nsAString& aContentDispositionFilename)
- {
- mContentDispositionFilename = new nsString(aContentDispositionFilename);
- // For safety reasons ensure the filename doesn't contain null characters and
- // replace them with underscores. We may later pass the extension to system
- // MIME APIs that expect null terminated strings.
- mContentDispositionFilename->ReplaceChar(char16_t(0), '_');
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetContentDispositionHeader(nsACString& aContentDispositionHeader)
- {
- if (!mResponseHead)
- return NS_ERROR_NOT_AVAILABLE;
- nsresult rv = mResponseHead->GetHeader(nsHttp::Content_Disposition,
- aContentDispositionHeader);
- if (NS_FAILED(rv) || aContentDispositionHeader.IsEmpty())
- return NS_ERROR_NOT_AVAILABLE;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetContentLength(int64_t *aContentLength)
- {
- NS_ENSURE_ARG_POINTER(aContentLength);
- if (!mResponseHead)
- return NS_ERROR_NOT_AVAILABLE;
- *aContentLength = mResponseHead->ContentLength();
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetContentLength(int64_t value)
- {
- NS_NOTYETIMPLEMENTED("HttpBaseChannel::SetContentLength");
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- NS_IMETHODIMP
- HttpBaseChannel::Open(nsIInputStream **aResult)
- {
- NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_IN_PROGRESS);
- if (!gHttpHandler->Active()) {
- LOG(("HttpBaseChannel::Open after HTTP shutdown..."));
- return NS_ERROR_NOT_AVAILABLE;
- }
- return NS_ImplementChannelOpen(this, aResult);
- }
- NS_IMETHODIMP
- HttpBaseChannel::Open2(nsIInputStream** aStream)
- {
- if (!gHttpHandler->Active()) {
- LOG(("HttpBaseChannel::Open after HTTP shutdown..."));
- return NS_ERROR_NOT_AVAILABLE;
- }
- nsCOMPtr<nsIStreamListener> listener;
- nsresult rv = nsContentSecurityManager::doContentSecurityCheck(this, listener);
- NS_ENSURE_SUCCESS(rv, rv);
- return Open(aStream);
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsIUploadChannel
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpBaseChannel::GetUploadStream(nsIInputStream **stream)
- {
- NS_ENSURE_ARG_POINTER(stream);
- *stream = mUploadStream;
- NS_IF_ADDREF(*stream);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetUploadStream(nsIInputStream *stream,
- const nsACString &contentTypeArg,
- int64_t contentLength)
- {
- // NOTE: for backwards compatibility and for compatibility with old style
- // plugins, |stream| may include headers, specifically Content-Type and
- // Content-Length headers. in this case, |contentType| and |contentLength|
- // would be unspecified. this is traditionally the case of a POST request,
- // and so we select POST as the request method if contentType and
- // contentLength are unspecified.
- if (stream) {
- nsAutoCString method;
- bool hasHeaders;
- // This method and ExplicitSetUploadStream mean different things by "empty
- // content type string". This method means "no header", but
- // ExplicitSetUploadStream means "header with empty value". So we have to
- // massage the contentType argument into the form ExplicitSetUploadStream
- // expects.
- nsAutoCString contentType;
- if (contentTypeArg.IsEmpty()) {
- method = NS_LITERAL_CSTRING("POST");
- hasHeaders = true;
- contentType.SetIsVoid(true);
- } else {
- method = NS_LITERAL_CSTRING("PUT");
- hasHeaders = false;
- contentType = contentTypeArg;
- }
- return ExplicitSetUploadStream(stream, contentType, contentLength,
- method, hasHeaders);
- }
- // if stream is null, ExplicitSetUploadStream returns error.
- // So we need special case for GET method.
- mUploadStreamHasHeaders = false;
- mRequestHead.SetMethod(NS_LITERAL_CSTRING("GET")); // revert to GET request
- mUploadStream = stream;
- return NS_OK;
- }
- namespace {
- void
- CopyComplete(void* aClosure, nsresult aStatus) {
- // Called on the STS thread by NS_AsyncCopy
- auto channel = static_cast<HttpBaseChannel*>(aClosure);
- nsCOMPtr<nsIRunnable> runnable = NewRunnableMethod<nsresult>(
- channel, &HttpBaseChannel::EnsureUploadStreamIsCloneableComplete, aStatus);
- NS_DispatchToMainThread(runnable.forget());
- }
- } // anonymous namespace
- NS_IMETHODIMP
- HttpBaseChannel::EnsureUploadStreamIsCloneable(nsIRunnable* aCallback)
- {
- MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
- NS_ENSURE_ARG_POINTER(aCallback);
- // We could in theory allow multiple callers to use this method,
- // but the complexity does not seem worth it yet. Just fail if
- // this is called more than once simultaneously.
- NS_ENSURE_FALSE(mUploadCloneableCallback, NS_ERROR_UNEXPECTED);
- // If the CloneUploadStream() will succeed, then synchronously invoke
- // the callback to indicate we're already cloneable.
- if (!mUploadStream || NS_InputStreamIsCloneable(mUploadStream)) {
- aCallback->Run();
- return NS_OK;
- }
- nsCOMPtr<nsIStorageStream> storageStream;
- nsresult rv = NS_NewStorageStream(4096, UINT32_MAX,
- getter_AddRefs(storageStream));
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIInputStream> newUploadStream;
- rv = storageStream->NewInputStream(0, getter_AddRefs(newUploadStream));
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIOutputStream> sink;
- rv = storageStream->GetOutputStream(0, getter_AddRefs(sink));
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIInputStream> source;
- if (NS_InputStreamIsBuffered(mUploadStream)) {
- source = mUploadStream;
- } else {
- rv = NS_NewBufferedInputStream(getter_AddRefs(source), mUploadStream, 4096);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- nsCOMPtr<nsIEventTarget> target =
- do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
- mUploadCloneableCallback = aCallback;
- rv = NS_AsyncCopy(source, sink, target, NS_ASYNCCOPY_VIA_READSEGMENTS,
- 4096, // copy segment size
- CopyComplete, this);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- mUploadCloneableCallback = nullptr;
- return rv;
- }
- // Since we're consuming the old stream, replace it with the new
- // stream immediately.
- mUploadStream = newUploadStream;
- // Explicity hold the stream alive until copying is complete. This will
- // be released in EnsureUploadStreamIsCloneableComplete().
- AddRef();
- return NS_OK;
- }
- void
- HttpBaseChannel::EnsureUploadStreamIsCloneableComplete(nsresult aStatus)
- {
- MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
- MOZ_ASSERT(mUploadCloneableCallback);
- if (NS_SUCCEEDED(mStatus)) {
- mStatus = aStatus;
- }
- mUploadCloneableCallback->Run();
- mUploadCloneableCallback = nullptr;
- // Release the reference we grabbed in EnsureUploadStreamIsCloneable() now
- // that the copying is complete.
- Release();
- }
- NS_IMETHODIMP
- HttpBaseChannel::CloneUploadStream(nsIInputStream** aClonedStream)
- {
- NS_ENSURE_ARG_POINTER(aClonedStream);
- *aClonedStream = nullptr;
- if (!mUploadStream) {
- return NS_OK;
- }
- nsCOMPtr<nsIInputStream> clonedStream;
- nsresult rv = NS_CloneInputStream(mUploadStream, getter_AddRefs(clonedStream));
- NS_ENSURE_SUCCESS(rv, rv);
- clonedStream.forget(aClonedStream);
- return NS_OK;
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsIUploadChannel2
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpBaseChannel::ExplicitSetUploadStream(nsIInputStream *aStream,
- const nsACString &aContentType,
- int64_t aContentLength,
- const nsACString &aMethod,
- bool aStreamHasHeaders)
- {
- // Ensure stream is set and method is valid
- NS_ENSURE_TRUE(aStream, NS_ERROR_FAILURE);
- if (aContentLength < 0 && !aStreamHasHeaders) {
- nsresult rv = aStream->Available(reinterpret_cast<uint64_t*>(&aContentLength));
- if (NS_FAILED(rv) || aContentLength < 0) {
- NS_ERROR("unable to determine content length");
- return NS_ERROR_FAILURE;
- }
- }
- nsresult rv = SetRequestMethod(aMethod);
- NS_ENSURE_SUCCESS(rv, rv);
- if (!aStreamHasHeaders) {
- // SetRequestHeader propagates headers to chrome if HttpChannelChild
- nsAutoCString contentLengthStr;
- contentLengthStr.AppendInt(aContentLength);
- SetRequestHeader(NS_LITERAL_CSTRING("Content-Length"), contentLengthStr,
- false);
- if (!aContentType.IsVoid()) {
- if (aContentType.IsEmpty()) {
- SetEmptyRequestHeader(NS_LITERAL_CSTRING("Content-Type"));
- } else {
- SetRequestHeader(NS_LITERAL_CSTRING("Content-Type"), aContentType,
- false);
- }
- }
- }
- mUploadStreamHasHeaders = aStreamHasHeaders;
- mUploadStream = aStream;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetUploadStreamHasHeaders(bool *hasHeaders)
- {
- NS_ENSURE_ARG(hasHeaders);
- *hasHeaders = mUploadStreamHasHeaders;
- return NS_OK;
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsIEncodedChannel
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpBaseChannel::GetApplyConversion(bool *value)
- {
- *value = mApplyConversion;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetApplyConversion(bool value)
- {
- LOG(("HttpBaseChannel::SetApplyConversion [this=%p value=%d]\n", this, value));
- mApplyConversion = value;
- return NS_OK;
- }
- nsresult
- HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener,
- nsIStreamListener** aNewNextListener)
- {
- return DoApplyContentConversions(aNextListener,
- aNewNextListener,
- mListenerContext);
- }
- // create a listener chain that looks like this
- // http-channel -> decompressor (n times) -> InterceptFailedOnSTop -> channel-creator-listener
- //
- // we need to do this because not every decompressor has fully streamed output so
- // may need a call to OnStopRequest to identify its completion state.. and if it
- // creates an error there the channel status code needs to be updated before calling
- // the terminal listener. Having the decompress do it via cancel() means channels cannot
- // effectively be used in two contexts (specifically this one and a peek context for
- // sniffing)
- //
- class InterceptFailedOnStop : public nsIStreamListener
- {
- virtual ~InterceptFailedOnStop() {}
- nsCOMPtr<nsIStreamListener> mNext;
- HttpBaseChannel *mChannel;
- public:
- InterceptFailedOnStop(nsIStreamListener *arg, HttpBaseChannel *chan)
- : mNext(arg)
- , mChannel(chan) {}
- NS_DECL_THREADSAFE_ISUPPORTS
- NS_IMETHOD OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) override
- {
- return mNext->OnStartRequest(aRequest, aContext);
- }
- NS_IMETHOD OnStopRequest(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatusCode) override
- {
- if (NS_FAILED(aStatusCode) && NS_SUCCEEDED(mChannel->mStatus)) {
- LOG(("HttpBaseChannel::InterceptFailedOnStop %p seting status %x", mChannel, aStatusCode));
- mChannel->mStatus = aStatusCode;
- }
- return mNext->OnStopRequest(aRequest, aContext, aStatusCode);
- }
- NS_IMETHOD OnDataAvailable(nsIRequest *aRequest, nsISupports *aContext,
- nsIInputStream *aInputStream, uint64_t aOffset,
- uint32_t aCount) override
- {
- return mNext->OnDataAvailable(aRequest, aContext, aInputStream, aOffset, aCount);
- }
- };
- NS_IMPL_ISUPPORTS(InterceptFailedOnStop, nsIStreamListener, nsIRequestObserver)
- NS_IMETHODIMP
- HttpBaseChannel::DoApplyContentConversions(nsIStreamListener* aNextListener,
- nsIStreamListener** aNewNextListener,
- nsISupports *aCtxt)
- {
- *aNewNextListener = nullptr;
- if (!mResponseHead || ! aNextListener) {
- return NS_OK;
- }
- LOG(("HttpBaseChannel::DoApplyContentConversions [this=%p]\n", this));
- if (!mApplyConversion) {
- LOG(("not applying conversion per mApplyConversion\n"));
- return NS_OK;
- }
- if (!mAvailableCachedAltDataType.IsEmpty()) {
- LOG(("not applying conversion because delivering alt-data\n"));
- return NS_OK;
- }
- nsAutoCString contentEncoding;
- nsresult rv = mResponseHead->GetHeader(nsHttp::Content_Encoding, contentEncoding);
- if (NS_FAILED(rv) || contentEncoding.IsEmpty())
- return NS_OK;
- nsCOMPtr<nsIStreamListener> nextListener = new InterceptFailedOnStop(aNextListener, this);
- // The encodings are listed in the order they were applied
- // (see rfc 2616 section 14.11), so they need to removed in reverse
- // order. This is accomplished because the converter chain ends up
- // being a stack with the last converter created being the first one
- // to accept the raw network data.
- char* cePtr = contentEncoding.BeginWriting();
- uint32_t count = 0;
- while (char* val = nsCRT::strtok(cePtr, HTTP_LWS ",", &cePtr)) {
- if (++count > 16) {
- // That's ridiculous. We only understand 2 different ones :)
- // but for compatibility with old code, we will just carry on without
- // removing the encodings
- LOG(("Too many Content-Encodings. Ignoring remainder.\n"));
- break;
- }
- if (gHttpHandler->IsAcceptableEncoding(val)) {
- nsCOMPtr<nsIStreamConverterService> serv;
- rv = gHttpHandler->GetStreamConverterService(getter_AddRefs(serv));
- // we won't fail to load the page just because we couldn't load the
- // stream converter service.. carry on..
- if (NS_FAILED(rv)) {
- if (val)
- LOG(("Unknown content encoding '%s', ignoring\n", val));
- continue;
- }
- nsCOMPtr<nsIStreamListener> converter;
- nsAutoCString from(val);
- ToLowerCase(from);
- rv = serv->AsyncConvertData(from.get(),
- "uncompressed",
- nextListener,
- aCtxt,
- getter_AddRefs(converter));
- if (NS_FAILED(rv)) {
- LOG(("Unexpected failure of AsyncConvertData %s\n", val));
- return rv;
- }
- LOG(("converter removed '%s' content-encoding\n", val));
- nextListener = converter;
- }
- else {
- if (val)
- LOG(("Unknown content encoding '%s', ignoring\n", val));
- }
- }
- *aNewNextListener = nextListener;
- NS_IF_ADDREF(*aNewNextListener);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetContentEncodings(nsIUTF8StringEnumerator** aEncodings)
- {
- if (!mResponseHead) {
- *aEncodings = nullptr;
- return NS_OK;
- }
- nsAutoCString encoding;
- mResponseHead->GetHeader(nsHttp::Content_Encoding, encoding);
- if (encoding.IsEmpty()) {
- *aEncodings = nullptr;
- return NS_OK;
- }
- nsContentEncodings* enumerator = new nsContentEncodings(this,
- encoding.get());
- NS_ADDREF(*aEncodings = enumerator);
- return NS_OK;
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsContentEncodings <public>
- //-----------------------------------------------------------------------------
- HttpBaseChannel::nsContentEncodings::nsContentEncodings(nsIHttpChannel* aChannel,
- const char* aEncodingHeader)
- : mEncodingHeader(aEncodingHeader)
- , mChannel(aChannel)
- , mReady(false)
- {
- mCurEnd = aEncodingHeader + strlen(aEncodingHeader);
- mCurStart = mCurEnd;
- }
- HttpBaseChannel::nsContentEncodings::~nsContentEncodings()
- {
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsContentEncodings::nsISimpleEnumerator
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpBaseChannel::nsContentEncodings::HasMore(bool* aMoreEncodings)
- {
- if (mReady) {
- *aMoreEncodings = true;
- return NS_OK;
- }
- nsresult rv = PrepareForNext();
- *aMoreEncodings = NS_SUCCEEDED(rv);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::nsContentEncodings::GetNext(nsACString& aNextEncoding)
- {
- aNextEncoding.Truncate();
- if (!mReady) {
- nsresult rv = PrepareForNext();
- if (NS_FAILED(rv)) {
- return NS_ERROR_FAILURE;
- }
- }
- const nsACString & encoding = Substring(mCurStart, mCurEnd);
- nsACString::const_iterator start, end;
- encoding.BeginReading(start);
- encoding.EndReading(end);
- bool haveType = false;
- if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("gzip"), start, end)) {
- aNextEncoding.AssignLiteral(APPLICATION_GZIP);
- haveType = true;
- }
- if (!haveType) {
- encoding.BeginReading(start);
- if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("compress"), start, end)) {
- aNextEncoding.AssignLiteral(APPLICATION_COMPRESS);
- haveType = true;
- }
- }
- if (!haveType) {
- encoding.BeginReading(start);
- if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("deflate"), start, end)) {
- aNextEncoding.AssignLiteral(APPLICATION_ZIP);
- haveType = true;
- }
- }
- if (!haveType) {
- encoding.BeginReading(start);
- if (CaseInsensitiveFindInReadable(NS_LITERAL_CSTRING("br"), start, end)) {
- aNextEncoding.AssignLiteral(APPLICATION_BROTLI);
- haveType = true;
- }
- }
- // Prepare to fetch the next encoding
- mCurEnd = mCurStart;
- mReady = false;
- if (haveType)
- return NS_OK;
- NS_WARNING("Unknown encoding type");
- return NS_ERROR_FAILURE;
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsContentEncodings::nsISupports
- //-----------------------------------------------------------------------------
- NS_IMPL_ISUPPORTS(HttpBaseChannel::nsContentEncodings, nsIUTF8StringEnumerator)
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsContentEncodings <private>
- //-----------------------------------------------------------------------------
- nsresult
- HttpBaseChannel::nsContentEncodings::PrepareForNext(void)
- {
- MOZ_ASSERT(mCurStart == mCurEnd, "Indeterminate state");
- // At this point both mCurStart and mCurEnd point to somewhere
- // past the end of the next thing we want to return
- while (mCurEnd != mEncodingHeader) {
- --mCurEnd;
- if (*mCurEnd != ',' && !nsCRT::IsAsciiSpace(*mCurEnd))
- break;
- }
- if (mCurEnd == mEncodingHeader)
- return NS_ERROR_NOT_AVAILABLE; // no more encodings
- ++mCurEnd;
- // At this point mCurEnd points to the first char _after_ the
- // header we want. Furthermore, mCurEnd - 1 != mEncodingHeader
- mCurStart = mCurEnd - 1;
- while (mCurStart != mEncodingHeader &&
- *mCurStart != ',' && !nsCRT::IsAsciiSpace(*mCurStart))
- --mCurStart;
- if (*mCurStart == ',' || nsCRT::IsAsciiSpace(*mCurStart))
- ++mCurStart; // we stopped because of a weird char, so move up one
- // At this point mCurStart and mCurEnd bracket the encoding string
- // we want. Check that it's not "identity"
- if (Substring(mCurStart, mCurEnd).Equals("identity",
- nsCaseInsensitiveCStringComparator())) {
- mCurEnd = mCurStart;
- return PrepareForNext();
- }
- mReady = true;
- return NS_OK;
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsIHttpChannel
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpBaseChannel::GetChannelId(nsACString& aChannelId)
- {
- char id[NSID_LENGTH];
- mChannelId.ToProvidedString(id);
- aChannelId.AssignASCII(id);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetChannelId(const nsACString& aChannelId)
- {
- nsID newId;
- nsAutoCString idStr(aChannelId);
- if (newId.Parse(idStr.get())) {
- mChannelId = newId;
- return NS_OK;
- }
- return NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP HttpBaseChannel::GetTopLevelContentWindowId(uint64_t *aWindowId)
- {
- if (!mContentWindowId) {
- nsCOMPtr<nsILoadContext> loadContext;
- GetCallback(loadContext);
- if (loadContext) {
- nsCOMPtr<mozIDOMWindowProxy> topWindow;
- loadContext->GetTopWindow(getter_AddRefs(topWindow));
- nsCOMPtr<nsIDOMWindowUtils> windowUtils = do_GetInterface(topWindow);
- if (windowUtils) {
- windowUtils->GetCurrentInnerWindowID(&mContentWindowId);
- }
- }
- }
- *aWindowId = mContentWindowId;
- return NS_OK;
- }
- NS_IMETHODIMP HttpBaseChannel::SetTopLevelContentWindowId(uint64_t aWindowId)
- {
- mContentWindowId = aWindowId;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetTransferSize(uint64_t *aTransferSize)
- {
- *aTransferSize = mTransferSize;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetDecodedBodySize(uint64_t *aDecodedBodySize)
- {
- *aDecodedBodySize = mDecodedBodySize;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetEncodedBodySize(uint64_t *aEncodedBodySize)
- {
- *aEncodedBodySize = mEncodedBodySize;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetRequestMethod(nsACString& aMethod)
- {
- mRequestHead.Method(aMethod);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetRequestMethod(const nsACString& aMethod)
- {
- ENSURE_CALLED_BEFORE_CONNECT();
- const nsCString& flatMethod = PromiseFlatCString(aMethod);
- // Method names are restricted to valid HTTP tokens.
- if (!nsHttp::IsValidToken(flatMethod))
- return NS_ERROR_INVALID_ARG;
- mRequestHead.SetMethod(flatMethod);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetNetworkInterfaceId(nsACString& aNetworkInterfaceId)
- {
- aNetworkInterfaceId = mNetworkInterfaceId;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetNetworkInterfaceId(const nsACString& aNetworkInterfaceId)
- {
- ENSURE_CALLED_BEFORE_CONNECT();
- mNetworkInterfaceId = aNetworkInterfaceId;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetReferrer(nsIURI **referrer)
- {
- NS_ENSURE_ARG_POINTER(referrer);
- *referrer = mReferrer;
- NS_IF_ADDREF(*referrer);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetReferrer(nsIURI *referrer)
- {
- return SetReferrerWithPolicy(referrer, REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE);
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetReferrerPolicy(uint32_t *referrerPolicy)
- {
- NS_ENSURE_ARG_POINTER(referrerPolicy);
- *referrerPolicy = mReferrerPolicy;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetReferrerWithPolicy(nsIURI *referrer,
- uint32_t referrerPolicy)
- {
- ENSURE_CALLED_BEFORE_CONNECT();
- // clear existing referrer, if any
- mReferrer = nullptr;
- nsresult rv = mRequestHead.ClearHeader(nsHttp::Referer);
- if(NS_FAILED(rv)) {
- return rv;
- }
- mReferrerPolicy = REFERRER_POLICY_NO_REFERRER_WHEN_DOWNGRADE;
- if (!referrer) {
- return NS_OK;
- }
- // Don't send referrer at all when the meta referrer setting is "no-referrer"
- if (referrerPolicy == REFERRER_POLICY_NO_REFERRER) {
- mReferrerPolicy = REFERRER_POLICY_NO_REFERRER;
- return NS_OK;
- }
- // 0: never send referer
- // 1: send referer for direct user action
- // 2: always send referer
- uint32_t userReferrerLevel = gHttpHandler->ReferrerLevel();
- // false: use real referrer
- // true: spoof with URI of the current request
- bool userSpoofReferrerSource = gHttpHandler->SpoofReferrerSource();
- // 0: full URI
- // 1: scheme+host+port+path
- // 2: scheme+host+port
- int userReferrerTrimmingPolicy = gHttpHandler->ReferrerTrimmingPolicy();
- // 0: send referer no matter what
- // 1: send referer ONLY when base domains match
- // 2: send referer ONLY when hosts match
- int userReferrerXOriginPolicy = gHttpHandler->ReferrerXOriginPolicy();
- // check referrer blocking pref
- uint32_t referrerLevel;
- if (mLoadFlags & LOAD_INITIAL_DOCUMENT_URI) {
- referrerLevel = 1; // user action
- } else {
- referrerLevel = 2; // inline content
- }
- if (userReferrerLevel < referrerLevel) {
- return NS_OK;
- }
- nsCOMPtr<nsIURI> referrerGrip;
- bool match;
- //
- // Strip off "wyciwyg://123/" from wyciwyg referrers.
- //
- // XXX this really belongs elsewhere since wyciwyg URLs aren't part of necko.
- // perhaps some sort of generic nsINestedURI could be used. then, if an URI
- // fails the whitelist test, then we could check for an inner URI and try
- // that instead. though, that might be too automatic.
- //
- rv = referrer->SchemeIs("wyciwyg", &match);
- if (NS_FAILED(rv)) return rv;
- if (match) {
- nsAutoCString path;
- rv = referrer->GetPath(path);
- if (NS_FAILED(rv)) return rv;
- uint32_t pathLength = path.Length();
- if (pathLength <= 2) return NS_ERROR_FAILURE;
- // Path is of the form "//123/http://foo/bar", with a variable number of
- // digits. To figure out where the "real" URL starts, search path for a
- // '/', starting at the third character.
- int32_t slashIndex = path.FindChar('/', 2);
- if (slashIndex == kNotFound) return NS_ERROR_FAILURE;
- // Get charset of the original URI so we can pass it to our fixed up URI.
- nsAutoCString charset;
- referrer->GetOriginCharset(charset);
- // Replace |referrer| with a URI without wyciwyg://123/.
- rv = NS_NewURI(getter_AddRefs(referrerGrip),
- Substring(path, slashIndex + 1, pathLength - slashIndex - 1),
- charset.get());
- if (NS_FAILED(rv)) return rv;
- referrer = referrerGrip.get();
- }
- //
- // block referrer if not on our white list...
- //
- static const char *const referrerWhiteList[] = {
- "http",
- "https",
- "ftp",
- nullptr
- };
- match = false;
- const char *const *scheme = referrerWhiteList;
- for (; *scheme && !match; ++scheme) {
- rv = referrer->SchemeIs(*scheme, &match);
- if (NS_FAILED(rv)) return rv;
- }
- if (!match) return NS_OK; // kick out....
- //
- // Handle secure referrals.
- //
- // Support referrals from a secure server if this is a secure site
- // and (optionally) if the host names are the same.
- //
- rv = referrer->SchemeIs("https", &match);
- if (NS_FAILED(rv)) return rv;
- if (match) {
- rv = mURI->SchemeIs("https", &match);
- if (NS_FAILED(rv)) return rv;
- // It's ok to send referrer for https-to-http scenarios if the referrer
- // policy is "unsafe-url", "origin", or "origin-when-cross-origin".
- if (referrerPolicy != REFERRER_POLICY_UNSAFE_URL &&
- referrerPolicy != REFERRER_POLICY_ORIGIN_WHEN_XORIGIN &&
- referrerPolicy != REFERRER_POLICY_ORIGIN) {
- // in other referrer policies, https->http is not allowed...
- if (!match) return NS_OK;
- }
- }
- // for cross-origin-based referrer changes (not just host-based), figure out
- // if the referrer is being sent cross-origin.
- nsCOMPtr<nsIURI> triggeringURI;
- bool isCrossOrigin = true;
- if (mLoadInfo) {
- nsCOMPtr<nsIPrincipal> triggeringPrincipal = mLoadInfo->TriggeringPrincipal();
- if (triggeringPrincipal) {
- triggeringPrincipal->GetURI(getter_AddRefs(triggeringURI));
- }
- }
- if (triggeringURI) {
- if (LOG_ENABLED()) {
- nsAutoCString triggeringURISpec;
- rv = triggeringURI->GetAsciiSpec(triggeringURISpec);
- if (!NS_FAILED(rv)) {
- LOG(("triggeringURI=%s\n", triggeringURISpec.get()));
- }
- }
- nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
- rv = ssm->CheckSameOriginURI(triggeringURI, mURI, false);
- isCrossOrigin = NS_FAILED(rv);
- } else {
- LOG(("no triggering principal available via loadInfo, assuming load is cross-origin"));
- }
- // Don't send referrer when the request is cross-origin and policy is "same-origin".
- if (isCrossOrigin && referrerPolicy == REFERRER_POLICY_SAME_ORIGIN) {
- mReferrerPolicy = REFERRER_POLICY_SAME_ORIGIN;
- return NS_OK;
- }
- nsCOMPtr<nsIURI> clone;
- //
- // we need to clone the referrer, so we can:
- // (1) modify it
- // (2) keep a reference to it after returning from this function
- //
- // Use CloneIgnoringRef to strip away any fragment per RFC 2616 section 14.36
- // and Referrer Policy section 6.3.5.
- rv = referrer->CloneIgnoringRef(getter_AddRefs(clone));
- if (NS_FAILED(rv)) return rv;
- nsAutoCString currentHost;
- nsAutoCString referrerHost;
- rv = mURI->GetAsciiHost(currentHost);
- if (NS_FAILED(rv)) return rv;
- rv = clone->GetAsciiHost(referrerHost);
- if (NS_FAILED(rv)) return rv;
- // check policy for sending ref only when hosts match
- if (userReferrerXOriginPolicy == 2 && !currentHost.Equals(referrerHost))
- return NS_OK;
- if (userReferrerXOriginPolicy == 1) {
- nsAutoCString currentDomain = currentHost;
- nsAutoCString referrerDomain = referrerHost;
- uint32_t extraDomains = 0;
- nsCOMPtr<nsIEffectiveTLDService> eTLDService = do_GetService(
- NS_EFFECTIVETLDSERVICE_CONTRACTID);
- if (eTLDService) {
- rv = eTLDService->GetBaseDomain(mURI, extraDomains, currentDomain);
- if (NS_FAILED(rv)) return rv;
- rv = eTLDService->GetBaseDomain(clone, extraDomains, referrerDomain);
- if (NS_FAILED(rv)) return rv;
- }
- // check policy for sending only when effective top level domain matches.
- // this falls back on using host if eTLDService does not work
- if (!currentDomain.Equals(referrerDomain))
- return NS_OK;
- }
- // send spoofed referrer if desired
- if (userSpoofReferrerSource) {
- nsCOMPtr<nsIURI> mURIclone;
- rv = mURI->CloneIgnoringRef(getter_AddRefs(mURIclone));
- if (NS_FAILED(rv)) return rv;
- clone = mURIclone;
- currentHost = referrerHost;
- }
- // strip away any userpass; we don't want to be giving out passwords ;-)
- // This is required by Referrer Policy stripping algorithm.
- rv = clone->SetUserPass(EmptyCString());
- if (NS_FAILED(rv)) return rv;
- nsAutoCString spec;
- // Apply the user cross-origin trimming policy if it's more
- // restrictive than the general one.
- if (isCrossOrigin) {
- int userReferrerXOriginTrimmingPolicy =
- gHttpHandler->ReferrerXOriginTrimmingPolicy();
- userReferrerTrimmingPolicy =
- std::max(userReferrerTrimmingPolicy, userReferrerXOriginTrimmingPolicy);
- }
- // site-specified referrer trimming may affect the trim level
- // "unsafe-url" behaves like "origin" (send referrer in the same situations) but
- // "unsafe-url" sends the whole referrer and origin removes the path.
- // "origin-when-cross-origin" trims the referrer only when the request is
- // cross-origin.
- // "Strict" request from https->http case was bailed out, so here:
- // "strict-origin" behaves the same as "origin".
- // "strict-origin-when-cross-origin" behaves the same as "origin-when-cross-origin"
- if (referrerPolicy == REFERRER_POLICY_ORIGIN ||
- referrerPolicy == REFERRER_POLICY_STRICT_ORIGIN ||
- (isCrossOrigin && (referrerPolicy == REFERRER_POLICY_ORIGIN_WHEN_XORIGIN ||
- referrerPolicy == REFERRER_POLICY_STRICT_ORIGIN_WHEN_XORIGIN))) {
- // We can override the user trimming preference because "origin"
- // (network.http.referer.trimmingPolicy = 2) is the strictest
- // trimming policy that users can specify.
- userReferrerTrimmingPolicy = 2;
- }
- // check how much referer to send
- if (userReferrerTrimmingPolicy) {
- // All output strings start with: scheme+host+port
- // We want the IDN-normalized PrePath. That's not something currently
- // available and there doesn't yet seem to be justification for adding it to
- // the interfaces, so just build it up ourselves from scheme+AsciiHostPort
- nsAutoCString scheme, asciiHostPort;
- rv = clone->GetScheme(scheme);
- if (NS_FAILED(rv)) return rv;
- spec = scheme;
- spec.AppendLiteral("://");
- // Note we explicitly cleared UserPass above, so do not need to build it.
- rv = clone->GetAsciiHostPort(asciiHostPort);
- if (NS_FAILED(rv)) return rv;
- spec.Append(asciiHostPort);
- switch (userReferrerTrimmingPolicy) {
- case 1: { // scheme+host+port+path
- nsCOMPtr<nsIURL> url(do_QueryInterface(clone));
- if (url) {
- nsAutoCString path;
- rv = url->GetFilePath(path);
- if (NS_FAILED(rv)) return rv;
- spec.Append(path);
- rv = url->SetQuery(EmptyCString());
- if (NS_FAILED(rv)) return rv;
- rv = url->SetRef(EmptyCString());
- if (NS_FAILED(rv)) return rv;
- break;
- }
- // No URL, so fall through to truncating the path and any query/ref off
- // as well.
- }
- MOZ_FALLTHROUGH;
- default: // (Pref limited to [0,2] enforced by clamp, MOZ_CRASH overkill.)
- case 2: // scheme+host+port+/
- spec.AppendLiteral("/");
- // This nukes any query/ref present as well in the case of nsStandardURL
- rv = clone->SetPath(EmptyCString());
- if (NS_FAILED(rv)) return rv;
- break;
- }
- } else {
- // use the full URI
- rv = clone->GetAsciiSpec(spec);
- if (NS_FAILED(rv)) return rv;
- }
- // finally, remember the referrer URI and set the Referer header.
- rv = SetRequestHeader(NS_LITERAL_CSTRING("Referer"), spec, false);
- if (NS_FAILED(rv)) return rv;
- mReferrer = clone;
- mReferrerPolicy = referrerPolicy;
- return NS_OK;
- }
- // Return the channel's proxy URI, or if it doesn't exist, the
- // channel's main URI.
- NS_IMETHODIMP
- HttpBaseChannel::GetProxyURI(nsIURI **aOut)
- {
- NS_ENSURE_ARG_POINTER(aOut);
- nsCOMPtr<nsIURI> result(mProxyURI);
- result.forget(aOut);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetRequestHeader(const nsACString& aHeader,
- nsACString& aValue)
- {
- aValue.Truncate();
- // XXX might be better to search the header list directly instead of
- // hitting the http atom hash table.
- nsHttpAtom atom = nsHttp::ResolveAtom(aHeader);
- if (!atom)
- return NS_ERROR_NOT_AVAILABLE;
- return mRequestHead.GetHeader(atom, aValue);
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetRequestHeader(const nsACString& aHeader,
- const nsACString& aValue,
- bool aMerge)
- {
- const nsCString &flatHeader = PromiseFlatCString(aHeader);
- const nsCString &flatValue = PromiseFlatCString(aValue);
- LOG(("HttpBaseChannel::SetRequestHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n",
- this, flatHeader.get(), flatValue.get(), aMerge));
- // Verify header names are valid HTTP tokens and header values are reasonably
- // close to whats allowed in RFC 2616.
- if (!nsHttp::IsValidToken(flatHeader) ||
- !nsHttp::IsReasonableHeaderValue(flatValue)) {
- return NS_ERROR_INVALID_ARG;
- }
- return mRequestHead.SetHeader(aHeader, flatValue, aMerge);
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetEmptyRequestHeader(const nsACString& aHeader)
- {
- const nsCString &flatHeader = PromiseFlatCString(aHeader);
- LOG(("HttpBaseChannel::SetEmptyRequestHeader [this=%p header=\"%s\"]\n",
- this, flatHeader.get()));
- // Verify header names are valid HTTP tokens and header values are reasonably
- // close to whats allowed in RFC 2616.
- if (!nsHttp::IsValidToken(flatHeader)) {
- return NS_ERROR_INVALID_ARG;
- }
- return mRequestHead.SetEmptyHeader(aHeader);
- }
- NS_IMETHODIMP
- HttpBaseChannel::VisitRequestHeaders(nsIHttpHeaderVisitor *visitor)
- {
- return mRequestHead.VisitHeaders(visitor);
- }
- NS_IMETHODIMP
- HttpBaseChannel::VisitNonDefaultRequestHeaders(nsIHttpHeaderVisitor *visitor)
- {
- return mRequestHead.VisitHeaders(visitor,
- nsHttpHeaderArray::eFilterSkipDefault);
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetResponseHeader(const nsACString &header, nsACString &value)
- {
- value.Truncate();
- if (!mResponseHead)
- return NS_ERROR_NOT_AVAILABLE;
- nsHttpAtom atom = nsHttp::ResolveAtom(header);
- if (!atom)
- return NS_ERROR_NOT_AVAILABLE;
- return mResponseHead->GetHeader(atom, value);
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetResponseHeader(const nsACString& header,
- const nsACString& value,
- bool merge)
- {
- LOG(("HttpBaseChannel::SetResponseHeader [this=%p header=\"%s\" value=\"%s\" merge=%u]\n",
- this, PromiseFlatCString(header).get(), PromiseFlatCString(value).get(), merge));
- if (!mResponseHead)
- return NS_ERROR_NOT_AVAILABLE;
- nsHttpAtom atom = nsHttp::ResolveAtom(header);
- if (!atom)
- return NS_ERROR_NOT_AVAILABLE;
- // these response headers must not be changed
- if (atom == nsHttp::Content_Type ||
- atom == nsHttp::Content_Length ||
- atom == nsHttp::Content_Encoding ||
- atom == nsHttp::Trailer ||
- atom == nsHttp::Transfer_Encoding)
- return NS_ERROR_ILLEGAL_VALUE;
- mResponseHeadersModified = true;
- return mResponseHead->SetHeader(header, value, merge);
- }
- NS_IMETHODIMP
- HttpBaseChannel::VisitResponseHeaders(nsIHttpHeaderVisitor *visitor)
- {
- if (!mResponseHead) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- return mResponseHead->VisitHeaders(visitor,
- nsHttpHeaderArray::eFilterResponse);
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetOriginalResponseHeader(const nsACString& aHeader,
- nsIHttpHeaderVisitor *aVisitor)
- {
- if (!mResponseHead) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- nsHttpAtom atom = nsHttp::ResolveAtom(aHeader);
- if (!atom) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- return mResponseHead->GetOriginalHeader(atom, aVisitor);
- }
- NS_IMETHODIMP
- HttpBaseChannel::VisitOriginalResponseHeaders(nsIHttpHeaderVisitor *aVisitor)
- {
- if (!mResponseHead) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- return mResponseHead->VisitHeaders(aVisitor,
- nsHttpHeaderArray::eFilterResponseOriginal);
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetAllowPipelining(bool *value)
- {
- NS_ENSURE_ARG_POINTER(value);
- *value = mAllowPipelining;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetAllowPipelining(bool value)
- {
- ENSURE_CALLED_BEFORE_CONNECT();
- mAllowPipelining = value;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetAllowSTS(bool *value)
- {
- NS_ENSURE_ARG_POINTER(value);
- *value = mAllowSTS;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetAllowSTS(bool value)
- {
- ENSURE_CALLED_BEFORE_CONNECT();
- mAllowSTS = value;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetRedirectionLimit(uint32_t *value)
- {
- NS_ENSURE_ARG_POINTER(value);
- *value = mRedirectionLimit;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetRedirectionLimit(uint32_t value)
- {
- ENSURE_CALLED_BEFORE_CONNECT();
- mRedirectionLimit = std::min<uint32_t>(value, 0xff);
- return NS_OK;
- }
- nsresult
- HttpBaseChannel::OverrideSecurityInfo(nsISupports* aSecurityInfo)
- {
- MOZ_ASSERT(!mSecurityInfo,
- "This can only be called when we don't have a security info object already");
- MOZ_RELEASE_ASSERT(aSecurityInfo,
- "This can only be called with a valid security info object");
- MOZ_ASSERT(!BypassServiceWorker(),
- "This can only be called on channels that are not bypassing interception");
- MOZ_ASSERT(mResponseCouldBeSynthesized,
- "This can only be called on channels that can be intercepted");
- if (mSecurityInfo) {
- LOG(("HttpBaseChannel::OverrideSecurityInfo mSecurityInfo is null! "
- "[this=%p]\n", this));
- return NS_ERROR_UNEXPECTED;
- }
- if (!mResponseCouldBeSynthesized) {
- LOG(("HttpBaseChannel::OverrideSecurityInfo channel cannot be intercepted! "
- "[this=%p]\n", this));
- return NS_ERROR_UNEXPECTED;
- }
- mSecurityInfo = aSecurityInfo;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::IsNoStoreResponse(bool *value)
- {
- if (!mResponseHead)
- return NS_ERROR_NOT_AVAILABLE;
- *value = mResponseHead->NoStore();
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::IsNoCacheResponse(bool *value)
- {
- if (!mResponseHead)
- return NS_ERROR_NOT_AVAILABLE;
- *value = mResponseHead->NoCache();
- if (!*value)
- *value = mResponseHead->ExpiresInPast();
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::IsPrivateResponse(bool *value)
- {
- if (!mResponseHead)
- return NS_ERROR_NOT_AVAILABLE;
- *value = mResponseHead->Private();
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetResponseStatus(uint32_t *aValue)
- {
- if (!mResponseHead)
- return NS_ERROR_NOT_AVAILABLE;
- *aValue = mResponseHead->Status();
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetResponseStatusText(nsACString& aValue)
- {
- if (!mResponseHead)
- return NS_ERROR_NOT_AVAILABLE;
- mResponseHead->StatusText(aValue);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetRequestSucceeded(bool *aValue)
- {
- if (!mResponseHead)
- return NS_ERROR_NOT_AVAILABLE;
- uint32_t status = mResponseHead->Status();
- *aValue = (status / 100 == 2);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::RedirectTo(nsIURI *targetURI)
- {
- // We cannot redirect after OnStartRequest of the listener
- // has been called, since to redirect we have to switch channels
- // and the dance with OnStartRequest et al has to start over.
- // This would break the nsIStreamListener contract.
- NS_ENSURE_FALSE(mOnStartRequestCalled, NS_ERROR_NOT_AVAILABLE);
- mAPIRedirectToURI = targetURI;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetRequestContextID(nsID *aRCID)
- {
- NS_ENSURE_ARG_POINTER(aRCID);
- *aRCID = mRequestContextID;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetRequestContextID(const nsID aRCID)
- {
- mRequestContextID = aRCID;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetIsMainDocumentChannel(bool* aValue)
- {
- NS_ENSURE_ARG_POINTER(aValue);
- *aValue = mForceMainDocumentChannel || (mLoadFlags & LOAD_DOCUMENT_URI);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetIsMainDocumentChannel(bool aValue)
- {
- mForceMainDocumentChannel = aValue;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetProtocolVersion(nsACString& aProtocolVersion)
- {
- nsresult rv;
- nsCOMPtr<nsISSLSocketControl> ssl = do_QueryInterface(mSecurityInfo, &rv);
- nsAutoCString protocol;
- if (NS_SUCCEEDED(rv) && ssl &&
- NS_SUCCEEDED(ssl->GetNegotiatedNPN(protocol)) &&
- !protocol.IsEmpty()) {
- // The negotiated protocol was not empty so we can use it.
- aProtocolVersion = protocol;
- return NS_OK;
- }
- if (mResponseHead) {
- uint32_t version = mResponseHead->Version();
- aProtocolVersion.Assign(nsHttp::GetProtocolVersion(version));
- return NS_OK;
- }
- return NS_ERROR_NOT_AVAILABLE;
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsIHttpChannelInternal
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpBaseChannel::GetTopWindowURI(nsIURI **aTopWindowURI)
- {
- nsresult rv = NS_OK;
- nsCOMPtr<mozIThirdPartyUtil> util;
- // Only compute the top window URI once. In e10s, this must be computed in the
- // child. The parent gets the top window URI through HttpChannelOpenArgs.
- if (!mTopWindowURI) {
- util = do_GetService(THIRDPARTYUTIL_CONTRACTID);
- if (!util) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- nsCOMPtr<mozIDOMWindowProxy> win;
- rv = util->GetTopWindowForChannel(this, getter_AddRefs(win));
- if (NS_SUCCEEDED(rv)) {
- rv = util->GetURIFromWindow(win, getter_AddRefs(mTopWindowURI));
- #if DEBUG
- if (mTopWindowURI) {
- nsCString spec;
- if (NS_SUCCEEDED(mTopWindowURI->GetSpec(spec))) {
- LOG(("HttpChannelBase::Setting topwindow URI spec %s [this=%p]\n",
- spec.get(), this));
- }
- }
- #endif
- }
- }
- NS_IF_ADDREF(*aTopWindowURI = mTopWindowURI);
- return rv;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetDocumentURI(nsIURI **aDocumentURI)
- {
- NS_ENSURE_ARG_POINTER(aDocumentURI);
- *aDocumentURI = mDocumentURI;
- NS_IF_ADDREF(*aDocumentURI);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetDocumentURI(nsIURI *aDocumentURI)
- {
- ENSURE_CALLED_BEFORE_CONNECT();
- mDocumentURI = aDocumentURI;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetRequestVersion(uint32_t *major, uint32_t *minor)
- {
- nsHttpVersion version = mRequestHead.Version();
- if (major) { *major = version / 10; }
- if (minor) { *minor = version % 10; }
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetResponseVersion(uint32_t *major, uint32_t *minor)
- {
- if (!mResponseHead)
- {
- *major = *minor = 0; // we should at least be kind about it
- return NS_ERROR_NOT_AVAILABLE;
- }
- nsHttpVersion version = mResponseHead->Version();
- if (major) { *major = version / 10; }
- if (minor) { *minor = version % 10; }
- return NS_OK;
- }
- void
- HttpBaseChannel::NotifySetCookie(char const *aCookie)
- {
- nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
- if (obs) {
- nsAutoString cookie;
- CopyASCIItoUTF16(aCookie, cookie);
- obs->NotifyObservers(static_cast<nsIChannel*>(this),
- "http-on-response-set-cookie",
- cookie.get());
- }
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetCookie(const char *aCookieHeader)
- {
- if (mLoadFlags & LOAD_ANONYMOUS)
- return NS_OK;
- // empty header isn't an error
- if (!(aCookieHeader && *aCookieHeader))
- return NS_OK;
- nsICookieService *cs = gHttpHandler->GetCookieService();
- NS_ENSURE_TRUE(cs, NS_ERROR_FAILURE);
- nsAutoCString date;
- mResponseHead->GetHeader(nsHttp::Date, date);
- nsresult rv =
- cs->SetCookieStringFromHttp(mURI, nullptr, nullptr, aCookieHeader,
- date.get(), this);
- if (NS_SUCCEEDED(rv)) {
- NotifySetCookie(aCookieHeader);
- }
- return rv;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetThirdPartyFlags(uint32_t *aFlags)
- {
- *aFlags = mThirdPartyFlags;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetThirdPartyFlags(uint32_t aFlags)
- {
- ENSURE_CALLED_BEFORE_ASYNC_OPEN();
- mThirdPartyFlags = aFlags;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetForceAllowThirdPartyCookie(bool *aForce)
- {
- *aForce = !!(mThirdPartyFlags & nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetForceAllowThirdPartyCookie(bool aForce)
- {
- ENSURE_CALLED_BEFORE_ASYNC_OPEN();
- if (aForce)
- mThirdPartyFlags |= nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW;
- else
- mThirdPartyFlags &= ~nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetCanceled(bool *aCanceled)
- {
- *aCanceled = mCanceled;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetChannelIsForDownload(bool *aChannelIsForDownload)
- {
- *aChannelIsForDownload = mChannelIsForDownload;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetChannelIsForDownload(bool aChannelIsForDownload)
- {
- mChannelIsForDownload = aChannelIsForDownload;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetCacheKeysRedirectChain(nsTArray<nsCString> *cacheKeys)
- {
- mRedirectedCachekeys = cacheKeys;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetLocalAddress(nsACString& addr)
- {
- if (mSelfAddr.raw.family == PR_AF_UNSPEC)
- return NS_ERROR_NOT_AVAILABLE;
- addr.SetCapacity(kIPv6CStrBufSize);
- NetAddrToString(&mSelfAddr, addr.BeginWriting(), kIPv6CStrBufSize);
- addr.SetLength(strlen(addr.BeginReading()));
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::TakeAllSecurityMessages(
- nsCOMArray<nsISecurityConsoleMessage> &aMessages)
- {
- aMessages.Clear();
- aMessages.SwapElements(mSecurityConsoleMessages);
- return NS_OK;
- }
- /* Please use this method with care. This can cause the message
- * queue to grow large and cause the channel to take up a lot
- * of memory. Use only static string messages and do not add
- * server side data to the queue, as that can be large.
- * Add only a limited number of messages to the queue to keep
- * the channel size down and do so only in rare erroneous situations.
- * More information can be found here:
- * https://bugzilla.mozilla.org/show_bug.cgi?id=846918
- */
- nsresult
- HttpBaseChannel::AddSecurityMessage(const nsAString &aMessageTag,
- const nsAString &aMessageCategory)
- {
- nsresult rv;
- nsCOMPtr<nsISecurityConsoleMessage> message =
- do_CreateInstance(NS_SECURITY_CONSOLE_MESSAGE_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- message->SetTag(aMessageTag);
- message->SetCategory(aMessageCategory);
- mSecurityConsoleMessages.AppendElement(message);
- nsCOMPtr<nsIConsoleService> console(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
- if (!console) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsILoadInfo> loadInfo;
- GetLoadInfo(getter_AddRefs(loadInfo));
- if (!loadInfo) {
- return NS_ERROR_FAILURE;
- }
- uint32_t innerWindowID = loadInfo->GetInnerWindowID();
- nsXPIDLString errorText;
- rv = nsContentUtils::GetLocalizedString(
- nsContentUtils::eSECURITY_PROPERTIES,
- NS_ConvertUTF16toUTF8(aMessageTag).get(),
- errorText);
- NS_ENSURE_SUCCESS(rv, rv);
- nsAutoCString spec;
- if (mURI) {
- spec = mURI->GetSpecOrDefault();
- }
- nsCOMPtr<nsIScriptError> error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID));
- error->InitWithWindowID(errorText, NS_ConvertUTF8toUTF16(spec),
- EmptyString(), 0, 0, nsIScriptError::warningFlag,
- NS_ConvertUTF16toUTF8(aMessageCategory),
- innerWindowID);
- console->LogMessage(error);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetLocalPort(int32_t* port)
- {
- NS_ENSURE_ARG_POINTER(port);
- if (mSelfAddr.raw.family == PR_AF_INET) {
- *port = (int32_t)ntohs(mSelfAddr.inet.port);
- }
- else if (mSelfAddr.raw.family == PR_AF_INET6) {
- *port = (int32_t)ntohs(mSelfAddr.inet6.port);
- }
- else
- return NS_ERROR_NOT_AVAILABLE;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetRemoteAddress(nsACString& addr)
- {
- if (mPeerAddr.raw.family == PR_AF_UNSPEC)
- return NS_ERROR_NOT_AVAILABLE;
- addr.SetCapacity(kIPv6CStrBufSize);
- NetAddrToString(&mPeerAddr, addr.BeginWriting(), kIPv6CStrBufSize);
- addr.SetLength(strlen(addr.BeginReading()));
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetRemotePort(int32_t* port)
- {
- NS_ENSURE_ARG_POINTER(port);
- if (mPeerAddr.raw.family == PR_AF_INET) {
- *port = (int32_t)ntohs(mPeerAddr.inet.port);
- }
- else if (mPeerAddr.raw.family == PR_AF_INET6) {
- *port = (int32_t)ntohs(mPeerAddr.inet6.port);
- }
- else
- return NS_ERROR_NOT_AVAILABLE;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::HTTPUpgrade(const nsACString &aProtocolName,
- nsIHttpUpgradeListener *aListener)
- {
- NS_ENSURE_ARG(!aProtocolName.IsEmpty());
- NS_ENSURE_ARG_POINTER(aListener);
- mUpgradeProtocol = aProtocolName;
- mUpgradeProtocolCallback = aListener;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetAllowSpdy(bool *aAllowSpdy)
- {
- NS_ENSURE_ARG_POINTER(aAllowSpdy);
- *aAllowSpdy = mAllowSpdy;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetAllowSpdy(bool aAllowSpdy)
- {
- mAllowSpdy = aAllowSpdy;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetAllowAltSvc(bool *aAllowAltSvc)
- {
- NS_ENSURE_ARG_POINTER(aAllowAltSvc);
- *aAllowAltSvc = mAllowAltSvc;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetAllowAltSvc(bool aAllowAltSvc)
- {
- mAllowAltSvc = aAllowAltSvc;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetBeConservative(bool *aBeConservative)
- {
- NS_ENSURE_ARG_POINTER(aBeConservative);
- *aBeConservative = mBeConservative;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetBeConservative(bool aBeConservative)
- {
- mBeConservative = aBeConservative;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetApiRedirectToURI(nsIURI ** aResult)
- {
- NS_ENSURE_ARG_POINTER(aResult);
- NS_IF_ADDREF(*aResult = mAPIRedirectToURI);
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetResponseTimeoutEnabled(bool *aEnable)
- {
- if (NS_WARN_IF(!aEnable)) {
- return NS_ERROR_NULL_POINTER;
- }
- *aEnable = mResponseTimeoutEnabled;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetResponseTimeoutEnabled(bool aEnable)
- {
- mResponseTimeoutEnabled = aEnable;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetInitialRwin(uint32_t *aRwin)
- {
- if (NS_WARN_IF(!aRwin)) {
- return NS_ERROR_NULL_POINTER;
- }
- *aRwin = mInitialRwin;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetInitialRwin(uint32_t aRwin)
- {
- ENSURE_CALLED_BEFORE_CONNECT();
- mInitialRwin = aRwin;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::ForcePending(bool aForcePending)
- {
- mForcePending = aForcePending;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetLastModifiedTime(PRTime* lastModifiedTime)
- {
- if (!mResponseHead)
- return NS_ERROR_NOT_AVAILABLE;
- uint32_t lastMod;
- mResponseHead->GetLastModifiedValue(&lastMod);
- *lastModifiedTime = lastMod;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetCorsIncludeCredentials(bool* aInclude)
- {
- *aInclude = mCorsIncludeCredentials;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetCorsIncludeCredentials(bool aInclude)
- {
- mCorsIncludeCredentials = aInclude;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetCorsMode(uint32_t* aMode)
- {
- *aMode = mCorsMode;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetCorsMode(uint32_t aMode)
- {
- mCorsMode = aMode;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetRedirectMode(uint32_t* aMode)
- {
- *aMode = mRedirectMode;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetRedirectMode(uint32_t aMode)
- {
- mRedirectMode = aMode;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetFetchCacheMode(uint32_t* aFetchCacheMode)
- {
- NS_ENSURE_ARG_POINTER(aFetchCacheMode);
- // If the fetch cache mode is overriden, then use it directly.
- if (mFetchCacheMode != nsIHttpChannelInternal::FETCH_CACHE_MODE_DEFAULT) {
- *aFetchCacheMode = mFetchCacheMode;
- return NS_OK;
- }
- // Otherwise try to guess an appropriate cache mode from the load flags.
- if (mLoadFlags & (INHIBIT_CACHING | LOAD_BYPASS_CACHE)) {
- *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_STORE;
- } else if (mLoadFlags & LOAD_BYPASS_CACHE) {
- *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_RELOAD;
- } else if (mLoadFlags & VALIDATE_ALWAYS) {
- *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_CACHE;
- } else if (mLoadFlags & (VALIDATE_NEVER | nsICachingChannel::LOAD_ONLY_FROM_CACHE)) {
- *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_ONLY_IF_CACHED;
- } else if (mLoadFlags & VALIDATE_NEVER) {
- *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_FORCE_CACHE;
- } else {
- *aFetchCacheMode = nsIHttpChannelInternal::FETCH_CACHE_MODE_DEFAULT;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetFetchCacheMode(uint32_t aFetchCacheMode)
- {
- ENSURE_CALLED_BEFORE_CONNECT();
- MOZ_ASSERT(mFetchCacheMode == nsIHttpChannelInternal::FETCH_CACHE_MODE_DEFAULT,
- "SetFetchCacheMode() should only be called once per channel");
- mFetchCacheMode = aFetchCacheMode;
- // Now, set the load flags that implement each cache mode.
- switch (mFetchCacheMode) {
- case nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_STORE:
- // no-store means don't consult the cache on the way to the network, and
- // don't store the response in the cache even if it's cacheable.
- mLoadFlags |= INHIBIT_CACHING | LOAD_BYPASS_CACHE;
- break;
- case nsIHttpChannelInternal::FETCH_CACHE_MODE_RELOAD:
- // reload means don't consult the cache on the way to the network, but
- // do store the response in the cache if possible.
- mLoadFlags |= LOAD_BYPASS_CACHE;
- break;
- case nsIHttpChannelInternal::FETCH_CACHE_MODE_NO_CACHE:
- // no-cache means always validate what's in the cache.
- mLoadFlags |= VALIDATE_ALWAYS;
- break;
- case nsIHttpChannelInternal::FETCH_CACHE_MODE_FORCE_CACHE:
- // force-cache means don't validate unless if the response would vary.
- mLoadFlags |= VALIDATE_NEVER;
- break;
- case nsIHttpChannelInternal::FETCH_CACHE_MODE_ONLY_IF_CACHED:
- // only-if-cached means only from cache, no network, no validation, generate
- // a network error if the document was't in the cache.
- // The privacy implications of these flags (making it fast/easy to check if
- // the user has things in their cache without any network traffic side
- // effects) are addressed in the Request constructor which enforces/requires
- // same-origin request mode.
- mLoadFlags |= VALIDATE_NEVER | nsICachingChannel::LOAD_ONLY_FROM_CACHE;
- break;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetIntegrityMetadata(const nsAString& aIntegrityMetadata)
- {
- mIntegrityMetadata = aIntegrityMetadata;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetIntegrityMetadata(nsAString& aIntegrityMetadata)
- {
- aIntegrityMetadata = mIntegrityMetadata;
- return NS_OK;
- }
- mozilla::net::nsHttpChannel*
- HttpBaseChannel::QueryHttpChannelImpl(void)
- {
- return nullptr;
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsISupportsPriority
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpBaseChannel::GetPriority(int32_t *value)
- {
- *value = mPriority;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::AdjustPriority(int32_t delta)
- {
- return SetPriority(mPriority + delta);
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsIResumableChannel
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpBaseChannel::GetEntityID(nsACString& aEntityID)
- {
- // Don't return an entity ID for Non-GET requests which require
- // additional data
- if (!mRequestHead.IsGet()) {
- return NS_ERROR_NOT_RESUMABLE;
- }
- uint64_t size = UINT64_MAX;
- nsAutoCString etag, lastmod;
- if (mResponseHead) {
- // Don't return an entity if the server sent the following header:
- // Accept-Ranges: none
- // Not sending the Accept-Ranges header means we can still try
- // sending range requests.
- nsAutoCString acceptRanges;
- mResponseHead->GetHeader(nsHttp::Accept_Ranges, acceptRanges);
- if (!acceptRanges.IsEmpty() &&
- !nsHttp::FindToken(acceptRanges.get(), "bytes", HTTP_HEADER_VALUE_SEPS)) {
- return NS_ERROR_NOT_RESUMABLE;
- }
- size = mResponseHead->TotalEntitySize();
- mResponseHead->GetHeader(nsHttp::Last_Modified, lastmod);
- mResponseHead->GetHeader(nsHttp::ETag, etag);
- }
- nsCString entityID;
- NS_EscapeURL(etag.BeginReading(), etag.Length(), esc_AlwaysCopy |
- esc_FileBaseName | esc_Forced, entityID);
- entityID.Append('/');
- entityID.AppendInt(int64_t(size));
- entityID.Append('/');
- entityID.Append(lastmod);
- // NOTE: Appending lastmod as the last part avoids having to escape it
- aEntityID = entityID;
- return NS_OK;
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsIConsoleReportCollector
- //-----------------------------------------------------------------------------
- void
- HttpBaseChannel::AddConsoleReport(uint32_t aErrorFlags,
- const nsACString& aCategory,
- nsContentUtils::PropertiesFile aPropertiesFile,
- const nsACString& aSourceFileURI,
- uint32_t aLineNumber, uint32_t aColumnNumber,
- const nsACString& aMessageName,
- const nsTArray<nsString>& aStringParams)
- {
- mReportCollector->AddConsoleReport(aErrorFlags, aCategory, aPropertiesFile,
- aSourceFileURI, aLineNumber,
- aColumnNumber, aMessageName,
- aStringParams);
- }
- void
- HttpBaseChannel::FlushConsoleReports(nsIDocument* aDocument,
- ReportAction aAction)
- {
- mReportCollector->FlushConsoleReports(aDocument, aAction);
- }
- void
- HttpBaseChannel::FlushConsoleReports(nsIConsoleReportCollector* aCollector)
- {
- mReportCollector->FlushConsoleReports(aCollector);
- }
- void
- HttpBaseChannel::FlushReportsByWindowId(uint64_t aWindowId,
- ReportAction aAction)
- {
- mReportCollector->FlushReportsByWindowId(aWindowId, aAction);
- }
- void
- HttpBaseChannel::ClearConsoleReports()
- {
- mReportCollector->ClearConsoleReports();
- }
- nsIPrincipal *
- HttpBaseChannel::GetURIPrincipal()
- {
- if (mPrincipal) {
- return mPrincipal;
- }
- nsIScriptSecurityManager *securityManager =
- nsContentUtils::GetSecurityManager();
- if (!securityManager) {
- LOG(("HttpBaseChannel::GetURIPrincipal: No security manager [this=%p]",
- this));
- return nullptr;
- }
- securityManager->GetChannelURIPrincipal(this, getter_AddRefs(mPrincipal));
- if (!mPrincipal) {
- LOG(("HttpBaseChannel::GetURIPrincipal: No channel principal [this=%p]",
- this));
- return nullptr;
- }
- return mPrincipal;
- }
- bool
- HttpBaseChannel::IsNavigation()
- {
- return mForceMainDocumentChannel;
- }
- bool
- HttpBaseChannel::BypassServiceWorker() const
- {
- return mLoadFlags & LOAD_BYPASS_SERVICE_WORKER;
- }
- bool
- HttpBaseChannel::ShouldIntercept(nsIURI* aURI)
- {
- nsCOMPtr<nsINetworkInterceptController> controller;
- GetCallback(controller);
- bool shouldIntercept = false;
- if (controller && !BypassServiceWorker() && mLoadInfo) {
- nsresult rv = controller->ShouldPrepareForIntercept(aURI ? aURI : mURI.get(),
- nsContentUtils::IsNonSubresourceRequest(this),
- &shouldIntercept);
- if (NS_FAILED(rv)) {
- return false;
- }
- }
- return shouldIntercept;
- }
- #ifdef DEBUG
- void HttpBaseChannel::AssertPrivateBrowsingId()
- {
- nsCOMPtr<nsILoadContext> loadContext;
- NS_QueryNotificationCallbacks(this, loadContext);
- // For addons it's possible that mLoadInfo is null.
- if (!mLoadInfo) {
- return;
- }
- if (!loadContext) {
- return;
- }
- // We skip testing of favicon loading here since it could be triggered by XUL image
- // which uses SystemPrincipal. The SystemPrincpal doesn't have mPrivateBrowsingId.
- if (nsContentUtils::IsSystemPrincipal(mLoadInfo->LoadingPrincipal()) &&
- mLoadInfo->InternalContentPolicyType() == nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON) {
- return;
- }
- DocShellOriginAttributes docShellAttrs;
- loadContext->GetOriginAttributes(docShellAttrs);
- MOZ_ASSERT(mLoadInfo->GetOriginAttributes().mPrivateBrowsingId == docShellAttrs.mPrivateBrowsingId,
- "PrivateBrowsingId values are not the same between LoadInfo and LoadContext.");
- }
- #endif
- //-----------------------------------------------------------------------------
- // nsHttpChannel::nsITraceableChannel
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpBaseChannel::SetNewListener(nsIStreamListener *aListener, nsIStreamListener **_retval)
- {
- LOG(("HttpBaseChannel::SetNewListener [this=%p, mListener=%p, newListener=%p]",
- this, mListener.get(), aListener));
- if (!mTracingEnabled)
- return NS_ERROR_FAILURE;
- NS_ENSURE_STATE(mListener);
- NS_ENSURE_ARG_POINTER(aListener);
- nsCOMPtr<nsIStreamListener> wrapper = new nsStreamListenerWrapper(mListener);
- wrapper.forget(_retval);
- mListener = aListener;
- return NS_OK;
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel helpers
- //-----------------------------------------------------------------------------
- void
- HttpBaseChannel::ReleaseListeners()
- {
- MOZ_ASSERT(NS_IsMainThread(), "Should only be called on the main thread.");
- mListener = nullptr;
- mListenerContext = nullptr;
- mCallbacks = nullptr;
- mProgressSink = nullptr;
- mCompressListener = nullptr;
- }
- void
- HttpBaseChannel::DoNotifyListener()
- {
- if (mListener) {
- MOZ_ASSERT(!mOnStartRequestCalled,
- "We should not call OnStartRequest twice");
- nsCOMPtr<nsIStreamListener> listener = mListener;
- listener->OnStartRequest(this, mListenerContext);
- mOnStartRequestCalled = true;
- }
- // Make sure mIsPending is set to false. At this moment we are done from
- // the point of view of our consumer and we have to report our self
- // as not-pending.
- mIsPending = false;
- if (mListener) {
- MOZ_ASSERT(!mOnStopRequestCalled,
- "We should not call OnStopRequest twice");
- nsCOMPtr<nsIStreamListener> listener = mListener;
- listener->OnStopRequest(this, mListenerContext, mStatus);
- mOnStopRequestCalled = true;
- }
- // We have to make sure to drop the references to listeners and callbacks
- // no longer needed
- ReleaseListeners();
- DoNotifyListenerCleanup();
- // If this is a navigation, then we must let the docshell flush the reports
- // to the console later. The LoadDocument() is pointing at the detached
- // document that started the navigation. We want to show the reports on the
- // new document. Otherwise the console is wiped and the user never sees
- // the information.
- if (!IsNavigation() && mLoadInfo) {
- nsCOMPtr<nsIDOMDocument> dommyDoc;
- mLoadInfo->GetLoadingDocument(getter_AddRefs(dommyDoc));
- nsCOMPtr<nsIDocument> doc = do_QueryInterface(dommyDoc);
- FlushConsoleReports(doc);
- }
- }
- void
- HttpBaseChannel::AddCookiesToRequest()
- {
- if (mLoadFlags & LOAD_ANONYMOUS) {
- return;
- }
- bool useCookieService =
- (XRE_IsParentProcess());
- nsXPIDLCString cookie;
- if (useCookieService) {
- nsICookieService *cs = gHttpHandler->GetCookieService();
- if (cs) {
- cs->GetCookieStringFromHttp(mURI,
- nullptr,
- this, getter_Copies(cookie));
- }
- if (cookie.IsEmpty()) {
- cookie = mUserSetCookieHeader;
- }
- else if (!mUserSetCookieHeader.IsEmpty()) {
- cookie.AppendLiteral("; ");
- cookie.Append(mUserSetCookieHeader);
- }
- }
- else {
- cookie = mUserSetCookieHeader;
- }
- // If we are in the child process, we want the parent seeing any
- // cookie headers that might have been set by SetRequestHeader()
- SetRequestHeader(nsDependentCString(nsHttp::Cookie), cookie, false);
- }
- bool
- HttpBaseChannel::ShouldRewriteRedirectToGET(uint32_t httpStatus,
- nsHttpRequestHead::ParsedMethodType method)
- {
- // for 301 and 302, only rewrite POST
- if (httpStatus == 301 || httpStatus == 302)
- return method == nsHttpRequestHead::kMethod_Post;
- // rewrite for 303 unless it was HEAD
- if (httpStatus == 303)
- return method != nsHttpRequestHead::kMethod_Head;
- // otherwise, such as for 307, do not rewrite
- return false;
- }
- static
- bool IsHeaderBlacklistedForRedirectCopy(nsHttpAtom const& aHeader)
- {
- // IMPORTANT: keep this list ASCII-code sorted
- static nsHttpAtom const* blackList[] = {
- &nsHttp::Accept,
- &nsHttp::Accept_Encoding,
- &nsHttp::Accept_Language,
- &nsHttp::Authentication,
- &nsHttp::Authorization,
- &nsHttp::Connection,
- &nsHttp::Content_Length,
- &nsHttp::Cookie,
- &nsHttp::Host,
- &nsHttp::If,
- &nsHttp::If_Match,
- &nsHttp::If_Modified_Since,
- &nsHttp::If_None_Match,
- &nsHttp::If_None_Match_Any,
- &nsHttp::If_Range,
- &nsHttp::If_Unmodified_Since,
- &nsHttp::Proxy_Authenticate,
- &nsHttp::Proxy_Authorization,
- &nsHttp::Range,
- &nsHttp::TE,
- &nsHttp::Transfer_Encoding,
- &nsHttp::Upgrade,
- &nsHttp::User_Agent,
- &nsHttp::WWW_Authenticate
- };
- class HttpAtomComparator
- {
- nsHttpAtom const& mTarget;
- public:
- explicit HttpAtomComparator(nsHttpAtom const& aTarget)
- : mTarget(aTarget) {}
- int operator()(nsHttpAtom const* aVal) const {
- if (mTarget == *aVal) {
- return 0;
- }
- return strcmp(mTarget._val, aVal->_val);
- }
- };
- size_t unused;
- return BinarySearchIf(blackList, 0, ArrayLength(blackList),
- HttpAtomComparator(aHeader), &unused);
- }
- class SetupReplacementChannelHeaderVisitor final : public nsIHttpHeaderVisitor
- {
- public:
- NS_DECL_ISUPPORTS
- explicit SetupReplacementChannelHeaderVisitor(nsIHttpChannel *aChannel)
- : mChannel(aChannel)
- {
- }
- NS_IMETHOD VisitHeader(const nsACString& aHeader,
- const nsACString& aValue) override
- {
- nsHttpAtom atom = nsHttp::ResolveAtom(aHeader);
- if (!IsHeaderBlacklistedForRedirectCopy(atom)) {
- mChannel->SetRequestHeader(aHeader, aValue, false);
- }
- return NS_OK;
- }
- private:
- ~SetupReplacementChannelHeaderVisitor()
- {
- }
- nsCOMPtr<nsIHttpChannel> mChannel;
- };
- NS_IMPL_ISUPPORTS(SetupReplacementChannelHeaderVisitor, nsIHttpHeaderVisitor)
- nsresult
- HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
- nsIChannel *newChannel,
- bool preserveMethod,
- uint32_t redirectFlags)
- {
- LOG(("HttpBaseChannel::SetupReplacementChannel "
- "[this=%p newChannel=%p preserveMethod=%d]",
- this, newChannel, preserveMethod));
- uint32_t newLoadFlags = mLoadFlags | LOAD_REPLACE;
- // if the original channel was using SSL and this channel is not using
- // SSL, then no need to inhibit persistent caching. however, if the
- // original channel was not using SSL and has INHIBIT_PERSISTENT_CACHING
- // set, then allow the flag to apply to the redirected channel as well.
- // since we force set INHIBIT_PERSISTENT_CACHING on all HTTPS channels,
- // we only need to check if the original channel was using SSL.
- bool usingSSL = false;
- nsresult rv = mURI->SchemeIs("https", &usingSSL);
- if (NS_SUCCEEDED(rv) && usingSSL)
- newLoadFlags &= ~INHIBIT_PERSISTENT_CACHING;
- // Do not pass along LOAD_CHECK_OFFLINE_CACHE
- newLoadFlags &= ~nsICachingChannel::LOAD_CHECK_OFFLINE_CACHE;
- newChannel->SetLoadGroup(mLoadGroup);
- newChannel->SetNotificationCallbacks(mCallbacks);
- newChannel->SetLoadFlags(newLoadFlags);
- // Try to preserve the privacy bit if it has been overridden
- if (mPrivateBrowsingOverriden) {
- nsCOMPtr<nsIPrivateBrowsingChannel> newPBChannel =
- do_QueryInterface(newChannel);
- if (newPBChannel) {
- newPBChannel->SetPrivate(mPrivateBrowsing);
- }
- }
- // make a copy of the loadinfo, append to the redirectchain
- // and set it on the new channel
- if (mLoadInfo) {
- nsCOMPtr<nsILoadInfo> newLoadInfo =
- static_cast<mozilla::LoadInfo*>(mLoadInfo.get())->Clone();
- nsContentPolicyType contentPolicyType = mLoadInfo->GetExternalContentPolicyType();
- if (contentPolicyType == nsIContentPolicy::TYPE_DOCUMENT ||
- contentPolicyType == nsIContentPolicy::TYPE_SUBDOCUMENT) {
- nsCOMPtr<nsIPrincipal> nullPrincipalToInherit = nsNullPrincipal::Create();
- newLoadInfo->SetPrincipalToInherit(nullPrincipalToInherit);
- }
- // re-compute the origin attributes of the loadInfo if it's top-level load.
- bool isTopLevelDoc =
- newLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_DOCUMENT;
- if (isTopLevelDoc) {
- nsCOMPtr<nsILoadContext> loadContext;
- NS_QueryNotificationCallbacks(this, loadContext);
- DocShellOriginAttributes docShellAttrs;
- if (loadContext) {
- loadContext->GetOriginAttributes(docShellAttrs);
- }
- MOZ_ASSERT(docShellAttrs.mFirstPartyDomain.IsEmpty(),
- "top-level docshell shouldn't have firstPartyDomain attribute.");
- NeckoOriginAttributes attrs = newLoadInfo->GetOriginAttributes();
- MOZ_ASSERT(docShellAttrs.mAppId == attrs.mAppId,
- "docshell and necko should have the same appId attribute.");
- MOZ_ASSERT(docShellAttrs.mUserContextId == attrs.mUserContextId,
- "docshell and necko should have the same userContextId attribute.");
- MOZ_ASSERT(docShellAttrs.mInIsolatedMozBrowser == attrs.mInIsolatedMozBrowser,
- "docshell and necko should have the same inIsolatedMozBrowser attribute.");
- MOZ_ASSERT(docShellAttrs.mPrivateBrowsingId == attrs.mPrivateBrowsingId,
- "docshell and necko should have the same privateBrowsingId attribute.");
- attrs.InheritFromDocShellToNecko(docShellAttrs, true, newURI);
- newLoadInfo->SetOriginAttributes(attrs);
- }
- bool isInternalRedirect =
- (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
- nsIChannelEventSink::REDIRECT_STS_UPGRADE));
- newLoadInfo->AppendRedirectedPrincipal(GetURIPrincipal(), isInternalRedirect);
- newChannel->SetLoadInfo(newLoadInfo);
- }
- else {
- // the newChannel was created with a dummy loadInfo, we should clear
- // it in case the original channel does not have a loadInfo
- newChannel->SetLoadInfo(nullptr);
- }
- nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
- if (!httpChannel)
- return NS_OK; // no other options to set
- // Preserve the CORS preflight information.
- nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(newChannel);
- if (mRequireCORSPreflight && httpInternal) {
- httpInternal->SetCorsPreflightParameters(mUnsafeHeaders);
- }
- if (preserveMethod) {
- nsCOMPtr<nsIUploadChannel> uploadChannel =
- do_QueryInterface(httpChannel);
- nsCOMPtr<nsIUploadChannel2> uploadChannel2 =
- do_QueryInterface(httpChannel);
- if (mUploadStream && (uploadChannel2 || uploadChannel)) {
- // rewind upload stream
- nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mUploadStream);
- if (seekable)
- seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
- // replicate original call to SetUploadStream...
- if (uploadChannel2) {
- nsAutoCString ctype;
- // If header is not present mRequestHead.HasHeaderValue will truncated
- // it. But we want to end up with a void string, not an empty string,
- // because ExplicitSetUploadStream treats the former as "no header" and
- // the latter as "header with empty string value".
- nsresult ctypeOK = mRequestHead.GetHeader(nsHttp::Content_Type, ctype);
- if (NS_FAILED(ctypeOK)) {
- ctype.SetIsVoid(true);
- }
- nsAutoCString clen;
- mRequestHead.GetHeader(nsHttp::Content_Length, clen);
- nsAutoCString method;
- mRequestHead.Method(method);
- int64_t len = clen.IsEmpty() ? -1 : nsCRT::atoll(clen.get());
- uploadChannel2->ExplicitSetUploadStream(
- mUploadStream, ctype, len,
- method,
- mUploadStreamHasHeaders);
- } else {
- if (mUploadStreamHasHeaders) {
- uploadChannel->SetUploadStream(mUploadStream, EmptyCString(),
- -1);
- } else {
- nsAutoCString ctype;
- if (NS_FAILED(mRequestHead.GetHeader(nsHttp::Content_Type, ctype))) {
- ctype = NS_LITERAL_CSTRING("application/octet-stream");
- }
- nsAutoCString clen;
- if (NS_SUCCEEDED(mRequestHead.GetHeader(nsHttp::Content_Length, clen))
- &&
- !clen.IsEmpty()) {
- uploadChannel->SetUploadStream(mUploadStream,
- ctype,
- nsCRT::atoll(clen.get()));
- }
- }
- }
- }
- // since preserveMethod is true, we need to ensure that the appropriate
- // request method gets set on the channel, regardless of whether or not
- // we set the upload stream above. This means SetRequestMethod() will
- // be called twice if ExplicitSetUploadStream() gets called above.
- nsAutoCString method;
- mRequestHead.Method(method);
- httpChannel->SetRequestMethod(method);
- }
- // convey the referrer if one was used for this channel to the next one
- if (mReferrer)
- httpChannel->SetReferrerWithPolicy(mReferrer, mReferrerPolicy);
- // convey the mAllowPipelining and mAllowSTS flags
- httpChannel->SetAllowPipelining(mAllowPipelining);
- httpChannel->SetAllowSTS(mAllowSTS);
- // convey the Accept header value
- {
- nsAutoCString oldAcceptValue;
- nsresult hasHeader = mRequestHead.GetHeader(nsHttp::Accept, oldAcceptValue);
- if (NS_SUCCEEDED(hasHeader)) {
- httpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Accept"),
- oldAcceptValue,
- false);
- }
- }
- // share the request context - see bug 1236650
- httpChannel->SetRequestContextID(mRequestContextID);
- if (httpInternal) {
- // Convey third party cookie, conservative, and spdy flags.
- httpInternal->SetThirdPartyFlags(mThirdPartyFlags);
- httpInternal->SetAllowSpdy(mAllowSpdy);
- httpInternal->SetAllowAltSvc(mAllowAltSvc);
- httpInternal->SetBeConservative(mBeConservative);
- RefPtr<nsHttpChannel> realChannel;
- CallQueryInterface(newChannel, realChannel.StartAssignment());
- if (realChannel) {
- realChannel->SetTopWindowURI(mTopWindowURI);
- }
- // update the DocumentURI indicator since we are being redirected.
- // if this was a top-level document channel, then the new channel
- // should have its mDocumentURI point to newURI; otherwise, we
- // just need to pass along our mDocumentURI to the new channel.
- if (newURI && (mURI == mDocumentURI))
- httpInternal->SetDocumentURI(newURI);
- else
- httpInternal->SetDocumentURI(mDocumentURI);
- // if there is a chain of keys for redirect-responses we transfer it to
- // the new channel (see bug #561276)
- if (mRedirectedCachekeys) {
- LOG(("HttpBaseChannel::SetupReplacementChannel "
- "[this=%p] transferring chain of redirect cache-keys", this));
- httpInternal->SetCacheKeysRedirectChain(mRedirectedCachekeys.forget());
- }
- // Preserve CORS mode flag.
- httpInternal->SetCorsMode(mCorsMode);
- // Preserve Redirect mode flag.
- httpInternal->SetRedirectMode(mRedirectMode);
- // Preserve Cache mode flag.
- httpInternal->SetFetchCacheMode(mFetchCacheMode);
- // Preserve Integrity metadata.
- httpInternal->SetIntegrityMetadata(mIntegrityMetadata);
- }
- // transfer application cache information
- nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
- do_QueryInterface(newChannel);
- if (appCacheChannel) {
- appCacheChannel->SetApplicationCache(mApplicationCache);
- appCacheChannel->SetInheritApplicationCache(mInheritApplicationCache);
- // We purposely avoid transfering mChooseApplicationCache.
- }
- // transfer any properties
- nsCOMPtr<nsIWritablePropertyBag> bag(do_QueryInterface(newChannel));
- if (bag) {
- for (auto iter = mPropertyHash.Iter(); !iter.Done(); iter.Next()) {
- bag->SetProperty(iter.Key(), iter.UserData());
- }
- }
- // Transfer the timing data (if we are dealing with an nsITimedChannel).
- nsCOMPtr<nsITimedChannel> newTimedChannel(do_QueryInterface(newChannel));
- nsCOMPtr<nsITimedChannel> oldTimedChannel(
- do_QueryInterface(static_cast<nsIHttpChannel*>(this)));
- if (oldTimedChannel && newTimedChannel) {
- newTimedChannel->SetTimingEnabled(mTimingEnabled);
- if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
- int8_t newCount = mInternalRedirectCount + 1;
- newTimedChannel->SetInternalRedirectCount(
- std::max(newCount, mInternalRedirectCount));
- } else {
- int8_t newCount = mRedirectCount + 1;
- newTimedChannel->SetRedirectCount(
- std::max(newCount, mRedirectCount));
- }
- // If the RedirectStart is null, we will use the AsyncOpen value of the
- // previous channel (this is the first redirect in the redirects chain).
- if (mRedirectStartTimeStamp.IsNull()) {
- // Only do this for real redirects. Internal redirects should be hidden.
- if (!(redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) {
- TimeStamp asyncOpen;
- oldTimedChannel->GetAsyncOpen(&asyncOpen);
- newTimedChannel->SetRedirectStart(asyncOpen);
- }
- } else {
- newTimedChannel->SetRedirectStart(mRedirectStartTimeStamp);
- }
- // For internal redirects just propagate the last redirect end time
- // forward. Otherwise the new redirect end time is the last response
- // end time.
- TimeStamp newRedirectEnd;
- if (redirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) {
- oldTimedChannel->GetRedirectEnd(&newRedirectEnd);
- } else {
- oldTimedChannel->GetResponseEnd(&newRedirectEnd);
- }
- newTimedChannel->SetRedirectEnd(newRedirectEnd);
- nsAutoString initiatorType;
- oldTimedChannel->GetInitiatorType(initiatorType);
- newTimedChannel->SetInitiatorType(initiatorType);
- // Check whether or not this was a cross-domain redirect.
- newTimedChannel->SetAllRedirectsSameOrigin(
- mAllRedirectsSameOrigin && SameOriginWithOriginalUri(newURI));
- // Execute the timing allow check to determine whether
- // to report the redirect timing info
- nsCOMPtr<nsILoadInfo> loadInfo;
- GetLoadInfo(getter_AddRefs(loadInfo));
- // TYPE_DOCUMENT loads don't have a loadingPrincipal, so we can't set
- // AllRedirectsPassTimingAllowCheck on them.
- if (loadInfo && loadInfo->GetExternalContentPolicyType() != nsIContentPolicy::TYPE_DOCUMENT) {
- nsCOMPtr<nsIPrincipal> principal = loadInfo->LoadingPrincipal();
- newTimedChannel->SetAllRedirectsPassTimingAllowCheck(
- mAllRedirectsPassTimingAllowCheck &&
- oldTimedChannel->TimingAllowCheck(principal));
- }
- // Propagate service worker measurements across redirects. The
- // PeformanceResourceTiming.workerStart API expects to see the
- // worker start time after a redirect.
- newTimedChannel->SetLaunchServiceWorkerStart(mLaunchServiceWorkerStart);
- newTimedChannel->SetLaunchServiceWorkerEnd(mLaunchServiceWorkerEnd);
- newTimedChannel->SetDispatchFetchEventStart(mDispatchFetchEventStart);
- newTimedChannel->SetDispatchFetchEventEnd(mDispatchFetchEventEnd);
- newTimedChannel->SetHandleFetchEventStart(mHandleFetchEventStart);
- newTimedChannel->SetHandleFetchEventEnd(mHandleFetchEventEnd);
- }
- // Pass the preferred alt-data type on to the new channel.
- nsCOMPtr<nsICacheInfoChannel> cacheInfoChan(do_QueryInterface(newChannel));
- if (cacheInfoChan) {
- cacheInfoChan->PreferAlternativeDataType(mPreferredCachedAltDataType);
- }
- if (redirectFlags & (nsIChannelEventSink::REDIRECT_INTERNAL |
- nsIChannelEventSink::REDIRECT_STS_UPGRADE)) {
- // Copy non-origin related headers to the new channel.
- nsCOMPtr<nsIHttpHeaderVisitor> visitor =
- new SetupReplacementChannelHeaderVisitor(httpChannel);
- mRequestHead.VisitHeaders(visitor);
- }
- // This channel has been redirected. Don't report timing info.
- mTimingEnabled = false;
- return NS_OK;
- }
- // Redirect Tracking
- bool
- HttpBaseChannel::SameOriginWithOriginalUri(nsIURI *aURI)
- {
- nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
- nsresult rv = ssm->CheckSameOriginURI(aURI, mOriginalURI, false);
- return (NS_SUCCEEDED(rv));
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsITimedChannel
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpBaseChannel::SetTimingEnabled(bool enabled) {
- mTimingEnabled = enabled;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetTimingEnabled(bool* _retval) {
- *_retval = mTimingEnabled;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetChannelCreation(TimeStamp* _retval) {
- *_retval = mChannelCreationTimestamp;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetAsyncOpen(TimeStamp* _retval) {
- *_retval = mAsyncOpenTime;
- return NS_OK;
- }
- /**
- * @return the number of redirects. There is no check for cross-domain
- * redirects. This check must be done by the consumers.
- */
- NS_IMETHODIMP
- HttpBaseChannel::GetRedirectCount(uint8_t *aRedirectCount)
- {
- *aRedirectCount = mRedirectCount;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetRedirectCount(uint8_t aRedirectCount)
- {
- mRedirectCount = aRedirectCount;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetInternalRedirectCount(uint8_t *aRedirectCount)
- {
- *aRedirectCount = mInternalRedirectCount;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetInternalRedirectCount(uint8_t aRedirectCount)
- {
- mInternalRedirectCount = aRedirectCount;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetRedirectStart(TimeStamp* _retval)
- {
- *_retval = mRedirectStartTimeStamp;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetRedirectStart(TimeStamp aRedirectStart)
- {
- mRedirectStartTimeStamp = aRedirectStart;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetRedirectEnd(TimeStamp* _retval)
- {
- *_retval = mRedirectEndTimeStamp;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetRedirectEnd(TimeStamp aRedirectEnd)
- {
- mRedirectEndTimeStamp = aRedirectEnd;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetAllRedirectsSameOrigin(bool *aAllRedirectsSameOrigin)
- {
- *aAllRedirectsSameOrigin = mAllRedirectsSameOrigin;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetAllRedirectsSameOrigin(bool aAllRedirectsSameOrigin)
- {
- mAllRedirectsSameOrigin = aAllRedirectsSameOrigin;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetAllRedirectsPassTimingAllowCheck(bool *aPassesCheck)
- {
- *aPassesCheck = mAllRedirectsPassTimingAllowCheck;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetAllRedirectsPassTimingAllowCheck(bool aPassesCheck)
- {
- mAllRedirectsPassTimingAllowCheck = aPassesCheck;
- return NS_OK;
- }
- // http://www.w3.org/TR/resource-timing/#timing-allow-check
- NS_IMETHODIMP
- HttpBaseChannel::TimingAllowCheck(nsIPrincipal *aOrigin, bool *_retval)
- {
- nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
- nsCOMPtr<nsIPrincipal> resourcePrincipal;
- nsresult rv = ssm->GetChannelURIPrincipal(this, getter_AddRefs(resourcePrincipal));
- if (NS_FAILED(rv) || !resourcePrincipal || !aOrigin) {
- *_retval = false;
- return NS_OK;
- }
- bool sameOrigin = false;
- rv = resourcePrincipal->Equals(aOrigin, &sameOrigin);
- if (NS_SUCCEEDED(rv) && sameOrigin) {
- *_retval = true;
- return NS_OK;
- }
- nsAutoCString headerValue;
- rv = GetResponseHeader(NS_LITERAL_CSTRING("Timing-Allow-Origin"), headerValue);
- if (NS_FAILED(rv)) {
- *_retval = false;
- return NS_OK;
- }
- if (headerValue == "*") {
- *_retval = true;
- return NS_OK;
- }
- nsAutoCString origin;
- nsContentUtils::GetASCIIOrigin(aOrigin, origin);
- if (headerValue == origin) {
- *_retval = true;
- return NS_OK;
- }
- *_retval = false;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetLaunchServiceWorkerStart(TimeStamp* _retval) {
- MOZ_ASSERT(_retval);
- *_retval = mLaunchServiceWorkerStart;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetLaunchServiceWorkerStart(TimeStamp aTimeStamp) {
- mLaunchServiceWorkerStart = aTimeStamp;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetLaunchServiceWorkerEnd(TimeStamp* _retval) {
- MOZ_ASSERT(_retval);
- *_retval = mLaunchServiceWorkerEnd;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetLaunchServiceWorkerEnd(TimeStamp aTimeStamp) {
- mLaunchServiceWorkerEnd = aTimeStamp;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetDispatchFetchEventStart(TimeStamp* _retval) {
- MOZ_ASSERT(_retval);
- *_retval = mDispatchFetchEventStart;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetDispatchFetchEventStart(TimeStamp aTimeStamp) {
- mDispatchFetchEventStart = aTimeStamp;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetDispatchFetchEventEnd(TimeStamp* _retval) {
- MOZ_ASSERT(_retval);
- *_retval = mDispatchFetchEventEnd;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetDispatchFetchEventEnd(TimeStamp aTimeStamp) {
- mDispatchFetchEventEnd = aTimeStamp;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetHandleFetchEventStart(TimeStamp* _retval) {
- MOZ_ASSERT(_retval);
- *_retval = mHandleFetchEventStart;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetHandleFetchEventStart(TimeStamp aTimeStamp) {
- mHandleFetchEventStart = aTimeStamp;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetHandleFetchEventEnd(TimeStamp* _retval) {
- MOZ_ASSERT(_retval);
- *_retval = mHandleFetchEventEnd;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetHandleFetchEventEnd(TimeStamp aTimeStamp) {
- mHandleFetchEventEnd = aTimeStamp;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetDomainLookupStart(TimeStamp* _retval) {
- *_retval = mTransactionTimings.domainLookupStart;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetDomainLookupEnd(TimeStamp* _retval) {
- *_retval = mTransactionTimings.domainLookupEnd;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetConnectStart(TimeStamp* _retval) {
- *_retval = mTransactionTimings.connectStart;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetSecureConnectionStart(TimeStamp* _retval) {
- *_retval = mTransactionTimings.secureConnectionStart;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetConnectEnd(TimeStamp* _retval) {
- *_retval = mTransactionTimings.connectEnd;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetRequestStart(TimeStamp* _retval) {
- *_retval = mTransactionTimings.requestStart;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetResponseStart(TimeStamp* _retval) {
- *_retval = mTransactionTimings.responseStart;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetResponseEnd(TimeStamp* _retval) {
- *_retval = mTransactionTimings.responseEnd;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetCacheReadStart(TimeStamp* _retval) {
- *_retval = mCacheReadStart;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetCacheReadEnd(TimeStamp* _retval) {
- *_retval = mCacheReadEnd;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetInitiatorType(nsAString & aInitiatorType)
- {
- aInitiatorType = mInitiatorType;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetInitiatorType(const nsAString & aInitiatorType)
- {
- mInitiatorType = aInitiatorType;
- return NS_OK;
- }
- #define IMPL_TIMING_ATTR(name) \
- NS_IMETHODIMP \
- HttpBaseChannel::Get##name##Time(PRTime* _retval) { \
- TimeStamp stamp; \
- Get##name(&stamp); \
- if (stamp.IsNull()) { \
- *_retval = 0; \
- return NS_OK; \
- } \
- *_retval = mChannelCreationTime + \
- (PRTime) ((stamp - mChannelCreationTimestamp).ToSeconds() * 1e6); \
- return NS_OK; \
- }
- IMPL_TIMING_ATTR(ChannelCreation)
- IMPL_TIMING_ATTR(AsyncOpen)
- IMPL_TIMING_ATTR(LaunchServiceWorkerStart)
- IMPL_TIMING_ATTR(LaunchServiceWorkerEnd)
- IMPL_TIMING_ATTR(DispatchFetchEventStart)
- IMPL_TIMING_ATTR(DispatchFetchEventEnd)
- IMPL_TIMING_ATTR(HandleFetchEventStart)
- IMPL_TIMING_ATTR(HandleFetchEventEnd)
- IMPL_TIMING_ATTR(DomainLookupStart)
- IMPL_TIMING_ATTR(DomainLookupEnd)
- IMPL_TIMING_ATTR(ConnectStart)
- IMPL_TIMING_ATTR(SecureConnectionStart)
- IMPL_TIMING_ATTR(ConnectEnd)
- IMPL_TIMING_ATTR(RequestStart)
- IMPL_TIMING_ATTR(ResponseStart)
- IMPL_TIMING_ATTR(ResponseEnd)
- IMPL_TIMING_ATTR(CacheReadStart)
- IMPL_TIMING_ATTR(CacheReadEnd)
- IMPL_TIMING_ATTR(RedirectStart)
- IMPL_TIMING_ATTR(RedirectEnd)
- #undef IMPL_TIMING_ATTR
- mozilla::dom::Performance*
- HttpBaseChannel::GetPerformance()
- {
- // If performance timing is disabled, there is no need for the Performance
- // object anymore.
- if (!mTimingEnabled) {
- return nullptr;
- }
- // There is no point in continuing, since the performance object in the parent
- // isn't the same as the one in the child which will be reporting resource performance.
- if (XRE_IsParentProcess() && BrowserTabsRemoteAutostart()) {
- return nullptr;
- }
- if (!mLoadInfo) {
- return nullptr;
- }
- // We don't need to report the resource timing entry for a TYPE_DOCUMENT load.
- if (mLoadInfo->GetExternalContentPolicyType() == nsIContentPolicyBase::TYPE_DOCUMENT) {
- return nullptr;
- }
- nsCOMPtr<nsIDOMDocument> domDocument;
- mLoadInfo->GetLoadingDocument(getter_AddRefs(domDocument));
- if (!domDocument) {
- return nullptr;
- }
- nsCOMPtr<nsIDocument> loadingDocument = do_QueryInterface(domDocument);
- if (!loadingDocument) {
- return nullptr;
- }
- if (!mLoadInfo->TriggeringPrincipal()->Equals(loadingDocument->NodePrincipal())) {
- return nullptr;
- }
- if (mLoadInfo->GetExternalContentPolicyType() == nsIContentPolicy::TYPE_SUBDOCUMENT &&
- !mLoadInfo->GetIsFromProcessingFrameAttributes()) {
- // We only report loads caused by processing the attributes of the
- // browsing context container.
- return nullptr;
- }
- nsCOMPtr<nsPIDOMWindowInner> innerWindow = loadingDocument->GetInnerWindow();
- if (!innerWindow) {
- return nullptr;
- }
- mozilla::dom::Performance* docPerformance = innerWindow->GetPerformance();
- if (!docPerformance) {
- return nullptr;
- }
- return docPerformance;
- }
- nsIURI*
- HttpBaseChannel::GetReferringPage()
- {
- nsCOMPtr<nsPIDOMWindowInner> pDomWindow = GetInnerDOMWindow();
- if (!pDomWindow) {
- return nullptr;
- }
- return pDomWindow->GetDocumentURI();
- }
- nsPIDOMWindowInner*
- HttpBaseChannel::GetInnerDOMWindow()
- {
- nsCOMPtr<nsILoadContext> loadContext;
- NS_QueryNotificationCallbacks(this, loadContext);
- if (!loadContext) {
- return nullptr;
- }
- nsCOMPtr<mozIDOMWindowProxy> domWindow;
- loadContext->GetAssociatedWindow(getter_AddRefs(domWindow));
- if (!domWindow) {
- return nullptr;
- }
- auto* pDomWindow = nsPIDOMWindowOuter::From(domWindow);
- if (!pDomWindow) {
- return nullptr;
- }
- nsCOMPtr<nsPIDOMWindowInner> innerWindow = pDomWindow->GetCurrentInnerWindow();
- if (!innerWindow) {
- return nullptr;
- }
- return innerWindow;
- }
- //-----------------------------------------------------------------------------
- // HttpBaseChannel::nsIThrottledInputChannel
- //-----------------------------------------------------------------------------
- NS_IMETHODIMP
- HttpBaseChannel::SetThrottleQueue(nsIInputChannelThrottleQueue* aQueue)
- {
- if (!XRE_IsParentProcess()) {
- return NS_ERROR_FAILURE;
- }
- mThrottleQueue = aQueue;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetThrottleQueue(nsIInputChannelThrottleQueue** aQueue)
- {
- *aQueue = mThrottleQueue;
- return NS_OK;
- }
- //------------------------------------------------------------------------------
- bool
- HttpBaseChannel::EnsureRequestContextID()
- {
- nsID nullID;
- nullID.Clear();
- if (!mRequestContextID.Equals(nullID)) {
- // Already have a request context ID, no need to do the rest of this work
- return true;
- }
- // Find the loadgroup at the end of the chain in order
- // to make sure all channels derived from the load group
- // use the same connection scope.
- nsCOMPtr<nsILoadGroupChild> childLoadGroup = do_QueryInterface(mLoadGroup);
- if (!childLoadGroup) {
- return false;
- }
- nsCOMPtr<nsILoadGroup> rootLoadGroup;
- childLoadGroup->GetRootLoadGroup(getter_AddRefs(rootLoadGroup));
- if (!rootLoadGroup) {
- return false;
- }
- // Set the load group connection scope on the transaction
- rootLoadGroup->GetRequestContextID(&mRequestContextID);
- return true;
- }
- void
- HttpBaseChannel::SetCorsPreflightParameters(const nsTArray<nsCString>& aUnsafeHeaders)
- {
- MOZ_RELEASE_ASSERT(!mRequestObserversCalled);
- mRequireCORSPreflight = true;
- mUnsafeHeaders = aUnsafeHeaders;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetBlockAuthPrompt(bool* aValue)
- {
- if (!aValue) {
- return NS_ERROR_FAILURE;
- }
- *aValue = mBlockAuthPrompt;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::SetBlockAuthPrompt(bool aValue)
- {
- ENSURE_CALLED_BEFORE_CONNECT();
- mBlockAuthPrompt = aValue;
- return NS_OK;
- }
- NS_IMETHODIMP
- HttpBaseChannel::GetConnectionInfoHashKey(nsACString& aConnectionInfoHashKey)
- {
- if (!mConnectionInfo) {
- return NS_ERROR_FAILURE;
- }
- aConnectionInfoHashKey.Assign(mConnectionInfo->HashKey());
- return NS_OK;
- }
- } // namespace net
- } // namespace mozilla
|