123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970 |
- /* -*- 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/. */
- #include "nsDocShell.h"
- #include <algorithm>
- #include "mozilla/ArrayUtils.h"
- #include "mozilla/Attributes.h"
- #include "mozilla/AutoRestore.h"
- #include "mozilla/BasePrincipal.h"
- #include "mozilla/Casting.h"
- #include "mozilla/dom/ContentChild.h"
- #include "mozilla/dom/ChromeUtils.h"
- #include "mozilla/dom/Element.h"
- #include "mozilla/dom/TabChild.h"
- #include "mozilla/dom/ProfileTimelineMarkerBinding.h"
- #include "mozilla/dom/ScreenOrientation.h"
- #include "mozilla/dom/ToJSValue.h"
- #include "mozilla/dom/PermissionMessageUtils.h"
- #include "mozilla/dom/workers/ServiceWorkerManager.h"
- #include "mozilla/EventStateManager.h"
- #include "mozilla/LoadInfo.h"
- #include "mozilla/Preferences.h"
- #include "mozilla/Services.h"
- #include "mozilla/StartupTimeline.h"
- #include "mozilla/Unused.h"
- #include "Navigator.h"
- #include "URIUtils.h"
- #include "mozilla/dom/DocGroup.h"
- #include "mozilla/dom/TabGroup.h"
- #include "nsIContent.h"
- #include "nsIContentInlines.h"
- #include "nsIDocument.h"
- #include "nsIDOMDocument.h"
- #include "nsIDOMElement.h"
- #include "nsAboutProtocolUtils.h"
- #include "nsArray.h"
- #include "nsArrayUtils.h"
- #include "nsContentSecurityManager.h"
- #include "nsICaptivePortalService.h"
- #include "nsIDOMStorage.h"
- #include "nsIContentViewer.h"
- #include "nsIDocumentLoaderFactory.h"
- #include "nsCURILoader.h"
- #include "nsDocShellCID.h"
- #include "nsDOMCID.h"
- #include "nsNetCID.h"
- #include "nsNetUtil.h"
- #include "mozilla/net/ReferrerPolicy.h"
- #include "nsRect.h"
- #include "prenv.h"
- #include "nsIDOMWindow.h"
- #include "nsIGlobalObject.h"
- #include "nsIViewSourceChannel.h"
- #include "nsIWebBrowserChrome.h"
- #include "nsPoint.h"
- #include "nsIObserverService.h"
- #include "nsIPrompt.h"
- #include "nsIAuthPrompt.h"
- #include "nsIAuthPrompt2.h"
- #include "nsIChannelEventSink.h"
- #include "nsIAsyncVerifyRedirectCallback.h"
- #include "nsIScriptSecurityManager.h"
- #include "nsIScriptObjectPrincipal.h"
- #include "nsIScrollableFrame.h"
- #include "nsContentPolicyUtils.h" // NS_CheckContentLoadPolicy(...)
- #include "nsISeekableStream.h"
- #include "nsAutoPtr.h"
- #include "nsQueryObject.h"
- #include "nsIWritablePropertyBag2.h"
- #include "nsIAppShell.h"
- #include "nsWidgetsCID.h"
- #include "nsIInterfaceRequestorUtils.h"
- #include "nsView.h"
- #include "nsViewManager.h"
- #include "nsIScriptChannel.h"
- #include "nsITimedChannel.h"
- #include "nsIPrivacyTransitionObserver.h"
- #include "nsIReflowObserver.h"
- #include "nsIScrollObserver.h"
- #include "nsIDocShellTreeItem.h"
- #include "nsIChannel.h"
- #include "IHistory.h"
- #include "nsViewSourceHandler.h"
- #include "nsWhitespaceTokenizer.h"
- #include "nsICookieService.h"
- #include "nsIConsoleReportCollector.h"
- #include "nsObjectLoadingContent.h"
- // we want to explore making the document own the load group
- // so we can associate the document URI with the load group.
- // until this point, we have an evil hack:
- #include "nsIHttpChannelInternal.h"
- #include "nsPILoadGroupInternal.h"
- // Local Includes
- #include "nsDocShellLoadInfo.h"
- #include "nsCDefaultURIFixup.h"
- #include "nsDocShellEnumerator.h"
- #include "nsSHistory.h"
- #include "nsDocShellEditorData.h"
- #include "GeckoProfiler.h"
- #include "timeline/JavascriptTimelineMarker.h"
- // Helper Classes
- #include "nsError.h"
- #include "nsEscape.h"
- // Interfaces Needed
- #include "nsIFormPOSTActionChannel.h"
- #include "nsIUploadChannel.h"
- #include "nsIUploadChannel2.h"
- #include "nsIWebProgress.h"
- #include "nsILayoutHistoryState.h"
- #include "nsITimer.h"
- #include "nsISHistoryInternal.h"
- #include "nsIPrincipal.h"
- #include "nsNullPrincipal.h"
- #include "nsISHEntry.h"
- #include "nsIWindowWatcher.h"
- #include "nsIPromptFactory.h"
- #include "nsITransportSecurityInfo.h"
- #include "nsINode.h"
- #include "nsINSSErrorsService.h"
- #include "nsIApplicationCacheChannel.h"
- #include "nsIApplicationCacheContainer.h"
- #include "nsStreamUtils.h"
- #include "nsIController.h"
- #include "nsPICommandUpdater.h"
- #include "nsIDOMHTMLAnchorElement.h"
- #include "nsIWebBrowserChrome3.h"
- #include "nsITabChild.h"
- #include "nsISiteSecurityService.h"
- #include "nsStructuredCloneContainer.h"
- #include "nsIStructuredCloneContainer.h"
- #include "nsISupportsPrimitives.h"
- #ifdef MOZ_PLACES
- #include "nsIFaviconService.h"
- #include "mozIPlacesPendingOperation.h"
- #include "mozIAsyncFavicons.h"
- #endif
- #include "nsINetworkPredictor.h"
- // Editor-related
- #include "nsIEditingSession.h"
- #include "nsPIDOMWindow.h"
- #include "nsGlobalWindow.h"
- #include "nsPIWindowRoot.h"
- #include "nsICachingChannel.h"
- #include "nsIMultiPartChannel.h"
- #include "nsIWyciwygChannel.h"
- // For reporting errors with the console service.
- // These can go away if error reporting is propagated up past nsDocShell.
- #include "nsIScriptError.h"
- // used to dispatch urls to default protocol handlers
- #include "nsCExternalHandlerService.h"
- #include "nsIExternalProtocolService.h"
- #include "nsFocusManager.h"
- #include "nsITextToSubURI.h"
- #include "nsIJARChannel.h"
- #include "mozilla/Logging.h"
- #include "nsISelectionDisplay.h"
- #include "nsIGlobalHistory2.h"
- #include "nsIFrame.h"
- #include "nsSubDocumentFrame.h"
- // for embedding
- #include "nsIWebBrowserChromeFocus.h"
- #if NS_PRINT_PREVIEW
- #include "nsIDocumentViewerPrint.h"
- #include "nsIWebBrowserPrint.h"
- #endif
- #include "nsContentUtils.h"
- #include "nsIContentSecurityPolicy.h"
- #include "nsILoadInfo.h"
- #include "nsSandboxFlags.h"
- #include "nsXULAppAPI.h"
- #include "nsDOMNavigationTiming.h"
- #include "nsIAppsService.h"
- #include "nsDSURIContentListener.h"
- #include "nsDocShellLoadTypes.h"
- #include "nsDocShellTransferableHooks.h"
- #include "nsICommandManager.h"
- #include "nsIDOMNode.h"
- #include "nsIDocShellTreeOwner.h"
- #include "nsIHttpChannel.h"
- #include "nsIIDNService.h"
- #include "nsIInputStreamChannel.h"
- #include "nsINestedURI.h"
- #include "nsISHContainer.h"
- #include "nsISHistory.h"
- #include "nsISecureBrowserUI.h"
- #include "nsISocketProvider.h"
- #include "nsIStringBundle.h"
- #include "nsIURIFixup.h"
- #include "nsIURILoader.h"
- #include "nsIURL.h"
- #include "nsIWebBrowserFind.h"
- #include "nsIWidget.h"
- #include "mozilla/dom/EncodingUtils.h"
- #include "mozilla/dom/PerformanceNavigation.h"
- #include "mozilla/dom/ScriptSettings.h"
- #ifdef MOZ_TOOLKIT_SEARCH
- #include "nsIBrowserSearchService.h"
- #endif
- #include "mozIThirdPartyUtil.h"
- static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
- #if defined(DEBUG_bryner) || defined(DEBUG_chb)
- //#define DEBUG_DOCSHELL_FOCUS
- #define DEBUG_PAGE_CACHE
- #endif
- #ifdef XP_WIN
- #include <process.h>
- #define getpid _getpid
- #else
- #include <unistd.h> // for getpid()
- #endif
- using namespace mozilla;
- using namespace mozilla::dom;
- using mozilla::dom::workers::ServiceWorkerManager;
- // True means sUseErrorPages has been added to
- // preferences var cache.
- static bool gAddedPreferencesVarCache = false;
- bool nsDocShell::sUseErrorPages = false;
- // Number of documents currently loading
- static int32_t gNumberOfDocumentsLoading = 0;
- // Global count of existing docshells.
- static int32_t gDocShellCount = 0;
- // Global count of docshells with the private attribute set
- static uint32_t gNumberOfPrivateDocShells = 0;
- // Global reference to the URI fixup service.
- nsIURIFixup* nsDocShell::sURIFixup = 0;
- // True means we validate window targets to prevent frameset
- // spoofing. Initialize this to a non-bolean value so we know to check
- // the pref on the creation of the first docshell.
- static uint32_t gValidateOrigin = 0xffffffff;
- // Hint for native dispatch of events on how long to delay after
- // all documents have loaded in milliseconds before favoring normal
- // native event dispatch priorites over performance
- // Can be overridden with docshell.event_starvation_delay_hint pref.
- #define NS_EVENT_STARVATION_DELAY_HINT 2000
- #ifdef DEBUG
- static mozilla::LazyLogModule gDocShellLog("nsDocShell");
- #endif
- static mozilla::LazyLogModule gDocShellLeakLog("nsDocShellLeak");;
- const char kBrandBundleURL[] = "chrome://branding/locale/brand.properties";
- const char kAppstringsBundleURL[] = "chrome://global/locale/appstrings.properties";
- static void
- FavorPerformanceHint(bool aPerfOverStarvation)
- {
- nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
- if (appShell) {
- appShell->FavorPerformanceHint(
- aPerfOverStarvation,
- Preferences::GetUint("docshell.event_starvation_delay_hint",
- NS_EVENT_STARVATION_DELAY_HINT));
- }
- }
- //*****************************************************************************
- // <a ping> support
- //*****************************************************************************
- #define PREF_PINGS_ENABLED "browser.send_pings"
- #define PREF_PINGS_MAX_PER_LINK "browser.send_pings.max_per_link"
- #define PREF_PINGS_REQUIRE_SAME_HOST "browser.send_pings.require_same_host"
- // Check prefs to see if pings are enabled and if so what restrictions might
- // be applied.
- //
- // @param maxPerLink
- // This parameter returns the number of pings that are allowed per link click
- //
- // @param requireSameHost
- // This parameter returns true if pings are restricted to the same host as
- // the document in which the click occurs. If the same host restriction is
- // imposed, then we still allow for pings to cross over to different
- // protocols and ports for flexibility and because it is not possible to send
- // a ping via FTP.
- //
- // @returns
- // true if pings are enabled and false otherwise.
- //
- static bool
- PingsEnabled(int32_t* aMaxPerLink, bool* aRequireSameHost)
- {
- bool allow = Preferences::GetBool(PREF_PINGS_ENABLED, false);
- *aMaxPerLink = 1;
- *aRequireSameHost = true;
- if (allow) {
- Preferences::GetInt(PREF_PINGS_MAX_PER_LINK, aMaxPerLink);
- Preferences::GetBool(PREF_PINGS_REQUIRE_SAME_HOST, aRequireSameHost);
- }
- return allow;
- }
- typedef void (*ForEachPingCallback)(void* closure, nsIContent* content,
- nsIURI* uri, nsIIOService* ios);
- static bool
- IsElementAnchor(nsIContent* aContent)
- {
- // Make sure we are dealing with either an <A> or <AREA> element in the HTML
- // or XHTML namespace.
- return aContent->IsAnyOfHTMLElements(nsGkAtoms::a, nsGkAtoms::area);
- }
- static void
- ForEachPing(nsIContent* aContent, ForEachPingCallback aCallback, void* aClosure)
- {
- // NOTE: Using nsIDOMHTMLAnchorElement::GetPing isn't really worth it here
- // since we'd still need to parse the resulting string. Instead, we
- // just parse the raw attribute. It might be nice if the content node
- // implemented an interface that exposed an enumeration of nsIURIs.
- // Make sure we are dealing with either an <A> or <AREA> element in the HTML
- // or XHTML namespace.
- if (!IsElementAnchor(aContent)) {
- return;
- }
- nsCOMPtr<nsIAtom> pingAtom = NS_Atomize("ping");
- if (!pingAtom) {
- return;
- }
- nsAutoString value;
- aContent->GetAttr(kNameSpaceID_None, pingAtom, value);
- if (value.IsEmpty()) {
- return;
- }
- nsCOMPtr<nsIIOService> ios = do_GetIOService();
- if (!ios) {
- return;
- }
- nsIDocument* doc = aContent->OwnerDoc();
- nsWhitespaceTokenizer tokenizer(value);
- while (tokenizer.hasMoreTokens()) {
- nsCOMPtr<nsIURI> uri, baseURI = aContent->GetBaseURI();
- ios->NewURI(NS_ConvertUTF16toUTF8(tokenizer.nextToken()),
- doc->GetDocumentCharacterSet().get(),
- baseURI, getter_AddRefs(uri));
- // if we can't generate a valid URI, then there is nothing to do
- if (!uri) {
- continue;
- }
- // Explicitly not allow loading data: URIs
- bool isDataScheme =
- (NS_SUCCEEDED(uri->SchemeIs("data", &isDataScheme)) && isDataScheme);
- if (!isDataScheme) {
- aCallback(aClosure, aContent, uri, ios);
- }
- }
- }
- //----------------------------------------------------------------------
- // We wait this many milliseconds before killing the ping channel...
- #define PING_TIMEOUT 10000
- static void
- OnPingTimeout(nsITimer* aTimer, void* aClosure)
- {
- nsILoadGroup* loadGroup = static_cast<nsILoadGroup*>(aClosure);
- if (loadGroup) {
- loadGroup->Cancel(NS_ERROR_ABORT);
- }
- }
- class nsPingListener final
- : public nsIStreamListener
- {
- public:
- NS_DECL_ISUPPORTS
- NS_DECL_NSIREQUESTOBSERVER
- NS_DECL_NSISTREAMLISTENER
- nsPingListener()
- {
- }
- void SetLoadGroup(nsILoadGroup* aLoadGroup) {
- mLoadGroup = aLoadGroup;
- }
- nsresult StartTimeout();
- private:
- ~nsPingListener();
- nsCOMPtr<nsILoadGroup> mLoadGroup;
- nsCOMPtr<nsITimer> mTimer;
- };
- NS_IMPL_ISUPPORTS(nsPingListener, nsIStreamListener, nsIRequestObserver)
- nsPingListener::~nsPingListener()
- {
- if (mTimer) {
- mTimer->Cancel();
- mTimer = nullptr;
- }
- }
- nsresult
- nsPingListener::StartTimeout()
- {
- nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
- if (timer) {
- nsresult rv = timer->InitWithFuncCallback(OnPingTimeout, mLoadGroup,
- PING_TIMEOUT,
- nsITimer::TYPE_ONE_SHOT);
- if (NS_SUCCEEDED(rv)) {
- mTimer = timer;
- return NS_OK;
- }
- }
- return NS_ERROR_OUT_OF_MEMORY;
- }
- NS_IMETHODIMP
- nsPingListener::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- nsPingListener::OnDataAvailable(nsIRequest* aRequest, nsISupports* aContext,
- nsIInputStream* aStream, uint64_t aOffset,
- uint32_t aCount)
- {
- uint32_t result;
- return aStream->ReadSegments(NS_DiscardSegment, nullptr, aCount, &result);
- }
- NS_IMETHODIMP
- nsPingListener::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext,
- nsresult aStatus)
- {
- mLoadGroup = nullptr;
- if (mTimer) {
- mTimer->Cancel();
- mTimer = nullptr;
- }
- return NS_OK;
- }
- struct MOZ_STACK_CLASS SendPingInfo
- {
- int32_t numPings;
- int32_t maxPings;
- bool requireSameHost;
- nsIURI* target;
- nsIURI* referrer;
- nsIDocShell* docShell;
- uint32_t referrerPolicy;
- };
- static void
- SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI,
- nsIIOService* aIOService)
- {
- SendPingInfo* info = static_cast<SendPingInfo*>(aClosure);
- if (info->maxPings > -1 && info->numPings >= info->maxPings) {
- return;
- }
- nsIDocument* doc = aContent->OwnerDoc();
- nsCOMPtr<nsIChannel> chan;
- NS_NewChannel(getter_AddRefs(chan),
- aURI,
- doc,
- info->requireSameHost
- ? nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
- : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
- nsIContentPolicy::TYPE_PING,
- nullptr, // aLoadGroup
- nullptr, // aCallbacks
- nsIRequest::LOAD_NORMAL, // aLoadFlags,
- aIOService);
- if (!chan) {
- return;
- }
- // Don't bother caching the result of this URI load, but do not exempt
- // it from Safe Browsing.
- chan->SetLoadFlags(nsIRequest::INHIBIT_CACHING | nsIChannel::LOAD_CLASSIFY_URI);
- nsCOMPtr<nsIHttpChannel> httpChan = do_QueryInterface(chan);
- if (!httpChan) {
- return;
- }
- // This is needed in order for 3rd-party cookie blocking to work.
- nsCOMPtr<nsIHttpChannelInternal> httpInternal = do_QueryInterface(httpChan);
- if (httpInternal) {
- httpInternal->SetDocumentURI(doc->GetDocumentURI());
- }
- httpChan->SetRequestMethod(NS_LITERAL_CSTRING("POST"));
- // Remove extraneous request headers (to reduce request size)
- httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept"),
- EmptyCString(), false);
- httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-language"),
- EmptyCString(), false);
- httpChan->SetRequestHeader(NS_LITERAL_CSTRING("accept-encoding"),
- EmptyCString(), false);
- // Always send a Ping-To header.
- nsAutoCString pingTo;
- if (NS_SUCCEEDED(info->target->GetSpec(pingTo))) {
- httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-To"), pingTo, false);
- }
- nsCOMPtr<nsIScriptSecurityManager> sm =
- do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
- if (sm && info->referrer) {
- bool referrerIsSecure;
- uint32_t flags = nsIProtocolHandler::URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
- nsresult rv = NS_URIChainHasFlags(info->referrer, flags, &referrerIsSecure);
- // Default to sending less data if NS_URIChainHasFlags() fails.
- referrerIsSecure = NS_FAILED(rv) || referrerIsSecure;
- bool sameOrigin =
- NS_SUCCEEDED(sm->CheckSameOriginURI(info->referrer, aURI, false));
- // If both the address of the document containing the hyperlink being
- // audited and "ping URL" have the same origin or the document containing
- // the hyperlink being audited was not retrieved over an encrypted
- // connection, send a Ping-From header.
- if (sameOrigin || !referrerIsSecure) {
- nsAutoCString pingFrom;
- if (NS_SUCCEEDED(info->referrer->GetSpec(pingFrom))) {
- httpChan->SetRequestHeader(NS_LITERAL_CSTRING("Ping-From"), pingFrom,
- false);
- }
- }
- // If the document containing the hyperlink being audited was not retrieved
- // over an encrypted connection and its address does not have the same
- // origin as "ping URL", send a referrer.
- if (!sameOrigin && !referrerIsSecure) {
- httpChan->SetReferrerWithPolicy(info->referrer, info->referrerPolicy);
- }
- }
- nsCOMPtr<nsIUploadChannel2> uploadChan = do_QueryInterface(httpChan);
- if (!uploadChan) {
- return;
- }
- NS_NAMED_LITERAL_CSTRING(uploadData, "PING");
- nsCOMPtr<nsIInputStream> uploadStream;
- NS_NewPostDataStream(getter_AddRefs(uploadStream), false, uploadData);
- if (!uploadStream) {
- return;
- }
- uploadChan->ExplicitSetUploadStream(uploadStream,
- NS_LITERAL_CSTRING("text/ping"),
- uploadData.Length(),
- NS_LITERAL_CSTRING("POST"), false);
- // The channel needs to have a loadgroup associated with it, so that we can
- // cancel the channel and any redirected channels it may create.
- nsCOMPtr<nsILoadGroup> loadGroup = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
- if (!loadGroup) {
- return;
- }
- nsCOMPtr<nsIInterfaceRequestor> callbacks = do_QueryInterface(info->docShell);
- loadGroup->SetNotificationCallbacks(callbacks);
- chan->SetLoadGroup(loadGroup);
- RefPtr<nsPingListener> pingListener = new nsPingListener();
- chan->AsyncOpen2(pingListener);
- // Even if AsyncOpen failed, we still count this as a successful ping. It's
- // possible that AsyncOpen may have failed after triggering some background
- // process that may have written something to the network.
- info->numPings++;
- // Prevent ping requests from stalling and never being garbage collected...
- if (NS_FAILED(pingListener->StartTimeout())) {
- // If we failed to setup the timer, then we should just cancel the channel
- // because we won't be able to ensure that it goes away in a timely manner.
- chan->Cancel(NS_ERROR_ABORT);
- return;
- }
- // if the channel openend successfully, then make the pingListener hold
- // a strong reference to the loadgroup which is released in ::OnStopRequest
- pingListener->SetLoadGroup(loadGroup);
- }
- // Spec: http://whatwg.org/specs/web-apps/current-work/#ping
- static void
- DispatchPings(nsIDocShell* aDocShell,
- nsIContent* aContent,
- nsIURI* aTarget,
- nsIURI* aReferrer,
- uint32_t aReferrerPolicy)
- {
- SendPingInfo info;
- if (!PingsEnabled(&info.maxPings, &info.requireSameHost)) {
- return;
- }
- if (info.maxPings == 0) {
- return;
- }
- info.numPings = 0;
- info.target = aTarget;
- info.referrer = aReferrer;
- info.referrerPolicy = aReferrerPolicy;
- info.docShell = aDocShell;
- ForEachPing(aContent, SendPing, &info);
- }
- static nsDOMNavigationTiming::Type
- ConvertLoadTypeToNavigationType(uint32_t aLoadType)
- {
- // Not initialized, assume it's normal load.
- if (aLoadType == 0) {
- aLoadType = LOAD_NORMAL;
- }
- auto result = nsDOMNavigationTiming::TYPE_RESERVED;
- switch (aLoadType) {
- case LOAD_NORMAL:
- case LOAD_NORMAL_EXTERNAL:
- case LOAD_NORMAL_BYPASS_CACHE:
- case LOAD_NORMAL_BYPASS_PROXY:
- case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
- case LOAD_NORMAL_REPLACE:
- case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
- case LOAD_LINK:
- case LOAD_STOP_CONTENT:
- case LOAD_REPLACE_BYPASS_CACHE:
- result = nsDOMNavigationTiming::TYPE_NAVIGATE;
- break;
- case LOAD_HISTORY:
- result = nsDOMNavigationTiming::TYPE_BACK_FORWARD;
- break;
- case LOAD_RELOAD_NORMAL:
- case LOAD_RELOAD_CHARSET_CHANGE:
- case LOAD_RELOAD_BYPASS_CACHE:
- case LOAD_RELOAD_BYPASS_PROXY:
- case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
- case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
- result = nsDOMNavigationTiming::TYPE_RELOAD;
- break;
- case LOAD_STOP_CONTENT_AND_REPLACE:
- case LOAD_REFRESH:
- case LOAD_BYPASS_HISTORY:
- case LOAD_ERROR_PAGE:
- case LOAD_PUSHSTATE:
- result = nsDOMNavigationTiming::TYPE_RESERVED;
- break;
- default:
- // NS_NOTREACHED("Unexpected load type value");
- result = nsDOMNavigationTiming::TYPE_RESERVED;
- break;
- }
- return result;
- }
- static nsISHEntry* GetRootSHEntry(nsISHEntry* aEntry);
- static void
- IncreasePrivateDocShellCount()
- {
- gNumberOfPrivateDocShells++;
- if (gNumberOfPrivateDocShells > 1 ||
- !XRE_IsContentProcess()) {
- return;
- }
- mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
- cc->SendPrivateDocShellsExist(true);
- }
- static void
- DecreasePrivateDocShellCount()
- {
- MOZ_ASSERT(gNumberOfPrivateDocShells > 0);
- gNumberOfPrivateDocShells--;
- if (!gNumberOfPrivateDocShells) {
- if (XRE_IsContentProcess()) {
- dom::ContentChild* cc = dom::ContentChild::GetSingleton();
- cc->SendPrivateDocShellsExist(false);
- return;
- }
- nsCOMPtr<nsIObserverService> obsvc = services::GetObserverService();
- if (obsvc) {
- obsvc->NotifyObservers(nullptr, "last-pb-context-exited", nullptr);
- }
- }
- }
- static uint64_t gDocshellIDCounter = 0;
- nsDocShell::nsDocShell()
- : nsDocLoader()
- , mDefaultScrollbarPref(Scrollbar_Auto, Scrollbar_Auto)
- , mTreeOwner(nullptr)
- , mChromeEventHandler(nullptr)
- , mCharsetReloadState(eCharsetReloadInit)
- , mChildOffset(0)
- , mBusyFlags(BUSY_FLAGS_NONE)
- , mAppType(nsIDocShell::APP_TYPE_UNKNOWN)
- , mLoadType(0)
- , mMarginWidth(-1)
- , mMarginHeight(-1)
- , mItemType(typeContent)
- , mPreviousTransIndex(-1)
- , mLoadedTransIndex(-1)
- , mSandboxFlags(0)
- , mOrientationLock(eScreenOrientation_None)
- , mFullscreenAllowed(CHECK_ATTRIBUTES)
- , mCreated(false)
- , mAllowSubframes(true)
- , mAllowPlugins(true)
- , mAllowJavascript(true)
- , mAllowMetaRedirects(true)
- , mAllowImages(true)
- , mAllowMedia(true)
- , mAllowDNSPrefetch(true)
- , mAllowWindowControl(true)
- , mAllowContentRetargeting(true)
- , mAllowContentRetargetingOnChildren(true)
- , mUseErrorPages(false)
- , mObserveErrorPages(true)
- , mAllowAuth(true)
- , mAllowKeywordFixup(false)
- , mIsOffScreenBrowser(false)
- , mIsActive(true)
- , mDisableMetaRefreshWhenInactive(false)
- , mIsPrerendered(false)
- , mIsAppTab(false)
- , mUseGlobalHistory(false)
- , mUseRemoteTabs(false)
- , mDeviceSizeIsPageSize(false)
- , mWindowDraggingAllowed(false)
- , mInFrameSwap(false)
- , mInheritPrivateBrowsingId(true)
- , mCanExecuteScripts(false)
- , mFiredUnloadEvent(false)
- , mEODForCurrentDocument(false)
- , mURIResultedInDocument(false)
- , mIsBeingDestroyed(false)
- , mIsExecutingOnLoadHandler(false)
- , mIsPrintingOrPP(false)
- , mSavingOldViewer(false)
- , mAffectPrivateSessionLifetime(true)
- , mInvisible(false)
- , mHasLoadedNonBlankURI(false)
- , mBlankTiming(false)
- , mCreatingDocument(false)
- #ifdef DEBUG
- , mInEnsureScriptEnv(false)
- #endif
- , mDefaultLoadFlags(nsIRequest::LOAD_NORMAL)
- , mFrameType(FRAME_TYPE_REGULAR)
- , mPrivateBrowsingId(0)
- , mParentCharsetSource(0)
- , mJSRunToCompletionDepth(0)
- , mTouchEventsOverride(nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE)
- , mStateFloodGuardCount(0)
- , mStateFloodGuardReported(false)
- , mReloadFloodGuardCount(0)
- , mReloadFloodGuardReported(false)
- {
- AssertOriginAttributesMatchPrivateBrowsing();
- mHistoryID = ++gDocshellIDCounter;
- if (gDocShellCount++ == 0) {
- NS_ASSERTION(sURIFixup == nullptr,
- "Huh, sURIFixup not null in first nsDocShell ctor!");
- CallGetService(NS_URIFIXUP_CONTRACTID, &sURIFixup);
- }
- MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p created\n", this));
- #ifdef DEBUG
- // We're counting the number of |nsDocShells| to help find leaks
- ++gNumberOfDocShells;
- if (!PR_GetEnv("MOZ_QUIET")) {
- printf_stderr("++DOCSHELL %p == %ld [pid = %d] [id = %llu]\n",
- (void*)this,
- gNumberOfDocShells,
- getpid(),
- AssertedCast<unsigned long long>(mHistoryID));
- }
- #endif
- }
- nsDocShell::~nsDocShell()
- {
- MOZ_ASSERT(!mObserved);
- // Avoid notifying observers while we're in the dtor.
- mIsBeingDestroyed = true;
- Destroy();
- nsCOMPtr<nsISHistoryInternal> shPrivate(do_QueryInterface(mSessionHistory));
- if (shPrivate) {
- shPrivate->SetRootDocShell(nullptr);
- }
- if (mContentViewer) {
- mContentViewer->Close(nullptr);
- mContentViewer->Destroy();
- mContentViewer = nullptr;
- }
- if (--gDocShellCount == 0) {
- NS_IF_RELEASE(sURIFixup);
- }
- if (gDocShellLeakLog) {
- MOZ_LOG(gDocShellLeakLog, LogLevel::Debug, ("DOCSHELL %p destroyed\n", this));
- }
- #ifdef DEBUG
- // We're counting the number of |nsDocShells| to help find leaks
- --gNumberOfDocShells;
- if (!PR_GetEnv("MOZ_QUIET")) {
- printf_stderr("--DOCSHELL %p == %ld [pid = %d] [id = %llu]\n",
- (void*)this,
- gNumberOfDocShells,
- getpid(),
- AssertedCast<unsigned long long>(mHistoryID));
- }
- #endif
- }
- nsresult
- nsDocShell::Init()
- {
- nsresult rv = nsDocLoader::Init();
- NS_ENSURE_SUCCESS(rv, rv);
- NS_ASSERTION(mLoadGroup, "Something went wrong!");
- mContentListener = new nsDSURIContentListener(this);
- rv = mContentListener->Init();
- NS_ENSURE_SUCCESS(rv, rv);
- // We want to hold a strong ref to the loadgroup, so it better hold a weak
- // ref to us... use an InterfaceRequestorProxy to do this.
- nsCOMPtr<nsIInterfaceRequestor> proxy =
- new InterfaceRequestorProxy(static_cast<nsIInterfaceRequestor*>(this));
- mLoadGroup->SetNotificationCallbacks(proxy);
- rv = nsDocLoader::AddDocLoaderAsChildOfRoot(this);
- NS_ENSURE_SUCCESS(rv, rv);
- // Add as |this| a progress listener to itself. A little weird, but
- // simpler than reproducing all the listener-notification logic in
- // overrides of the various methods via which nsDocLoader can be
- // notified. Note that this holds an nsWeakPtr to ourselves, so it's ok.
- return AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT |
- nsIWebProgress::NOTIFY_STATE_NETWORK);
- }
- void
- nsDocShell::DestroyChildren()
- {
- nsCOMPtr<nsIDocShellTreeItem> shell;
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- shell = do_QueryObject(iter.GetNext());
- NS_ASSERTION(shell, "docshell has null child");
- if (shell) {
- shell->SetTreeOwner(nullptr);
- }
- }
- nsDocLoader::DestroyChildren();
- }
- NS_IMPL_ADDREF_INHERITED(nsDocShell, nsDocLoader)
- NS_IMPL_RELEASE_INHERITED(nsDocShell, nsDocLoader)
- NS_INTERFACE_MAP_BEGIN(nsDocShell)
- NS_INTERFACE_MAP_ENTRY(nsIDocShell)
- NS_INTERFACE_MAP_ENTRY(nsIDocShellTreeItem)
- NS_INTERFACE_MAP_ENTRY(nsIWebNavigation)
- NS_INTERFACE_MAP_ENTRY(nsIBaseWindow)
- NS_INTERFACE_MAP_ENTRY(nsIScrollable)
- NS_INTERFACE_MAP_ENTRY(nsITextScroll)
- NS_INTERFACE_MAP_ENTRY(nsIDocCharset)
- NS_INTERFACE_MAP_ENTRY(nsIRefreshURI)
- NS_INTERFACE_MAP_ENTRY(nsIWebProgressListener)
- NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
- NS_INTERFACE_MAP_ENTRY(nsIContentViewerContainer)
- NS_INTERFACE_MAP_ENTRY(nsIWebPageDescriptor)
- NS_INTERFACE_MAP_ENTRY(nsIAuthPromptProvider)
- NS_INTERFACE_MAP_ENTRY(nsILoadContext)
- NS_INTERFACE_MAP_ENTRY(nsIWebShellServices)
- NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
- NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
- NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
- NS_INTERFACE_MAP_ENTRY(nsINetworkInterceptController)
- NS_INTERFACE_MAP_ENTRY(nsIDeprecationWarner)
- NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
- NS_IMETHODIMP
- nsDocShell::GetInterface(const nsIID& aIID, void** aSink)
- {
- NS_PRECONDITION(aSink, "null out param");
- *aSink = nullptr;
- if (aIID.Equals(NS_GET_IID(nsICommandManager))) {
- NS_ENSURE_SUCCESS(EnsureCommandHandler(), NS_ERROR_FAILURE);
- *aSink = mCommandManager;
- } else if (aIID.Equals(NS_GET_IID(nsIURIContentListener))) {
- *aSink = mContentListener;
- } else if ((aIID.Equals(NS_GET_IID(nsIScriptGlobalObject)) ||
- aIID.Equals(NS_GET_IID(nsIGlobalObject)) ||
- aIID.Equals(NS_GET_IID(nsPIDOMWindowOuter)) ||
- aIID.Equals(NS_GET_IID(mozIDOMWindowProxy)) ||
- aIID.Equals(NS_GET_IID(nsIDOMWindow)) ||
- aIID.Equals(NS_GET_IID(nsIDOMWindowInternal))) &&
- NS_SUCCEEDED(EnsureScriptEnvironment())) {
- return mScriptGlobal->QueryInterface(aIID, aSink);
- } else if (aIID.Equals(NS_GET_IID(nsIDOMDocument)) &&
- NS_SUCCEEDED(EnsureContentViewer())) {
- mContentViewer->GetDOMDocument((nsIDOMDocument**)aSink);
- return *aSink ? NS_OK : NS_NOINTERFACE;
- } else if (aIID.Equals(NS_GET_IID(nsIDocument)) &&
- NS_SUCCEEDED(EnsureContentViewer())) {
- nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
- doc.forget(aSink);
- return *aSink ? NS_OK : NS_NOINTERFACE;
- } else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) {
- *aSink = nullptr;
- // Return application cache associated with this docshell, if any
- nsCOMPtr<nsIContentViewer> contentViewer;
- GetContentViewer(getter_AddRefs(contentViewer));
- if (!contentViewer) {
- return NS_ERROR_NO_INTERFACE;
- }
- nsCOMPtr<nsIDOMDocument> domDoc;
- contentViewer->GetDOMDocument(getter_AddRefs(domDoc));
- NS_ASSERTION(domDoc, "Should have a document.");
- if (!domDoc) {
- return NS_ERROR_NO_INTERFACE;
- }
- #if defined(DEBUG)
- MOZ_LOG(gDocShellLog, LogLevel::Debug,
- ("nsDocShell[%p]: returning app cache container %p",
- this, domDoc.get()));
- #endif
- return domDoc->QueryInterface(aIID, aSink);
- } else if (aIID.Equals(NS_GET_IID(nsIPrompt)) &&
- NS_SUCCEEDED(EnsureScriptEnvironment())) {
- nsresult rv;
- nsCOMPtr<nsIWindowWatcher> wwatch =
- do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- // Get the an auth prompter for our window so that the parenting
- // of the dialogs works as it should when using tabs.
- nsIPrompt* prompt;
- rv = wwatch->GetNewPrompter(mScriptGlobal->AsOuter(), &prompt);
- NS_ENSURE_SUCCESS(rv, rv);
- *aSink = prompt;
- return NS_OK;
- } else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
- aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
- return NS_SUCCEEDED(GetAuthPrompt(PROMPT_NORMAL, aIID, aSink)) ?
- NS_OK : NS_NOINTERFACE;
- } else if (aIID.Equals(NS_GET_IID(nsISHistory))) {
- nsCOMPtr<nsISHistory> shistory;
- nsresult rv = GetSessionHistory(getter_AddRefs(shistory));
- if (NS_SUCCEEDED(rv) && shistory) {
- shistory.forget(aSink);
- return NS_OK;
- }
- return NS_NOINTERFACE;
- } else if (aIID.Equals(NS_GET_IID(nsIWebBrowserFind))) {
- nsresult rv = EnsureFind();
- if (NS_FAILED(rv)) {
- return rv;
- }
- *aSink = mFind;
- NS_ADDREF((nsISupports*)*aSink);
- return NS_OK;
- } else if (aIID.Equals(NS_GET_IID(nsIEditingSession))) {
- nsCOMPtr<nsIEditingSession> es;
- GetEditingSession(getter_AddRefs(es));
- es.forget(aSink);
- return *aSink ? NS_OK : NS_NOINTERFACE;
- } else if (aIID.Equals(NS_GET_IID(nsIClipboardDragDropHookList)) &&
- NS_SUCCEEDED(EnsureTransferableHookData())) {
- *aSink = mTransferableHookData;
- NS_ADDREF((nsISupports*)*aSink);
- return NS_OK;
- } else if (aIID.Equals(NS_GET_IID(nsISelectionDisplay))) {
- nsIPresShell* shell = GetPresShell();
- if (shell) {
- return shell->QueryInterface(aIID, aSink);
- }
- } else if (aIID.Equals(NS_GET_IID(nsIDocShellTreeOwner))) {
- nsCOMPtr<nsIDocShellTreeOwner> treeOwner;
- nsresult rv = GetTreeOwner(getter_AddRefs(treeOwner));
- if (NS_SUCCEEDED(rv) && treeOwner) {
- return treeOwner->QueryInterface(aIID, aSink);
- }
- } else if (aIID.Equals(NS_GET_IID(nsITabChild))) {
- *aSink = GetTabChild().take();
- return *aSink ? NS_OK : NS_ERROR_FAILURE;
- } else if (aIID.Equals(NS_GET_IID(nsIContentFrameMessageManager))) {
- nsCOMPtr<nsITabChild> tabChild =
- do_GetInterface(static_cast<nsIDocShell*>(this));
- nsCOMPtr<nsIContentFrameMessageManager> mm;
- if (tabChild) {
- tabChild->GetMessageManager(getter_AddRefs(mm));
- } else {
- if (nsPIDOMWindowOuter* win = GetWindow()) {
- mm = do_QueryInterface(win->GetParentTarget());
- }
- }
- *aSink = mm.get();
- } else {
- return nsDocLoader::GetInterface(aIID, aSink);
- }
- NS_IF_ADDREF(((nsISupports*)*aSink));
- return *aSink ? NS_OK : NS_NOINTERFACE;
- }
- uint32_t
- nsDocShell::ConvertDocShellLoadInfoToLoadType(
- nsDocShellInfoLoadType aDocShellLoadType)
- {
- uint32_t loadType = LOAD_NORMAL;
- switch (aDocShellLoadType) {
- case nsIDocShellLoadInfo::loadNormal:
- loadType = LOAD_NORMAL;
- break;
- case nsIDocShellLoadInfo::loadNormalReplace:
- loadType = LOAD_NORMAL_REPLACE;
- break;
- case nsIDocShellLoadInfo::loadNormalExternal:
- loadType = LOAD_NORMAL_EXTERNAL;
- break;
- case nsIDocShellLoadInfo::loadHistory:
- loadType = LOAD_HISTORY;
- break;
- case nsIDocShellLoadInfo::loadNormalBypassCache:
- loadType = LOAD_NORMAL_BYPASS_CACHE;
- break;
- case nsIDocShellLoadInfo::loadNormalBypassProxy:
- loadType = LOAD_NORMAL_BYPASS_PROXY;
- break;
- case nsIDocShellLoadInfo::loadNormalBypassProxyAndCache:
- loadType = LOAD_NORMAL_BYPASS_PROXY_AND_CACHE;
- break;
- case nsIDocShellLoadInfo::loadNormalAllowMixedContent:
- loadType = LOAD_NORMAL_ALLOW_MIXED_CONTENT;
- break;
- case nsIDocShellLoadInfo::loadReloadNormal:
- loadType = LOAD_RELOAD_NORMAL;
- break;
- case nsIDocShellLoadInfo::loadReloadCharsetChange:
- loadType = LOAD_RELOAD_CHARSET_CHANGE;
- break;
- case nsIDocShellLoadInfo::loadReloadBypassCache:
- loadType = LOAD_RELOAD_BYPASS_CACHE;
- break;
- case nsIDocShellLoadInfo::loadReloadBypassProxy:
- loadType = LOAD_RELOAD_BYPASS_PROXY;
- break;
- case nsIDocShellLoadInfo::loadReloadBypassProxyAndCache:
- loadType = LOAD_RELOAD_BYPASS_PROXY_AND_CACHE;
- break;
- case nsIDocShellLoadInfo::loadLink:
- loadType = LOAD_LINK;
- break;
- case nsIDocShellLoadInfo::loadRefresh:
- loadType = LOAD_REFRESH;
- break;
- case nsIDocShellLoadInfo::loadBypassHistory:
- loadType = LOAD_BYPASS_HISTORY;
- break;
- case nsIDocShellLoadInfo::loadStopContent:
- loadType = LOAD_STOP_CONTENT;
- break;
- case nsIDocShellLoadInfo::loadStopContentAndReplace:
- loadType = LOAD_STOP_CONTENT_AND_REPLACE;
- break;
- case nsIDocShellLoadInfo::loadPushState:
- loadType = LOAD_PUSHSTATE;
- break;
- case nsIDocShellLoadInfo::loadReplaceBypassCache:
- loadType = LOAD_REPLACE_BYPASS_CACHE;
- break;
- case nsIDocShellLoadInfo::loadReloadMixedContent:
- loadType = LOAD_RELOAD_ALLOW_MIXED_CONTENT;
- break;
- default:
- NS_NOTREACHED("Unexpected nsDocShellInfoLoadType value");
- }
- return loadType;
- }
- nsDocShellInfoLoadType
- nsDocShell::ConvertLoadTypeToDocShellLoadInfo(uint32_t aLoadType)
- {
- nsDocShellInfoLoadType docShellLoadType = nsIDocShellLoadInfo::loadNormal;
- switch (aLoadType) {
- case LOAD_NORMAL:
- docShellLoadType = nsIDocShellLoadInfo::loadNormal;
- break;
- case LOAD_NORMAL_REPLACE:
- docShellLoadType = nsIDocShellLoadInfo::loadNormalReplace;
- break;
- case LOAD_NORMAL_EXTERNAL:
- docShellLoadType = nsIDocShellLoadInfo::loadNormalExternal;
- break;
- case LOAD_NORMAL_BYPASS_CACHE:
- docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassCache;
- break;
- case LOAD_NORMAL_BYPASS_PROXY:
- docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxy;
- break;
- case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
- docShellLoadType = nsIDocShellLoadInfo::loadNormalBypassProxyAndCache;
- break;
- case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
- docShellLoadType = nsIDocShellLoadInfo::loadNormalAllowMixedContent;
- break;
- case LOAD_HISTORY:
- docShellLoadType = nsIDocShellLoadInfo::loadHistory;
- break;
- case LOAD_RELOAD_NORMAL:
- docShellLoadType = nsIDocShellLoadInfo::loadReloadNormal;
- break;
- case LOAD_RELOAD_CHARSET_CHANGE:
- docShellLoadType = nsIDocShellLoadInfo::loadReloadCharsetChange;
- break;
- case LOAD_RELOAD_BYPASS_CACHE:
- docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassCache;
- break;
- case LOAD_RELOAD_BYPASS_PROXY:
- docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxy;
- break;
- case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
- docShellLoadType = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache;
- break;
- case LOAD_LINK:
- docShellLoadType = nsIDocShellLoadInfo::loadLink;
- break;
- case LOAD_REFRESH:
- docShellLoadType = nsIDocShellLoadInfo::loadRefresh;
- break;
- case LOAD_BYPASS_HISTORY:
- case LOAD_ERROR_PAGE:
- docShellLoadType = nsIDocShellLoadInfo::loadBypassHistory;
- break;
- case LOAD_STOP_CONTENT:
- docShellLoadType = nsIDocShellLoadInfo::loadStopContent;
- break;
- case LOAD_STOP_CONTENT_AND_REPLACE:
- docShellLoadType = nsIDocShellLoadInfo::loadStopContentAndReplace;
- break;
- case LOAD_PUSHSTATE:
- docShellLoadType = nsIDocShellLoadInfo::loadPushState;
- break;
- case LOAD_REPLACE_BYPASS_CACHE:
- docShellLoadType = nsIDocShellLoadInfo::loadReplaceBypassCache;
- break;
- case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
- docShellLoadType = nsIDocShellLoadInfo::loadReloadMixedContent;
- break;
- default:
- NS_NOTREACHED("Unexpected load type value");
- }
- return docShellLoadType;
- }
- NS_IMETHODIMP
- nsDocShell::LoadURI(nsIURI* aURI,
- nsIDocShellLoadInfo* aLoadInfo,
- uint32_t aLoadFlags,
- bool aFirstParty)
- {
- NS_PRECONDITION(aLoadInfo || (aLoadFlags & EXTRA_LOAD_FLAGS) == 0,
- "Unexpected flags");
- NS_PRECONDITION((aLoadFlags & 0xf) == 0, "Should not have these flags set");
- // Note: we allow loads to get through here even if mFiredUnloadEvent is
- // true; that case will get handled in LoadInternal or LoadHistoryEntry,
- // so we pass false as the second parameter to IsNavigationAllowed.
- // However, we don't allow the page to change location *in the middle of*
- // firing beforeunload, so we do need to check if *beforeunload* is currently
- // firing, so we call IsNavigationAllowed rather than just IsPrintingOrPP.
- if (!IsNavigationAllowed(true, false)) {
- return NS_OK; // JS may not handle returning of an error code
- }
- nsCOMPtr<nsIURI> referrer;
- nsCOMPtr<nsIURI> originalURI;
- bool loadReplace = false;
- bool isFromProcessingFrameAttributes = false;
- nsCOMPtr<nsIInputStream> postStream;
- nsCOMPtr<nsIInputStream> headersStream;
- nsCOMPtr<nsIPrincipal> triggeringPrincipal;
- bool inheritPrincipal = false;
- bool principalIsExplicit = false;
- bool sendReferrer = true;
- uint32_t referrerPolicy = mozilla::net::RP_Default;
- bool isSrcdoc = false;
- nsCOMPtr<nsISHEntry> shEntry;
- nsXPIDLString target;
- nsAutoString srcdoc;
- bool forceAllowDataURI = false;
- nsCOMPtr<nsIDocShell> sourceDocShell;
- nsCOMPtr<nsIURI> baseURI;
- uint32_t loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
- NS_ENSURE_ARG(aURI);
- if (!StartupTimeline::HasRecord(StartupTimeline::FIRST_LOAD_URI) &&
- mItemType == typeContent && !NS_IsAboutBlank(aURI)) {
- StartupTimeline::RecordOnce(StartupTimeline::FIRST_LOAD_URI);
- }
- // Extract the info from the DocShellLoadInfo struct...
- if (aLoadInfo) {
- aLoadInfo->GetReferrer(getter_AddRefs(referrer));
- aLoadInfo->GetOriginalURI(getter_AddRefs(originalURI));
- aLoadInfo->GetLoadReplace(&loadReplace);
- aLoadInfo->GetIsFromProcessingFrameAttributes(&isFromProcessingFrameAttributes);
- nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
- aLoadInfo->GetLoadType(<);
- // Get the appropriate loadType from nsIDocShellLoadInfo type
- loadType = ConvertDocShellLoadInfoToLoadType(lt);
- aLoadInfo->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal));
- aLoadInfo->GetInheritPrincipal(&inheritPrincipal);
- aLoadInfo->GetPrincipalIsExplicit(&principalIsExplicit);
- aLoadInfo->GetSHEntry(getter_AddRefs(shEntry));
- aLoadInfo->GetTarget(getter_Copies(target));
- aLoadInfo->GetPostDataStream(getter_AddRefs(postStream));
- aLoadInfo->GetHeadersStream(getter_AddRefs(headersStream));
- aLoadInfo->GetSendReferrer(&sendReferrer);
- aLoadInfo->GetReferrerPolicy(&referrerPolicy);
- aLoadInfo->GetIsSrcdocLoad(&isSrcdoc);
- aLoadInfo->GetSrcdocData(srcdoc);
- aLoadInfo->GetSourceDocShell(getter_AddRefs(sourceDocShell));
- aLoadInfo->GetBaseURI(getter_AddRefs(baseURI));
- aLoadInfo->GetForceAllowDataURI(&forceAllowDataURI);
- }
- #if defined(DEBUG)
- if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
- nsAutoCString uristr;
- aURI->GetAsciiSpec(uristr);
- MOZ_LOG(gDocShellLog, LogLevel::Debug,
- ("nsDocShell[%p]: loading %s with flags 0x%08x",
- this, uristr.get(), aLoadFlags));
- }
- #endif
- if (!shEntry &&
- !LOAD_TYPE_HAS_FLAGS(loadType, LOAD_FLAGS_REPLACE_HISTORY)) {
- // First verify if this is a subframe.
- nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
- GetSameTypeParent(getter_AddRefs(parentAsItem));
- nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
- uint32_t parentLoadType;
- if (parentDS && parentDS != static_cast<nsIDocShell*>(this)) {
- /* OK. It is a subframe. Checkout the
- * parent's loadtype. If the parent was loaded thro' a history
- * mechanism, then get the SH entry for the child from the parent.
- * This is done to restore frameset navigation while going back/forward.
- * If the parent was loaded through any other loadType, set the
- * child's loadType too accordingly, so that session history does not
- * get confused.
- */
- // Get the parent's load type
- parentDS->GetLoadType(&parentLoadType);
- // Get the ShEntry for the child from the parent
- nsCOMPtr<nsISHEntry> currentSH;
- bool oshe = false;
- parentDS->GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
- bool dynamicallyAddedChild = mDynamicallyCreated;
- if (!dynamicallyAddedChild && !oshe && currentSH) {
- currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
- }
- if (!dynamicallyAddedChild) {
- // Only use the old SHEntry, if we're sure enough that
- // it wasn't originally for some other frame.
- parentDS->GetChildSHEntry(mChildOffset, getter_AddRefs(shEntry));
- }
- // Make some decisions on the child frame's loadType based on the
- // parent's loadType.
- if (!mCurrentURI) {
- // This is a newly created frame. Check for exception cases first.
- // By default the subframe will inherit the parent's loadType.
- if (shEntry && (parentLoadType == LOAD_NORMAL ||
- parentLoadType == LOAD_LINK ||
- parentLoadType == LOAD_NORMAL_EXTERNAL)) {
- // The parent was loaded normally. In this case, this *brand new*
- // child really shouldn't have a SHEntry. If it does, it could be
- // because the parent is replacing an existing frame with a new frame,
- // in the onLoadHandler. We don't want this url to get into session
- // history. Clear off shEntry, and set load type to
- // LOAD_BYPASS_HISTORY.
- bool inOnLoadHandler = false;
- parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
- if (inOnLoadHandler) {
- loadType = LOAD_NORMAL_REPLACE;
- shEntry = nullptr;
- }
- } else if (parentLoadType == LOAD_REFRESH) {
- // Clear shEntry. For refresh loads, we have to load
- // what comes thro' the pipe, not what's in history.
- shEntry = nullptr;
- } else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
- (shEntry &&
- ((parentLoadType & LOAD_CMD_HISTORY) ||
- (parentLoadType == LOAD_RELOAD_NORMAL) ||
- (parentLoadType == LOAD_RELOAD_CHARSET_CHANGE)))) {
- // If the parent url, bypassed history or was loaded from
- // history, pass on the parent's loadType to the new child
- // frame too, so that the child frame will also
- // avoid getting into history.
- loadType = parentLoadType;
- } else if (parentLoadType == LOAD_ERROR_PAGE) {
- // If the parent document is an error page, we don't
- // want to update global/session history. However,
- // this child frame is not an error page.
- loadType = LOAD_BYPASS_HISTORY;
- } else if ((parentLoadType == LOAD_RELOAD_BYPASS_CACHE) ||
- (parentLoadType == LOAD_RELOAD_BYPASS_PROXY) ||
- (parentLoadType == LOAD_RELOAD_BYPASS_PROXY_AND_CACHE)) {
- // the new frame should inherit the parent's load type so that it also
- // bypasses the cache and/or proxy
- loadType = parentLoadType;
- }
- } else {
- // This is a pre-existing subframe. If the load was not originally
- // initiated by session history, (if (!shEntry) condition succeeded) and
- // mCurrentURI is not null, it is possible that a parent's onLoadHandler
- // or even self's onLoadHandler is loading a new page in this child.
- // Check parent's and self's busy flag and if it is set, we don't want
- // this onLoadHandler load to get in to session history.
- uint32_t parentBusy = BUSY_FLAGS_NONE;
- uint32_t selfBusy = BUSY_FLAGS_NONE;
- parentDS->GetBusyFlags(&parentBusy);
- GetBusyFlags(&selfBusy);
- if (parentBusy & BUSY_FLAGS_BUSY ||
- selfBusy & BUSY_FLAGS_BUSY) {
- loadType = LOAD_NORMAL_REPLACE;
- shEntry = nullptr;
- }
- }
- } // parentDS
- else {
- // This is the root docshell. If we got here while
- // executing an onLoad Handler,this load will not go
- // into session history.
- bool inOnLoadHandler = false;
- GetIsExecutingOnLoadHandler(&inOnLoadHandler);
- if (inOnLoadHandler) {
- loadType = LOAD_NORMAL_REPLACE;
- }
- }
- } // !shEntry
- if (shEntry) {
- #ifdef DEBUG
- MOZ_LOG(gDocShellLog, LogLevel::Debug,
- ("nsDocShell[%p]: loading from session history", this));
- #endif
- return LoadHistoryEntry(shEntry, loadType);
- }
- // On history navigation via Back/Forward buttons, don't execute
- // automatic JavaScript redirection such as |location.href = ...| or
- // |window.open()|
- //
- // LOAD_NORMAL: window.open(...) etc.
- // LOAD_STOP_CONTENT: location.href = ..., location.assign(...)
- if ((loadType == LOAD_NORMAL || loadType == LOAD_STOP_CONTENT) &&
- ShouldBlockLoadingForBackButton()) {
- return NS_OK;
- }
- // Perform the load...
- // We need a principalToInherit.
- //
- // If principalIsExplicit is not set there are 4 possibilities:
- // (1) If the system principal or an expanded principal was passed
- // in and we're a typeContent docshell, inherit the principal
- // from the current document instead.
- // (2) In all other cases when the principal passed in is not null,
- // use that principal.
- // (3) If the caller has allowed inheriting from the current document,
- // or if we're being called from system code (eg chrome JS or pure
- // C++) then inheritPrincipal should be true and InternalLoad will get
- // a principal from the current document. If none of these things are
- // true, then
- // (4) we don't pass a principal into the channel, and a principal will be
- // created later from the channel's internal data.
- //
- // If principalIsExplicit *is* set, there are 4 possibilities
- // (1) If the system principal or an expanded principal was passed in
- // and we're a typeContent docshell, return an error.
- // (2) In all other cases when the principal passed in is not null,
- // use that principal.
- // (3) If the caller has allowed inheriting from the current document,
- // then inheritPrincipal should be true and InternalLoad will get
- // a principal from the current document. If none of these things are
- // true, then
- // (4) we dont' pass a principal into the channel, and a principal will be
- // created later from the channel's internal data.
- nsCOMPtr<nsIPrincipal> principalToInherit = triggeringPrincipal;
- if (principalToInherit && mItemType != typeChrome) {
- if (nsContentUtils::IsSystemPrincipal(principalToInherit)) {
- if (principalIsExplicit) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- principalToInherit = nullptr;
- inheritPrincipal = true;
- } else if (nsContentUtils::IsExpandedPrincipal(principalToInherit)) {
- if (principalIsExplicit) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- // Don't inherit from the current page. Just do the safe thing
- // and pretend that we were loaded by a nullprincipal.
- //
- // We didn't inherit OriginAttributes here as ExpandedPrincipal doesn't
- // have origin attributes.
- principalToInherit = nsNullPrincipal::CreateWithInheritedAttributes(this);
- inheritPrincipal = false;
- }
- }
- if (!principalToInherit && !inheritPrincipal && !principalIsExplicit) {
- // See if there's system or chrome JS code running
- inheritPrincipal = nsContentUtils::LegacyIsCallerChromeOrNativeCode();
- }
- if (aLoadFlags & LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL) {
- inheritPrincipal = false;
- principalToInherit = nsNullPrincipal::CreateWithInheritedAttributes(this);
- }
- // If the triggeringPrincipal is not passed explicitly, we first try to create
- // a principal from the referrer, since the referrer URI reflects the web origin
- // that triggered the load. If there is no referrer URI, we fall back to using
- // the SystemPrincipal. It's safe to assume that no provided triggeringPrincipal
- // and no referrer simulate a load that was triggered by the system.
- // It's important to note that this block of code needs to appear *after* the block
- // where we munge the principalToInherit, because otherwise we would never enter
- // code blocks checking if the principalToInherit is null and we will end up with
- // a wrong inheritPrincipal flag.
- if (!triggeringPrincipal) {
- if (referrer) {
- nsresult rv = CreatePrincipalFromReferrer(referrer,
- getter_AddRefs(triggeringPrincipal));
- NS_ENSURE_SUCCESS(rv, rv);
- }
- else {
- triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
- }
- }
- uint32_t flags = 0;
- if (inheritPrincipal) {
- flags |= INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
- }
- if (!sendReferrer) {
- flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER;
- }
- if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
- flags |= INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
- }
- if (aLoadFlags & LOAD_FLAGS_FIRST_LOAD) {
- flags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
- }
- if (aLoadFlags & LOAD_FLAGS_BYPASS_CLASSIFIER) {
- flags |= INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER;
- }
- if (aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_COOKIES) {
- flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES;
- }
- if (isSrcdoc) {
- flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
- }
- if (forceAllowDataURI) {
- flags |= INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
- }
- return InternalLoad(aURI,
- originalURI,
- loadReplace,
- isFromProcessingFrameAttributes,
- referrer,
- referrerPolicy,
- triggeringPrincipal,
- principalToInherit,
- flags,
- target,
- nullptr, // No type hint
- NullString(), // No forced download
- postStream,
- headersStream,
- loadType,
- nullptr, // No SHEntry
- aFirstParty,
- srcdoc,
- sourceDocShell,
- baseURI,
- nullptr, // No nsIDocShell
- nullptr); // No nsIRequest
- }
- NS_IMETHODIMP
- nsDocShell::LoadStream(nsIInputStream* aStream, nsIURI* aURI,
- const nsACString& aContentType,
- const nsACString& aContentCharset,
- nsIDocShellLoadInfo* aLoadInfo)
- {
- NS_ENSURE_ARG(aStream);
- mAllowKeywordFixup = false;
- // if the caller doesn't pass in a URI we need to create a dummy URI. necko
- // currently requires a URI in various places during the load. Some consumers
- // do as well.
- nsCOMPtr<nsIURI> uri = aURI;
- if (!uri) {
- // HACK ALERT
- nsresult rv = NS_OK;
- uri = do_CreateInstance(NS_SIMPLEURI_CONTRACTID, &rv);
- if (NS_FAILED(rv)) {
- return rv;
- }
- // Make sure that the URI spec "looks" like a protocol and path...
- // For now, just use a bogus protocol called "internal"
- rv = uri->SetSpec(NS_LITERAL_CSTRING("internal:load-stream"));
- if (NS_FAILED(rv)) {
- return rv;
- }
- }
- uint32_t loadType = LOAD_NORMAL;
- nsCOMPtr<nsIPrincipal> triggeringPrincipal;
- if (aLoadInfo) {
- nsDocShellInfoLoadType lt = nsIDocShellLoadInfo::loadNormal;
- (void)aLoadInfo->GetLoadType(<);
- // Get the appropriate LoadType from nsIDocShellLoadInfo type
- loadType = ConvertDocShellLoadInfoToLoadType(lt);
- aLoadInfo->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal));
- }
- NS_ENSURE_SUCCESS(Stop(nsIWebNavigation::STOP_NETWORK), NS_ERROR_FAILURE);
- mLoadType = loadType;
- if (!triggeringPrincipal) {
- triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
- }
- // build up a channel for this stream.
- nsCOMPtr<nsIChannel> channel;
- nsresult rv = NS_NewInputStreamChannel(getter_AddRefs(channel),
- uri,
- aStream,
- triggeringPrincipal,
- nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
- nsIContentPolicy::TYPE_OTHER,
- aContentType,
- aContentCharset);
- NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
- nsCOMPtr<nsIURILoader> uriLoader(do_GetService(NS_URI_LOADER_CONTRACTID));
- NS_ENSURE_TRUE(uriLoader, NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(DoChannelLoad(channel, uriLoader, false),
- NS_ERROR_FAILURE);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::CreateLoadInfo(nsIDocShellLoadInfo** aLoadInfo)
- {
- nsDocShellLoadInfo* loadInfo = new nsDocShellLoadInfo();
- nsCOMPtr<nsIDocShellLoadInfo> localRef(loadInfo);
- localRef.forget(aLoadInfo);
- return NS_OK;
- }
- /*
- * Reset state to a new content model within the current document and the
- * document viewer. Called by the document before initiating an out of band
- * document.write().
- */
- NS_IMETHODIMP
- nsDocShell::PrepareForNewContentModel()
- {
- mEODForCurrentDocument = false;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::FirePageHideNotification(bool aIsUnload)
- {
- if (mContentViewer && !mFiredUnloadEvent) {
- // Keep an explicit reference since calling PageHide could release
- // mContentViewer
- nsCOMPtr<nsIContentViewer> contentViewer(mContentViewer);
- mFiredUnloadEvent = true;
- if (mTiming) {
- mTiming->NotifyUnloadEventStart();
- }
- contentViewer->PageHide(aIsUnload);
- if (mTiming) {
- mTiming->NotifyUnloadEventEnd();
- }
- AutoTArray<nsCOMPtr<nsIDocShell>, 8> kids;
- uint32_t n = mChildList.Length();
- kids.SetCapacity(n);
- for (uint32_t i = 0; i < n; i++) {
- kids.AppendElement(do_QueryInterface(ChildAt(i)));
- }
- n = kids.Length();
- for (uint32_t i = 0; i < n; ++i) {
- if (kids[i]) {
- kids[i]->FirePageHideNotification(aIsUnload);
- }
- }
- // Now make sure our editor, if any, is detached before we go
- // any farther.
- DetachEditorFromWindow();
- }
- return NS_OK;
- }
- void
- nsDocShell::MaybeInitTiming()
- {
- if (mTiming && !mBlankTiming) {
- return;
- }
- if (mScriptGlobal && mBlankTiming) {
- nsPIDOMWindowInner* innerWin =
- mScriptGlobal->AsOuter()->GetCurrentInnerWindow();
- if (innerWin && innerWin->GetPerformance()) {
- mTiming = innerWin->GetPerformance()->GetDOMTiming();
- mBlankTiming = false;
- }
- }
- if (!mTiming) {
- mTiming = new nsDOMNavigationTiming();
- }
- mTiming->NotifyNavigationStart(
- mIsActive ? nsDOMNavigationTiming::DocShellState::eActive
- : nsDOMNavigationTiming::DocShellState::eInactive);
- }
- //
- // Bug 13871: Prevent frameset spoofing
- //
- // This routine answers: 'Is origin's document from same domain as
- // target's document?'
- //
- // file: uris are considered the same domain for the purpose of
- // frame navigation regardless of script accessibility (bug 420425)
- //
- /* static */ bool
- nsDocShell::ValidateOrigin(nsIDocShellTreeItem* aOriginTreeItem,
- nsIDocShellTreeItem* aTargetTreeItem)
- {
- // We want to bypass this check for chrome callers, but only if there's
- // JS on the stack. System callers still need to do it.
- if (nsContentUtils::GetCurrentJSContext() &&
- nsContentUtils::IsCallerChrome()) {
- return true;
- }
- MOZ_ASSERT(aOriginTreeItem && aTargetTreeItem, "need two docshells");
- // Get origin document principal
- nsCOMPtr<nsIDocument> originDocument = aOriginTreeItem->GetDocument();
- NS_ENSURE_TRUE(originDocument, false);
- // Get target principal
- nsCOMPtr<nsIDocument> targetDocument = aTargetTreeItem->GetDocument();
- NS_ENSURE_TRUE(targetDocument, false);
- bool equal;
- nsresult rv = originDocument->NodePrincipal()->Equals(
- targetDocument->NodePrincipal(), &equal);
- if (NS_SUCCEEDED(rv) && equal) {
- return true;
- }
- // Not strictly equal, special case if both are file: uris
- bool originIsFile = false;
- bool targetIsFile = false;
- nsCOMPtr<nsIURI> originURI;
- nsCOMPtr<nsIURI> targetURI;
- nsCOMPtr<nsIURI> innerOriginURI;
- nsCOMPtr<nsIURI> innerTargetURI;
- rv = originDocument->NodePrincipal()->GetURI(getter_AddRefs(originURI));
- if (NS_SUCCEEDED(rv) && originURI) {
- innerOriginURI = NS_GetInnermostURI(originURI);
- }
- rv = targetDocument->NodePrincipal()->GetURI(getter_AddRefs(targetURI));
- if (NS_SUCCEEDED(rv) && targetURI) {
- innerTargetURI = NS_GetInnermostURI(targetURI);
- }
- return innerOriginURI && innerTargetURI &&
- NS_SUCCEEDED(innerOriginURI->SchemeIs("file", &originIsFile)) &&
- NS_SUCCEEDED(innerTargetURI->SchemeIs("file", &targetIsFile)) &&
- originIsFile && targetIsFile;
- }
- nsresult
- nsDocShell::GetEldestPresContext(nsPresContext** aPresContext)
- {
- NS_ENSURE_ARG_POINTER(aPresContext);
- *aPresContext = nullptr;
- nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
- while (viewer) {
- nsCOMPtr<nsIContentViewer> prevViewer;
- viewer->GetPreviousViewer(getter_AddRefs(prevViewer));
- if (!prevViewer) {
- return viewer->GetPresContext(aPresContext);
- }
- viewer = prevViewer;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetPresContext(nsPresContext** aPresContext)
- {
- NS_ENSURE_ARG_POINTER(aPresContext);
- *aPresContext = nullptr;
- if (!mContentViewer) {
- return NS_OK;
- }
- return mContentViewer->GetPresContext(aPresContext);
- }
- NS_IMETHODIMP_(nsIPresShell*)
- nsDocShell::GetPresShell()
- {
- RefPtr<nsPresContext> presContext;
- (void)GetPresContext(getter_AddRefs(presContext));
- return presContext ? presContext->GetPresShell() : nullptr;
- }
- NS_IMETHODIMP
- nsDocShell::GetEldestPresShell(nsIPresShell** aPresShell)
- {
- nsresult rv = NS_OK;
- NS_ENSURE_ARG_POINTER(aPresShell);
- *aPresShell = nullptr;
- RefPtr<nsPresContext> presContext;
- (void)GetEldestPresContext(getter_AddRefs(presContext));
- if (presContext) {
- NS_IF_ADDREF(*aPresShell = presContext->GetPresShell());
- }
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::GetContentViewer(nsIContentViewer** aContentViewer)
- {
- NS_ENSURE_ARG_POINTER(aContentViewer);
- *aContentViewer = mContentViewer;
- NS_IF_ADDREF(*aContentViewer);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetChromeEventHandler(nsIDOMEventTarget* aChromeEventHandler)
- {
- // Weak reference. Don't addref.
- nsCOMPtr<EventTarget> handler = do_QueryInterface(aChromeEventHandler);
- mChromeEventHandler = handler.get();
- if (mScriptGlobal) {
- mScriptGlobal->SetChromeEventHandler(mChromeEventHandler);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetChromeEventHandler(nsIDOMEventTarget** aChromeEventHandler)
- {
- NS_ENSURE_ARG_POINTER(aChromeEventHandler);
- nsCOMPtr<EventTarget> handler = mChromeEventHandler;
- handler.forget(aChromeEventHandler);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetCurrentURI(nsIURI* aURI)
- {
- // Note that securityUI will set STATE_IS_INSECURE, even if
- // the scheme of |aURI| is "https".
- SetCurrentURI(aURI, nullptr, true, 0);
- return NS_OK;
- }
- bool
- nsDocShell::SetCurrentURI(nsIURI* aURI, nsIRequest* aRequest,
- bool aFireOnLocationChange, uint32_t aLocationFlags)
- {
- if (gDocShellLeakLog && MOZ_LOG_TEST(gDocShellLeakLog, LogLevel::Debug)) {
- PR_LogPrint("DOCSHELL %p SetCurrentURI %s\n",
- this, aURI ? aURI->GetSpecOrDefault().get() : "");
- }
- // We don't want to send a location change when we're displaying an error
- // page, and we don't want to change our idea of "current URI" either
- if (mLoadType == LOAD_ERROR_PAGE) {
- return false;
- }
- mCurrentURI = NS_TryToMakeImmutable(aURI);
- if (!NS_IsAboutBlank(mCurrentURI)) {
- mHasLoadedNonBlankURI = true;
- }
- bool isRoot = false; // Is this the root docshell
- bool isSubFrame = false; // Is this a subframe navigation?
- nsCOMPtr<nsIDocShellTreeItem> root;
- GetSameTypeRootTreeItem(getter_AddRefs(root));
- if (root.get() == static_cast<nsIDocShellTreeItem*>(this)) {
- // This is the root docshell
- isRoot = true;
- }
- if (mLSHE) {
- mLSHE->GetIsSubFrame(&isSubFrame);
- }
- if (!isSubFrame && !isRoot) {
- /*
- * We don't want to send OnLocationChange notifications when
- * a subframe is being loaded for the first time, while
- * visiting a frameset page
- */
- return false;
- }
- if (aFireOnLocationChange) {
- FireOnLocationChange(this, aRequest, aURI, aLocationFlags);
- }
- return !aFireOnLocationChange;
- }
- NS_IMETHODIMP
- nsDocShell::GetCharset(nsACString& aCharset)
- {
- aCharset.Truncate();
- nsIPresShell* presShell = GetPresShell();
- NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
- nsIDocument* doc = presShell->GetDocument();
- NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
- aCharset = doc->GetDocumentCharacterSet();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GatherCharsetMenuTelemetry()
- {
- /* STUB */
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetCharset(const nsACString& aCharset)
- {
- // set the charset override
- return SetForcedCharset(aCharset);
- }
- NS_IMETHODIMP
- nsDocShell::SetForcedCharset(const nsACString& aCharset)
- {
- if (aCharset.IsEmpty()) {
- mForcedCharset.Truncate();
- return NS_OK;
- }
- nsAutoCString encoding;
- if (!EncodingUtils::FindEncodingForLabel(aCharset, encoding)) {
- // Reject unknown labels
- return NS_ERROR_INVALID_ARG;
- }
- if (!EncodingUtils::IsAsciiCompatible(encoding)) {
- // Reject XSS hazards
- return NS_ERROR_INVALID_ARG;
- }
- mForcedCharset = encoding;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetForcedCharset(nsACString& aResult)
- {
- aResult = mForcedCharset;
- return NS_OK;
- }
- void
- nsDocShell::SetParentCharset(const nsACString& aCharset,
- int32_t aCharsetSource,
- nsIPrincipal* aPrincipal)
- {
- mParentCharset = aCharset;
- mParentCharsetSource = aCharsetSource;
- mParentCharsetPrincipal = aPrincipal;
- }
- void
- nsDocShell::GetParentCharset(nsACString& aCharset,
- int32_t* aCharsetSource,
- nsIPrincipal** aPrincipal)
- {
- aCharset = mParentCharset;
- *aCharsetSource = mParentCharsetSource;
- NS_IF_ADDREF(*aPrincipal = mParentCharsetPrincipal);
- }
- NS_IMETHODIMP
- nsDocShell::GetChannelIsUnsafe(bool* aUnsafe)
- {
- *aUnsafe = false;
- nsIChannel* channel = GetCurrentDocChannel();
- if (!channel) {
- return NS_OK;
- }
- nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(channel);
- if (!jarChannel) {
- return NS_OK;
- }
- return jarChannel->GetIsUnsafe(aUnsafe);
- }
- NS_IMETHODIMP
- nsDocShell::GetHasMixedActiveContentLoaded(bool* aHasMixedActiveContentLoaded)
- {
- nsCOMPtr<nsIDocument> doc(GetDocument());
- *aHasMixedActiveContentLoaded = doc && doc->GetHasMixedActiveContentLoaded();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetHasMixedActiveContentBlocked(bool* aHasMixedActiveContentBlocked)
- {
- nsCOMPtr<nsIDocument> doc(GetDocument());
- *aHasMixedActiveContentBlocked =
- doc && doc->GetHasMixedActiveContentBlocked();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetHasMixedDisplayContentLoaded(bool* aHasMixedDisplayContentLoaded)
- {
- nsCOMPtr<nsIDocument> doc(GetDocument());
- *aHasMixedDisplayContentLoaded =
- doc && doc->GetHasMixedDisplayContentLoaded();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetHasMixedDisplayContentBlocked(
- bool* aHasMixedDisplayContentBlocked)
- {
- nsCOMPtr<nsIDocument> doc(GetDocument());
- *aHasMixedDisplayContentBlocked =
- doc && doc->GetHasMixedDisplayContentBlocked();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetHasTrackingContentBlocked(bool* aHasTrackingContentBlocked)
- {
- nsCOMPtr<nsIDocument> doc(GetDocument());
- *aHasTrackingContentBlocked = doc && doc->GetHasTrackingContentBlocked();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetHasTrackingContentLoaded(bool* aHasTrackingContentLoaded)
- {
- nsCOMPtr<nsIDocument> doc(GetDocument());
- *aHasTrackingContentLoaded = doc && doc->GetHasTrackingContentLoaded();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetAllowPlugins(bool* aAllowPlugins)
- {
- NS_ENSURE_ARG_POINTER(aAllowPlugins);
- *aAllowPlugins = mAllowPlugins;
- if (!mAllowPlugins) {
- return NS_OK;
- }
- bool unsafe;
- *aAllowPlugins = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetAllowPlugins(bool aAllowPlugins)
- {
- mAllowPlugins = aAllowPlugins;
- // XXX should enable or disable a plugin host
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetAllowJavascript(bool* aAllowJavascript)
- {
- NS_ENSURE_ARG_POINTER(aAllowJavascript);
- *aAllowJavascript = mAllowJavascript;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetAllowJavascript(bool aAllowJavascript)
- {
- mAllowJavascript = aAllowJavascript;
- RecomputeCanExecuteScripts();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetUsePrivateBrowsing(bool* aUsePrivateBrowsing)
- {
- NS_ENSURE_ARG_POINTER(aUsePrivateBrowsing);
- AssertOriginAttributesMatchPrivateBrowsing();
- *aUsePrivateBrowsing = mPrivateBrowsingId > 0;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetUsePrivateBrowsing(bool aUsePrivateBrowsing)
- {
- nsContentUtils::ReportToConsoleNonLocalized(
- NS_LITERAL_STRING("Only internal code is allowed to set the usePrivateBrowsing attribute"),
- nsIScriptError::warningFlag,
- NS_LITERAL_CSTRING("Internal API Used"),
- mContentViewer ? mContentViewer->GetDocument() : nullptr);
- if (!CanSetOriginAttributes()) {
- bool changed = aUsePrivateBrowsing != (mPrivateBrowsingId > 0);
- return changed ? NS_ERROR_FAILURE : NS_OK;
- }
- return SetPrivateBrowsing(aUsePrivateBrowsing);
- }
- NS_IMETHODIMP
- nsDocShell::SetPrivateBrowsing(bool aUsePrivateBrowsing)
- {
- bool changed = aUsePrivateBrowsing != (mPrivateBrowsingId > 0);
- if (changed) {
- mPrivateBrowsingId = aUsePrivateBrowsing ? 1 : 0;
- if (mItemType != typeChrome) {
- mOriginAttributes.SyncAttributesWithPrivateBrowsing(aUsePrivateBrowsing);
- }
- if (mAffectPrivateSessionLifetime) {
- if (aUsePrivateBrowsing) {
- IncreasePrivateDocShellCount();
- } else {
- DecreasePrivateDocShellCount();
- }
- }
- }
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- nsCOMPtr<nsILoadContext> shell = do_QueryObject(iter.GetNext());
- if (shell) {
- shell->SetPrivateBrowsing(aUsePrivateBrowsing);
- }
- }
- if (changed) {
- nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mPrivacyObservers);
- while (iter.HasMore()) {
- nsWeakPtr ref = iter.GetNext();
- nsCOMPtr<nsIPrivacyTransitionObserver> obs = do_QueryReferent(ref);
- if (!obs) {
- mPrivacyObservers.RemoveElement(ref);
- } else {
- obs->PrivateModeChanged(aUsePrivateBrowsing);
- }
- }
- }
- AssertOriginAttributesMatchPrivateBrowsing();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetHasLoadedNonBlankURI(bool* aResult)
- {
- NS_ENSURE_ARG_POINTER(aResult);
- *aResult = mHasLoadedNonBlankURI;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetUseRemoteTabs(bool* aUseRemoteTabs)
- {
- NS_ENSURE_ARG_POINTER(aUseRemoteTabs);
- *aUseRemoteTabs = mUseRemoteTabs;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetRemoteTabs(bool aUseRemoteTabs)
- {
- mUseRemoteTabs = aUseRemoteTabs;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetAffectPrivateSessionLifetime(bool aAffectLifetime)
- {
- bool change = aAffectLifetime != mAffectPrivateSessionLifetime;
- if (change && UsePrivateBrowsing()) {
- AssertOriginAttributesMatchPrivateBrowsing();
- if (aAffectLifetime) {
- IncreasePrivateDocShellCount();
- } else {
- DecreasePrivateDocShellCount();
- }
- }
- mAffectPrivateSessionLifetime = aAffectLifetime;
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
- if (shell) {
- shell->SetAffectPrivateSessionLifetime(aAffectLifetime);
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetAffectPrivateSessionLifetime(bool* aAffectLifetime)
- {
- *aAffectLifetime = mAffectPrivateSessionLifetime;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::AddWeakPrivacyTransitionObserver(
- nsIPrivacyTransitionObserver* aObserver)
- {
- nsWeakPtr weakObs = do_GetWeakReference(aObserver);
- if (!weakObs) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- return mPrivacyObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsDocShell::AddWeakReflowObserver(nsIReflowObserver* aObserver)
- {
- nsWeakPtr weakObs = do_GetWeakReference(aObserver);
- if (!weakObs) {
- return NS_ERROR_FAILURE;
- }
- return mReflowObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsDocShell::RemoveWeakReflowObserver(nsIReflowObserver* aObserver)
- {
- nsWeakPtr obs = do_GetWeakReference(aObserver);
- return mReflowObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsDocShell::NotifyReflowObservers(bool aInterruptible,
- DOMHighResTimeStamp aStart,
- DOMHighResTimeStamp aEnd)
- {
- nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mReflowObservers);
- while (iter.HasMore()) {
- nsWeakPtr ref = iter.GetNext();
- nsCOMPtr<nsIReflowObserver> obs = do_QueryReferent(ref);
- if (!obs) {
- mReflowObservers.RemoveElement(ref);
- } else if (aInterruptible) {
- obs->ReflowInterruptible(aStart, aEnd);
- } else {
- obs->Reflow(aStart, aEnd);
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetAllowMetaRedirects(bool* aReturn)
- {
- NS_ENSURE_ARG_POINTER(aReturn);
- *aReturn = mAllowMetaRedirects;
- if (!mAllowMetaRedirects) {
- return NS_OK;
- }
- bool unsafe;
- *aReturn = NS_SUCCEEDED(GetChannelIsUnsafe(&unsafe)) && !unsafe;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetAllowMetaRedirects(bool aValue)
- {
- mAllowMetaRedirects = aValue;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetAllowSubframes(bool* aAllowSubframes)
- {
- NS_ENSURE_ARG_POINTER(aAllowSubframes);
- *aAllowSubframes = mAllowSubframes;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetAllowSubframes(bool aAllowSubframes)
- {
- mAllowSubframes = aAllowSubframes;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetAllowImages(bool* aAllowImages)
- {
- NS_ENSURE_ARG_POINTER(aAllowImages);
- *aAllowImages = mAllowImages;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetAllowImages(bool aAllowImages)
- {
- mAllowImages = aAllowImages;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetAllowMedia(bool* aAllowMedia)
- {
- *aAllowMedia = mAllowMedia;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetAllowMedia(bool aAllowMedia)
- {
- mAllowMedia = aAllowMedia;
- // Mute or unmute audio contexts attached to the inner window.
- if (mScriptGlobal) {
- if (nsPIDOMWindowInner* innerWin =
- mScriptGlobal->AsOuter()->GetCurrentInnerWindow()) {
- if (aAllowMedia) {
- innerWin->UnmuteAudioContexts();
- } else {
- innerWin->MuteAudioContexts();
- }
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetAllowDNSPrefetch(bool* aAllowDNSPrefetch)
- {
- *aAllowDNSPrefetch = mAllowDNSPrefetch;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetAllowDNSPrefetch(bool aAllowDNSPrefetch)
- {
- mAllowDNSPrefetch = aAllowDNSPrefetch;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetAllowWindowControl(bool* aAllowWindowControl)
- {
- *aAllowWindowControl = mAllowWindowControl;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetAllowWindowControl(bool aAllowWindowControl)
- {
- mAllowWindowControl = aAllowWindowControl;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetAllowContentRetargeting(bool* aAllowContentRetargeting)
- {
- *aAllowContentRetargeting = mAllowContentRetargeting;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetAllowContentRetargeting(bool aAllowContentRetargeting)
- {
- mAllowContentRetargetingOnChildren = aAllowContentRetargeting;
- mAllowContentRetargeting = aAllowContentRetargeting;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetAllowContentRetargetingOnChildren(
- bool* aAllowContentRetargetingOnChildren)
- {
- *aAllowContentRetargetingOnChildren = mAllowContentRetargetingOnChildren;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetAllowContentRetargetingOnChildren(
- bool aAllowContentRetargetingOnChildren)
- {
- mAllowContentRetargetingOnChildren = aAllowContentRetargetingOnChildren;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetInheritPrivateBrowsingId(bool* aInheritPrivateBrowsingId)
- {
- *aInheritPrivateBrowsingId = mInheritPrivateBrowsingId;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetInheritPrivateBrowsingId(bool aInheritPrivateBrowsingId)
- {
- mInheritPrivateBrowsingId = aInheritPrivateBrowsingId;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetFullscreenAllowed(bool* aFullscreenAllowed)
- {
- NS_ENSURE_ARG_POINTER(aFullscreenAllowed);
- // Browsers and apps have their mFullscreenAllowed retrieved from their
- // corresponding iframe in their parent upon creation.
- if (mFullscreenAllowed != CHECK_ATTRIBUTES) {
- *aFullscreenAllowed = (mFullscreenAllowed == PARENT_ALLOWS);
- return NS_OK;
- }
- // Assume false until we determine otherwise...
- *aFullscreenAllowed = false;
- nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
- if (!win) {
- return NS_OK;
- }
- if (nsCOMPtr<Element> frameElement = win->GetFrameElementInternal()) {
- if (frameElement->IsXULElement()) {
- if (frameElement->HasAttr(kNameSpaceID_None,
- nsGkAtoms::disablefullscreen)) {
- // Document inside this frame is explicitly disabled.
- return NS_OK;
- }
- } else {
- // We do not allow document inside any containing element other
- // than iframe to enter fullscreen.
- if (frameElement->IsHTMLElement(nsGkAtoms::iframe)) {
- // If any ancestor iframe does not have allowfullscreen attribute
- // set, then fullscreen is not allowed.
- if (!frameElement->HasAttr(kNameSpaceID_None,
- nsGkAtoms::allowfullscreen) &&
- !frameElement->HasAttr(kNameSpaceID_None,
- nsGkAtoms::mozallowfullscreen)) {
- return NS_OK;
- }
- } else if (frameElement->IsHTMLElement(nsGkAtoms::embed)) {
- // Respect allowfullscreen only if this is a rewritten YouTube embed.
- nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent =
- do_QueryInterface(frameElement);
- if (!objectLoadingContent) {
- return NS_OK;
- }
- nsObjectLoadingContent* olc =
- static_cast<nsObjectLoadingContent*>(objectLoadingContent.get());
- if (!olc->IsRewrittenYoutubeEmbed()) {
- return NS_OK;
- }
- // We don't have to check prefixed attributes because Flash does not
- // support them.
- if (!frameElement->HasAttr(kNameSpaceID_None,
- nsGkAtoms::allowfullscreen)) {
- return NS_OK;
- }
- } else {
- // neither iframe nor embed
- return NS_OK;
- }
- }
- }
- // If we have no parent then we're the root docshell; no ancestor of the
- // original docshell doesn't have a allowfullscreen attribute, so
- // report fullscreen as allowed.
- RefPtr<nsDocShell> parent = GetParentDocshell();
- if (!parent) {
- *aFullscreenAllowed = true;
- return NS_OK;
- }
- // Otherwise, we have a parent, continue the checking for
- // mozFullscreenAllowed in the parent docshell's ancestors.
- return parent->GetFullscreenAllowed(aFullscreenAllowed);
- }
- NS_IMETHODIMP
- nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed)
- {
- if (!nsIDocShell::GetIsMozBrowserOrApp()) {
- // Only allow setting of fullscreenAllowed on content/process boundaries.
- // At non-boundaries the fullscreenAllowed attribute is calculated based on
- // whether all enclosing frames have the "mozFullscreenAllowed" attribute
- // set to "true". fullscreenAllowed is set at the process boundaries to
- // propagate the value of the parent's "mozFullscreenAllowed" attribute
- // across process boundaries.
- return NS_ERROR_UNEXPECTED;
- }
- mFullscreenAllowed = (aFullscreenAllowed ? PARENT_ALLOWS : PARENT_PROHIBITS);
- return NS_OK;
- }
- ScreenOrientationInternal
- nsDocShell::OrientationLock()
- {
- return mOrientationLock;
- }
- void
- nsDocShell::SetOrientationLock(ScreenOrientationInternal aOrientationLock)
- {
- mOrientationLock = aOrientationLock;
- }
- NS_IMETHODIMP
- nsDocShell::GetMayEnableCharacterEncodingMenu(
- bool* aMayEnableCharacterEncodingMenu)
- {
- *aMayEnableCharacterEncodingMenu = false;
- if (!mContentViewer) {
- return NS_OK;
- }
- nsIDocument* doc = mContentViewer->GetDocument();
- if (!doc) {
- return NS_OK;
- }
- if (doc->WillIgnoreCharsetOverride()) {
- return NS_OK;
- }
- *aMayEnableCharacterEncodingMenu = true;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetDocShellEnumerator(int32_t aItemType, int32_t aDirection,
- nsISimpleEnumerator** aResult)
- {
- NS_ENSURE_ARG_POINTER(aResult);
- *aResult = nullptr;
- RefPtr<nsDocShellEnumerator> docShellEnum;
- if (aDirection == ENUMERATE_FORWARDS) {
- docShellEnum = new nsDocShellForwardsEnumerator;
- } else {
- docShellEnum = new nsDocShellBackwardsEnumerator;
- }
- nsresult rv = docShellEnum->SetEnumDocShellType(aItemType);
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = docShellEnum->SetEnumerationRootItem((nsIDocShellTreeItem*)this);
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = docShellEnum->First();
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = docShellEnum->QueryInterface(NS_GET_IID(nsISimpleEnumerator),
- (void**)aResult);
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::GetAppType(uint32_t* aAppType)
- {
- *aAppType = mAppType;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetAppType(uint32_t aAppType)
- {
- mAppType = aAppType;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetAllowAuth(bool* aAllowAuth)
- {
- *aAllowAuth = mAllowAuth;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetAllowAuth(bool aAllowAuth)
- {
- mAllowAuth = aAllowAuth;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetZoom(float* aZoom)
- {
- NS_ENSURE_ARG_POINTER(aZoom);
- *aZoom = 1.0f;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetZoom(float aZoom)
- {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- NS_IMETHODIMP
- nsDocShell::GetMarginWidth(int32_t* aWidth)
- {
- NS_ENSURE_ARG_POINTER(aWidth);
- *aWidth = mMarginWidth;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetMarginWidth(int32_t aWidth)
- {
- mMarginWidth = aWidth;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetMarginHeight(int32_t* aHeight)
- {
- NS_ENSURE_ARG_POINTER(aHeight);
- *aHeight = mMarginHeight;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetMarginHeight(int32_t aHeight)
- {
- mMarginHeight = aHeight;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetBusyFlags(uint32_t* aBusyFlags)
- {
- NS_ENSURE_ARG_POINTER(aBusyFlags);
- *aBusyFlags = mBusyFlags;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::TabToTreeOwner(bool aForward, bool aForDocumentNavigation, bool* aTookFocus)
- {
- NS_ENSURE_ARG_POINTER(aTookFocus);
- nsCOMPtr<nsIWebBrowserChromeFocus> chromeFocus = do_GetInterface(mTreeOwner);
- if (chromeFocus) {
- if (aForward) {
- *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusNextElement(aForDocumentNavigation));
- } else {
- *aTookFocus = NS_SUCCEEDED(chromeFocus->FocusPrevElement(aForDocumentNavigation));
- }
- } else {
- *aTookFocus = false;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetSecurityUI(nsISecureBrowserUI** aSecurityUI)
- {
- NS_IF_ADDREF(*aSecurityUI = mSecurityUI);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetSecurityUI(nsISecureBrowserUI* aSecurityUI)
- {
- mSecurityUI = aSecurityUI;
- mSecurityUI->SetDocShell(this);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetUseErrorPages(bool* aUseErrorPages)
- {
- *aUseErrorPages = UseErrorPages();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetUseErrorPages(bool aUseErrorPages)
- {
- // If mUseErrorPages is set explicitly, stop using sUseErrorPages.
- if (mObserveErrorPages) {
- mObserveErrorPages = false;
- }
- mUseErrorPages = aUseErrorPages;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetPreviousTransIndex(int32_t* aPreviousTransIndex)
- {
- *aPreviousTransIndex = mPreviousTransIndex;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetLoadedTransIndex(int32_t* aLoadedTransIndex)
- {
- *aLoadedTransIndex = mLoadedTransIndex;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::HistoryPurged(int32_t aNumEntries)
- {
- // These indices are used for fastback cache eviction, to determine
- // which session history entries are candidates for content viewer
- // eviction. We need to adjust by the number of entries that we
- // just purged from history, so that we look at the right session history
- // entries during eviction.
- mPreviousTransIndex = std::max(-1, mPreviousTransIndex - aNumEntries);
- mLoadedTransIndex = std::max(0, mLoadedTransIndex - aNumEntries);
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
- if (shell) {
- shell->HistoryPurged(aNumEntries);
- }
- }
- return NS_OK;
- }
- nsresult
- nsDocShell::HistoryTransactionRemoved(int32_t aIndex)
- {
- // These indices are used for fastback cache eviction, to determine
- // which session history entries are candidates for content viewer
- // eviction. We need to adjust by the number of entries that we
- // just purged from history, so that we look at the right session history
- // entries during eviction.
- if (aIndex == mPreviousTransIndex) {
- mPreviousTransIndex = -1;
- } else if (aIndex < mPreviousTransIndex) {
- --mPreviousTransIndex;
- }
- if (mLoadedTransIndex == aIndex) {
- mLoadedTransIndex = 0;
- } else if (aIndex < mLoadedTransIndex) {
- --mLoadedTransIndex;
- }
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
- if (shell) {
- static_cast<nsDocShell*>(shell.get())->HistoryTransactionRemoved(aIndex);
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetRecordProfileTimelineMarkers(bool aValue)
- {
- bool currentValue = nsIDocShell::GetRecordProfileTimelineMarkers();
- if (currentValue == aValue) {
- return NS_OK;
- }
- RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
- if (!timelines) {
- return NS_OK;
- }
- if (aValue) {
- MOZ_ASSERT(!timelines->HasConsumer(this));
- timelines->AddConsumer(this);
- MOZ_ASSERT(timelines->HasConsumer(this));
- UseEntryScriptProfiling();
- } else {
- MOZ_ASSERT(timelines->HasConsumer(this));
- timelines->RemoveConsumer(this);
- MOZ_ASSERT(!timelines->HasConsumer(this));
- UnuseEntryScriptProfiling();
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetRecordProfileTimelineMarkers(bool* aValue)
- {
- *aValue = !!mObserved;
- return NS_OK;
- }
- nsresult
- nsDocShell::PopProfileTimelineMarkers(
- JSContext* aCx,
- JS::MutableHandle<JS::Value> aOut)
- {
- RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
- if (!timelines) {
- return NS_OK;
- }
- nsTArray<dom::ProfileTimelineMarker> store;
- SequenceRooter<dom::ProfileTimelineMarker> rooter(aCx, &store);
- timelines->PopMarkers(this, aCx, store);
- if (!ToJSValue(aCx, store, aOut)) {
- JS_ClearPendingException(aCx);
- return NS_ERROR_UNEXPECTED;
- }
- return NS_OK;
- }
- nsresult
- nsDocShell::Now(DOMHighResTimeStamp* aWhen)
- {
- bool ignore;
- *aWhen =
- (TimeStamp::Now() - TimeStamp::ProcessCreation(ignore)).ToMilliseconds();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetWindowDraggingAllowed(bool aValue)
- {
- RefPtr<nsDocShell> parent = GetParentDocshell();
- if (!aValue && mItemType == typeChrome && !parent) {
- // Window dragging is always allowed for top level
- // chrome docshells.
- return NS_ERROR_FAILURE;
- }
- mWindowDraggingAllowed = aValue;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetWindowDraggingAllowed(bool* aValue)
- {
- // window dragging regions in CSS (-moz-window-drag:drag)
- // can be slow. Default behavior is to only allow it for
- // chrome top level windows.
- RefPtr<nsDocShell> parent = GetParentDocshell();
- if (mItemType == typeChrome && !parent) {
- // Top level chrome window
- *aValue = true;
- } else {
- *aValue = mWindowDraggingAllowed;
- }
- return NS_OK;
- }
- nsIDOMStorageManager*
- nsDocShell::TopSessionStorageManager()
- {
- nsresult rv;
- nsCOMPtr<nsIDocShellTreeItem> topItem;
- rv = GetSameTypeRootTreeItem(getter_AddRefs(topItem));
- if (NS_FAILED(rv)) {
- return nullptr;
- }
- if (!topItem) {
- return nullptr;
- }
- nsDocShell* topDocShell = static_cast<nsDocShell*>(topItem.get());
- if (topDocShell != this) {
- return topDocShell->TopSessionStorageManager();
- }
- if (!mSessionStorageManager) {
- mSessionStorageManager =
- do_CreateInstance("@mozilla.org/dom/sessionStorage-manager;1");
- }
- return mSessionStorageManager;
- }
- NS_IMETHODIMP
- nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
- const nsAString& aDocumentURI,
- bool aCreate,
- nsIDOMStorage** aStorage)
- {
- nsCOMPtr<nsIDOMStorageManager> manager = TopSessionStorageManager();
- if (!manager) {
- return NS_ERROR_UNEXPECTED;
- }
- nsCOMPtr<nsPIDOMWindowOuter> domWin = GetWindow();
- AssertOriginAttributesMatchPrivateBrowsing();
- if (aCreate) {
- return manager->CreateStorage(domWin->GetCurrentInnerWindow(), aPrincipal,
- aDocumentURI, UsePrivateBrowsing(), aStorage);
- }
- return manager->GetStorage(domWin->GetCurrentInnerWindow(), aPrincipal,
- UsePrivateBrowsing(), aStorage);
- }
- nsresult
- nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal, nsIDOMStorage* aStorage)
- {
- RefPtr<DOMStorage> storage = static_cast<DOMStorage*>(aStorage);
- if (!storage) {
- return NS_ERROR_UNEXPECTED;
- }
- nsIPrincipal* storagePrincipal = storage->GetPrincipal();
- if (storagePrincipal != aPrincipal) {
- NS_ERROR("Wanting to add a sessionStorage for different principal");
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- nsCOMPtr<nsIDOMStorageManager> manager = TopSessionStorageManager();
- if (!manager) {
- return NS_ERROR_UNEXPECTED;
- }
- return manager->CloneStorage(aStorage);
- }
- NS_IMETHODIMP
- nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult)
- {
- NS_IF_ADDREF(*aResult = GetCurrentDocChannel());
- return NS_OK;
- }
- nsIChannel*
- nsDocShell::GetCurrentDocChannel()
- {
- if (mContentViewer) {
- nsIDocument* doc = mContentViewer->GetDocument();
- if (doc) {
- return doc->GetChannel();
- }
- }
- return nullptr;
- }
- NS_IMETHODIMP
- nsDocShell::AddWeakScrollObserver(nsIScrollObserver* aObserver)
- {
- nsWeakPtr weakObs = do_GetWeakReference(aObserver);
- if (!weakObs) {
- return NS_ERROR_FAILURE;
- }
- return mScrollObservers.AppendElement(weakObs) ? NS_OK : NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsDocShell::RemoveWeakScrollObserver(nsIScrollObserver* aObserver)
- {
- nsWeakPtr obs = do_GetWeakReference(aObserver);
- return mScrollObservers.RemoveElement(obs) ? NS_OK : NS_ERROR_FAILURE;
- }
- void
- nsDocShell::NotifyAsyncPanZoomStarted()
- {
- nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
- while (iter.HasMore()) {
- nsWeakPtr ref = iter.GetNext();
- nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
- if (obs) {
- obs->AsyncPanZoomStarted();
- } else {
- mScrollObservers.RemoveElement(ref);
- }
- }
- }
- void
- nsDocShell::NotifyAsyncPanZoomStopped()
- {
- nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
- while (iter.HasMore()) {
- nsWeakPtr ref = iter.GetNext();
- nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
- if (obs) {
- obs->AsyncPanZoomStopped();
- } else {
- mScrollObservers.RemoveElement(ref);
- }
- }
- }
- NS_IMETHODIMP
- nsDocShell::NotifyScrollObservers()
- {
- nsTObserverArray<nsWeakPtr>::ForwardIterator iter(mScrollObservers);
- while (iter.HasMore()) {
- nsWeakPtr ref = iter.GetNext();
- nsCOMPtr<nsIScrollObserver> obs = do_QueryReferent(ref);
- if (obs) {
- obs->ScrollPositionChanged();
- } else {
- mScrollObservers.RemoveElement(ref);
- }
- }
- return NS_OK;
- }
- //*****************************************************************************
- // nsDocShell::nsIDocShellTreeItem
- //*****************************************************************************
- NS_IMETHODIMP
- nsDocShell::GetName(nsAString& aName)
- {
- aName = mName;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetName(const nsAString& aName)
- {
- mName = aName;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::NameEquals(const nsAString& aName, bool* aResult)
- {
- NS_ENSURE_ARG_POINTER(aResult);
- *aResult = mName.Equals(aName);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetCustomUserAgent(nsAString& aCustomUserAgent)
- {
- aCustomUserAgent = mCustomUserAgent;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetCustomUserAgent(const nsAString& aCustomUserAgent)
- {
- mCustomUserAgent = aCustomUserAgent;
- RefPtr<nsGlobalWindow> win = mScriptGlobal ?
- mScriptGlobal->GetCurrentInnerWindowInternal() : nullptr;
- if (win) {
- ErrorResult ignored;
- Navigator* navigator = win->GetNavigator(ignored);
- ignored.SuppressException();
- if (navigator) {
- navigator->ClearUserAgentCache();
- }
- }
- uint32_t childCount = mChildList.Length();
- for (uint32_t i = 0; i < childCount; ++i) {
- nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(ChildAt(i));
- if (childShell) {
- childShell->SetCustomUserAgent(aCustomUserAgent);
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetTouchEventsOverride(uint32_t* aTouchEventsOverride)
- {
- NS_ENSURE_ARG_POINTER(aTouchEventsOverride);
- *aTouchEventsOverride = mTouchEventsOverride;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetTouchEventsOverride(uint32_t aTouchEventsOverride)
- {
- if (!(aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_NONE ||
- aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_ENABLED ||
- aTouchEventsOverride == nsIDocShell::TOUCHEVENTS_OVERRIDE_DISABLED)) {
- return NS_ERROR_INVALID_ARG;
- }
- mTouchEventsOverride = aTouchEventsOverride;
- uint32_t childCount = mChildList.Length();
- for (uint32_t i = 0; i < childCount; ++i) {
- nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(ChildAt(i));
- if (childShell) {
- childShell->SetTouchEventsOverride(aTouchEventsOverride);
- }
- }
- return NS_OK;
- }
- /* virtual */ int32_t
- nsDocShell::ItemType()
- {
- return mItemType;
- }
- NS_IMETHODIMP
- nsDocShell::GetItemType(int32_t* aItemType)
- {
- NS_ENSURE_ARG_POINTER(aItemType);
- *aItemType = ItemType();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetItemType(int32_t aItemType)
- {
- NS_ENSURE_ARG((aItemType == typeChrome) || (typeContent == aItemType));
- // Only allow setting the type on root docshells. Those would be the ones
- // that have the docloader service as mParent or have no mParent at all.
- nsCOMPtr<nsIDocumentLoader> docLoaderService =
- do_GetService(NS_DOCUMENTLOADER_SERVICE_CONTRACTID);
- NS_ENSURE_TRUE(docLoaderService, NS_ERROR_UNEXPECTED);
- NS_ENSURE_STATE(!mParent || mParent == docLoaderService);
- mItemType = aItemType;
- // disable auth prompting for anything but content
- mAllowAuth = mItemType == typeContent;
- RefPtr<nsPresContext> presContext = nullptr;
- GetPresContext(getter_AddRefs(presContext));
- if (presContext) {
- presContext->UpdateIsChrome();
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetParent(nsIDocShellTreeItem** aParent)
- {
- if (!mParent) {
- *aParent = nullptr;
- } else {
- CallQueryInterface(mParent, aParent);
- }
- // Note that in the case when the parent is not an nsIDocShellTreeItem we
- // don't want to throw; we just want to return null.
- return NS_OK;
- }
- already_AddRefed<nsDocShell>
- nsDocShell::GetParentDocshell()
- {
- nsCOMPtr<nsIDocShell> docshell = do_QueryInterface(GetAsSupports(mParent));
- return docshell.forget().downcast<nsDocShell>();
- }
- void
- nsDocShell::RecomputeCanExecuteScripts()
- {
- bool old = mCanExecuteScripts;
- RefPtr<nsDocShell> parent = GetParentDocshell();
- // If we have no tree owner, that means that we've been detached from the
- // docshell tree (this is distinct from having no parent dochshell, which
- // is the case for root docshells). It would be nice to simply disallow
- // script in detached docshells, but bug 986542 demonstrates that this
- // behavior breaks at least one website.
- //
- // So instead, we use our previous value, unless mAllowJavascript has been
- // explicitly set to false.
- if (!mTreeOwner) {
- mCanExecuteScripts = mCanExecuteScripts && mAllowJavascript;
- // If scripting has been explicitly disabled on our docshell, we're done.
- } else if (!mAllowJavascript) {
- mCanExecuteScripts = false;
- // If we have a parent, inherit.
- } else if (parent) {
- mCanExecuteScripts = parent->mCanExecuteScripts;
- // Otherwise, we're the root of the tree, and we haven't explicitly disabled
- // script. Allow.
- } else {
- mCanExecuteScripts = true;
- }
- // Inform our active DOM window.
- //
- // This will pass the outer, which will be in the scope of the active inner.
- if (mScriptGlobal && mScriptGlobal->GetGlobalJSObject()) {
- xpc::Scriptability& scriptability =
- xpc::Scriptability::Get(mScriptGlobal->GetGlobalJSObject());
- scriptability.SetDocShellAllowsScript(mCanExecuteScripts);
- }
- // If our value has changed, our children might be affected. Recompute their
- // value as well.
- if (old != mCanExecuteScripts) {
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- static_cast<nsDocShell*>(iter.GetNext())->RecomputeCanExecuteScripts();
- }
- }
- }
- nsresult
- nsDocShell::SetDocLoaderParent(nsDocLoader* aParent)
- {
- bool wasFrame = IsFrame();
- #ifdef DEBUG
- bool wasPrivate = UsePrivateBrowsing();
- #endif
- nsresult rv = nsDocLoader::SetDocLoaderParent(aParent);
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsISupportsPriority> priorityGroup = do_QueryInterface(mLoadGroup);
- if (wasFrame != IsFrame() && priorityGroup) {
- priorityGroup->AdjustPriority(wasFrame ? -1 : 1);
- }
- // Curse ambiguous nsISupports inheritance!
- nsISupports* parent = GetAsSupports(aParent);
- // If parent is another docshell, we inherit all their flags for
- // allowing plugins, scripting etc.
- bool value;
- nsString customUserAgent;
- nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(parent));
- if (parentAsDocShell) {
- if (mAllowPlugins && NS_SUCCEEDED(parentAsDocShell->GetAllowPlugins(&value))) {
- SetAllowPlugins(value);
- }
- if (mAllowJavascript && NS_SUCCEEDED(parentAsDocShell->GetAllowJavascript(&value))) {
- SetAllowJavascript(value);
- }
- if (mAllowMetaRedirects && NS_SUCCEEDED(parentAsDocShell->GetAllowMetaRedirects(&value))) {
- SetAllowMetaRedirects(value);
- }
- if (mAllowSubframes && NS_SUCCEEDED(parentAsDocShell->GetAllowSubframes(&value))) {
- SetAllowSubframes(value);
- }
- if (mAllowImages && NS_SUCCEEDED(parentAsDocShell->GetAllowImages(&value))) {
- SetAllowImages(value);
- }
- SetAllowMedia(parentAsDocShell->GetAllowMedia() && mAllowMedia);
- if (mAllowWindowControl && NS_SUCCEEDED(parentAsDocShell->GetAllowWindowControl(&value))) {
- SetAllowWindowControl(value);
- }
- SetAllowContentRetargeting(mAllowContentRetargeting &&
- parentAsDocShell->GetAllowContentRetargetingOnChildren());
- if (parentAsDocShell->GetIsPrerendered()) {
- SetIsPrerendered();
- }
- if (NS_SUCCEEDED(parentAsDocShell->GetIsActive(&value))) {
- // a prerendered docshell is not active yet
- SetIsActive(value && !mIsPrerendered);
- }
- if (NS_SUCCEEDED(parentAsDocShell->GetCustomUserAgent(customUserAgent)) &&
- !customUserAgent.IsEmpty()) {
- SetCustomUserAgent(customUserAgent);
- }
- if (NS_FAILED(parentAsDocShell->GetAllowDNSPrefetch(&value))) {
- value = false;
- }
- SetAllowDNSPrefetch(mAllowDNSPrefetch && value);
- if (mInheritPrivateBrowsingId) {
- value = parentAsDocShell->GetAffectPrivateSessionLifetime();
- SetAffectPrivateSessionLifetime(value);
- }
- uint32_t flags;
- if (NS_SUCCEEDED(parentAsDocShell->GetDefaultLoadFlags(&flags))) {
- SetDefaultLoadFlags(flags);
- }
- uint32_t touchEventsOverride;
- if (NS_SUCCEEDED(parentAsDocShell->GetTouchEventsOverride(&touchEventsOverride))) {
- SetTouchEventsOverride(touchEventsOverride);
- }
- }
- nsCOMPtr<nsILoadContext> parentAsLoadContext(do_QueryInterface(parent));
- if (parentAsLoadContext && mInheritPrivateBrowsingId &&
- NS_SUCCEEDED(parentAsLoadContext->GetUsePrivateBrowsing(&value))) {
- SetPrivateBrowsing(value);
- }
- nsCOMPtr<nsIURIContentListener> parentURIListener(do_GetInterface(parent));
- if (parentURIListener) {
- mContentListener->SetParentContentListener(parentURIListener);
- }
- // Our parent has changed. Recompute scriptability.
- RecomputeCanExecuteScripts();
- NS_ASSERTION(mInheritPrivateBrowsingId || wasPrivate == UsePrivateBrowsing(),
- "Private browsing state changed while inheritance was disabled");
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetSameTypeParent(nsIDocShellTreeItem** aParent)
- {
- NS_ENSURE_ARG_POINTER(aParent);
- *aParent = nullptr;
- if (nsIDocShell::GetIsMozBrowserOrApp()) {
- return NS_OK;
- }
- nsCOMPtr<nsIDocShellTreeItem> parent =
- do_QueryInterface(GetAsSupports(mParent));
- if (!parent) {
- return NS_OK;
- }
- if (parent->ItemType() == mItemType) {
- parent.swap(*aParent);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetSameTypeParentIgnoreBrowserAndAppBoundaries(nsIDocShell** aParent)
- {
- NS_ENSURE_ARG_POINTER(aParent);
- *aParent = nullptr;
- nsCOMPtr<nsIDocShellTreeItem> parent =
- do_QueryInterface(GetAsSupports(mParent));
- if (!parent) {
- return NS_OK;
- }
- if (parent->ItemType() == mItemType) {
- nsCOMPtr<nsIDocShell> parentDS = do_QueryInterface(parent);
- parentDS.forget(aParent);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetRootTreeItem(nsIDocShellTreeItem** aRootTreeItem)
- {
- NS_ENSURE_ARG_POINTER(aRootTreeItem);
- RefPtr<nsDocShell> root = this;
- RefPtr<nsDocShell> parent = root->GetParentDocshell();
- while (parent) {
- root = parent;
- parent = root->GetParentDocshell();
- }
- root.forget(aRootTreeItem);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetSameTypeRootTreeItem(nsIDocShellTreeItem** aRootTreeItem)
- {
- NS_ENSURE_ARG_POINTER(aRootTreeItem);
- *aRootTreeItem = static_cast<nsIDocShellTreeItem*>(this);
- nsCOMPtr<nsIDocShellTreeItem> parent;
- NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parent)),
- NS_ERROR_FAILURE);
- while (parent) {
- *aRootTreeItem = parent;
- NS_ENSURE_SUCCESS(
- (*aRootTreeItem)->GetSameTypeParent(getter_AddRefs(parent)),
- NS_ERROR_FAILURE);
- }
- NS_ADDREF(*aRootTreeItem);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetSameTypeRootTreeItemIgnoreBrowserAndAppBoundaries(nsIDocShell ** aRootTreeItem)
- {
- NS_ENSURE_ARG_POINTER(aRootTreeItem);
- *aRootTreeItem = static_cast<nsIDocShell *>(this);
- nsCOMPtr<nsIDocShell> parent;
- NS_ENSURE_SUCCESS(GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent)),
- NS_ERROR_FAILURE);
- while (parent) {
- *aRootTreeItem = parent;
- NS_ENSURE_SUCCESS((*aRootTreeItem)->
- GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent)),
- NS_ERROR_FAILURE);
- }
- NS_ADDREF(*aRootTreeItem);
- return NS_OK;
- }
- /* static */
- bool
- nsDocShell::CanAccessItem(nsIDocShellTreeItem* aTargetItem,
- nsIDocShellTreeItem* aAccessingItem,
- bool aConsiderOpener)
- {
- NS_PRECONDITION(aTargetItem, "Must have target item!");
- if (!gValidateOrigin || !aAccessingItem) {
- // Good to go
- return true;
- }
- // XXXbz should we care if aAccessingItem or the document therein is
- // chrome? Should those get extra privileges?
- // For historical context, see:
- //
- // Bug 13871: Prevent frameset spoofing
- // Bug 103638: Targets with same name in different windows open in wrong
- // window with javascript
- // Bug 408052: Adopt "ancestor" frame navigation policy
- // Now do a security check.
- //
- // Disallow navigation if the two frames are not part of the same app, or if
- // they have different is-in-browser-element states.
- //
- // Allow navigation if
- // 1) aAccessingItem can script aTargetItem or one of its ancestors in
- // the frame hierarchy or
- // 2) aTargetItem is a top-level frame and aAccessingItem is its descendant
- // 3) aTargetItem is a top-level frame and aAccessingItem can target
- // its opener per rule (1) or (2).
- if (aTargetItem == aAccessingItem) {
- // A frame is allowed to navigate itself.
- return true;
- }
- nsCOMPtr<nsIDocShell> targetDS = do_QueryInterface(aTargetItem);
- nsCOMPtr<nsIDocShell> accessingDS = do_QueryInterface(aAccessingItem);
- if (!targetDS || !accessingDS) {
- // We must be able to convert both to nsIDocShell.
- return false;
- }
- if (targetDS->GetIsInIsolatedMozBrowserElement() !=
- accessingDS->GetIsInIsolatedMozBrowserElement() ||
- targetDS->GetAppId() != accessingDS->GetAppId()) {
- return false;
- }
- nsCOMPtr<nsIDocShellTreeItem> accessingRoot;
- aAccessingItem->GetSameTypeRootTreeItem(getter_AddRefs(accessingRoot));
- nsCOMPtr<nsIDocShell> accessingRootDS = do_QueryInterface(accessingRoot);
- nsCOMPtr<nsIDocShellTreeItem> targetRoot;
- aTargetItem->GetSameTypeRootTreeItem(getter_AddRefs(targetRoot));
- nsCOMPtr<nsIDocShell> targetRootDS = do_QueryInterface(targetRoot);
- DocShellOriginAttributes targetOA =
- static_cast<nsDocShell*>(targetDS.get())->GetOriginAttributes();
- DocShellOriginAttributes accessingOA =
- static_cast<nsDocShell*>(accessingDS.get())->GetOriginAttributes();
- // When the first party isolation is on, the top-level docShell may not have
- // the firstPartyDomain in its originAttributes, but its document will have
- // it. So we get the firstPartyDomain from the nodePrincipal of the document
- // before we compare the originAttributes.
- if (OriginAttributes::IsFirstPartyEnabled()) {
- if (accessingDS == accessingRootDS &&
- aAccessingItem->ItemType() == nsIDocShellTreeItem::typeContent &&
- !accessingDS->GetIsMozBrowserOrApp()) {
- nsCOMPtr<nsIDocument> accessingDoc = aAccessingItem->GetDocument();
- if (accessingDoc) {
- nsCOMPtr<nsIPrincipal> accessingPrincipal = accessingDoc->NodePrincipal();
- accessingOA.mFirstPartyDomain =
- BasePrincipal::Cast(accessingPrincipal)->OriginAttributesRef().mFirstPartyDomain;
- }
- }
- if (targetDS == targetRootDS &&
- aTargetItem->ItemType() == nsIDocShellTreeItem::typeContent &&
- !targetDS->GetIsMozBrowserOrApp()) {
- nsCOMPtr<nsIDocument> targetDoc = aAccessingItem->GetDocument();
- if (targetDoc) {
- nsCOMPtr<nsIPrincipal> targetPrincipal = targetDoc->NodePrincipal();
- targetOA.mFirstPartyDomain =
- BasePrincipal::Cast(targetPrincipal)->OriginAttributesRef().mFirstPartyDomain;
- }
- }
- }
- if (targetOA != accessingOA) {
- return false;
- }
- // A private document can't access a non-private one, and vice versa.
- if (static_cast<nsDocShell*>(targetDS.get())->UsePrivateBrowsing() !=
- static_cast<nsDocShell*>(accessingDS.get())->UsePrivateBrowsing()) {
- return false;
- }
- if (aTargetItem == accessingRoot) {
- // A frame can navigate its root.
- return true;
- }
- // Check if aAccessingItem can navigate one of aTargetItem's ancestors.
- nsCOMPtr<nsIDocShellTreeItem> target = aTargetItem;
- do {
- if (ValidateOrigin(aAccessingItem, target)) {
- return true;
- }
- nsCOMPtr<nsIDocShellTreeItem> parent;
- target->GetSameTypeParent(getter_AddRefs(parent));
- parent.swap(target);
- } while (target);
- if (aTargetItem != targetRoot) {
- // target is a subframe, not in accessor's frame hierarchy, and all its
- // ancestors have origins different from that of the accessor. Don't
- // allow access.
- return false;
- }
- if (!aConsiderOpener) {
- // All done here
- return false;
- }
- nsCOMPtr<nsPIDOMWindowOuter> targetWindow = aTargetItem->GetWindow();
- if (!targetWindow) {
- NS_ERROR("This should not happen, really");
- return false;
- }
- nsCOMPtr<mozIDOMWindowProxy> targetOpener = targetWindow->GetOpener();
- nsCOMPtr<nsIWebNavigation> openerWebNav(do_GetInterface(targetOpener));
- nsCOMPtr<nsIDocShellTreeItem> openerItem(do_QueryInterface(openerWebNav));
- if (!openerItem) {
- return false;
- }
- return CanAccessItem(openerItem, aAccessingItem, false);
- }
- static bool
- ItemIsActive(nsIDocShellTreeItem* aItem)
- {
- if (nsCOMPtr<nsPIDOMWindowOuter> window = aItem->GetWindow()) {
- auto* win = nsGlobalWindow::Cast(window);
- MOZ_ASSERT(win->IsOuterWindow());
- if (!win->GetClosedOuter()) {
- return true;
- }
- }
- return false;
- }
- NS_IMETHODIMP
- nsDocShell::FindItemWithName(const nsAString& aName,
- nsISupports* aRequestor,
- nsIDocShellTreeItem* aOriginalRequestor,
- nsIDocShellTreeItem** aResult)
- {
- NS_ENSURE_ARG_POINTER(aResult);
- // If we don't find one, we return NS_OK and a null result
- *aResult = nullptr;
- if (aName.IsEmpty()) {
- return NS_OK;
- }
- if (aRequestor) {
- // If aRequestor is not null we don't need to check special names, so
- // just hand straight off to the search by actual name function.
- return DoFindItemWithName(aName, aRequestor, aOriginalRequestor, aResult);
- } else {
- // This is the entry point into the target-finding algorithm. Check
- // for special names. This should only be done once, hence the check
- // for a null aRequestor.
- nsCOMPtr<nsIDocShellTreeItem> foundItem;
- if (aName.LowerCaseEqualsLiteral("_self")) {
- foundItem = this;
- } else if (aName.LowerCaseEqualsLiteral("_blank")) {
- // Just return null. Caller must handle creating a new window with
- // a blank name himself.
- return NS_OK;
- } else if (aName.LowerCaseEqualsLiteral("_parent")) {
- GetSameTypeParent(getter_AddRefs(foundItem));
- if (!foundItem) {
- foundItem = this;
- }
- } else if (aName.LowerCaseEqualsLiteral("_top")) {
- GetSameTypeRootTreeItem(getter_AddRefs(foundItem));
- NS_ASSERTION(foundItem, "Must have this; worst case it's us!");
- } else {
- // Do the search for item by an actual name.
- DoFindItemWithName(aName, aRequestor, aOriginalRequestor,
- getter_AddRefs(foundItem));
- }
- if (foundItem && !CanAccessItem(foundItem, aOriginalRequestor)) {
- foundItem = nullptr;
- }
- // DoFindItemWithName only returns active items and we don't check if
- // the item is active for the special cases.
- if (foundItem) {
- foundItem.swap(*aResult);
- }
- return NS_OK;
- }
- }
- void
- nsDocShell::AssertOriginAttributesMatchPrivateBrowsing() {
- // Chrome docshells must not have a private browsing OriginAttribute
- // Content docshells must maintain the equality:
- // mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId
- if (mItemType == typeChrome) {
- MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes.mPrivateBrowsingId == 0);
- } else {
- MOZ_DIAGNOSTIC_ASSERT(mOriginAttributes.mPrivateBrowsingId == mPrivateBrowsingId);
- }
- }
- nsresult
- nsDocShell::DoFindItemWithName(const nsAString& aName,
- nsISupports* aRequestor,
- nsIDocShellTreeItem* aOriginalRequestor,
- nsIDocShellTreeItem** aResult)
- {
- // First we check our name.
- if (mName.Equals(aName) && ItemIsActive(this) &&
- CanAccessItem(this, aOriginalRequestor)) {
- NS_ADDREF(*aResult = this);
- return NS_OK;
- }
- // This QI may fail, but the places where we want to compare, comparing
- // against nullptr serves the same purpose.
- nsCOMPtr<nsIDocShellTreeItem> reqAsTreeItem(do_QueryInterface(aRequestor));
- // Second we check our children making sure not to ask a child if
- // it is the aRequestor.
- #ifdef DEBUG
- nsresult rv =
- #endif
- FindChildWithName(aName, true, true, reqAsTreeItem, aOriginalRequestor,
- aResult);
- NS_ASSERTION(NS_SUCCEEDED(rv),
- "FindChildWithName should not be failing here.");
- if (*aResult) {
- return NS_OK;
- }
- // Third if we have a parent and it isn't the requestor then we
- // should ask it to do the search. If it is the requestor we
- // should just stop here and let the parent do the rest. If we
- // don't have a parent, then we should ask the
- // docShellTreeOwner to do the search.
- nsCOMPtr<nsIDocShellTreeItem> parentAsTreeItem =
- do_QueryInterface(GetAsSupports(mParent));
- if (parentAsTreeItem) {
- if (parentAsTreeItem == reqAsTreeItem) {
- return NS_OK;
- }
- // If we have a same-type parent, respecting browser and app boundaries.
- // NOTE: Could use GetSameTypeParent if the issues described in bug 1310344 are fixed.
- if (!GetIsMozBrowserOrApp() && parentAsTreeItem->ItemType() == mItemType) {
- return parentAsTreeItem->FindItemWithName(
- aName,
- static_cast<nsIDocShellTreeItem*>(this),
- aOriginalRequestor,
- aResult);
- }
- }
- // If we have a null parent or the parent is not of the same type, we need to
- // give up on finding it in our tree, and start looking in our TabGroup.
- nsCOMPtr<nsPIDOMWindowOuter> window = GetWindow();
- if (window) {
- RefPtr<mozilla::dom::TabGroup> tabGroup = window->TabGroup();
- // We don't want to make the request to our TabGroup if they are the ones
- // which made a request to us.
- if (tabGroup != aRequestor) {
- tabGroup->FindItemWithName(aName, this, aOriginalRequestor, aResult);
- }
- }
- return NS_OK;
- }
- bool
- nsDocShell::IsSandboxedFrom(nsIDocShell* aTargetDocShell)
- {
- // If no target then not sandboxed.
- if (!aTargetDocShell) {
- return false;
- }
- // We cannot be sandboxed from ourselves.
- if (aTargetDocShell == this) {
- return false;
- }
- // Default the sandbox flags to our flags, so that if we can't retrieve the
- // active document, we will still enforce our own.
- uint32_t sandboxFlags = mSandboxFlags;
- if (mContentViewer) {
- nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
- if (doc) {
- sandboxFlags = doc->GetSandboxFlags();
- }
- }
- // If no flags, we are not sandboxed at all.
- if (!sandboxFlags) {
- return false;
- }
- // If aTargetDocShell has an ancestor, it is not top level.
- nsCOMPtr<nsIDocShellTreeItem> ancestorOfTarget;
- aTargetDocShell->GetSameTypeParent(getter_AddRefs(ancestorOfTarget));
- if (ancestorOfTarget) {
- do {
- // We are not sandboxed if we are an ancestor of target.
- if (ancestorOfTarget == this) {
- return false;
- }
- nsCOMPtr<nsIDocShellTreeItem> tempTreeItem;
- ancestorOfTarget->GetSameTypeParent(getter_AddRefs(tempTreeItem));
- tempTreeItem.swap(ancestorOfTarget);
- } while (ancestorOfTarget);
- // Otherwise, we are sandboxed from aTargetDocShell.
- return true;
- }
- // aTargetDocShell is top level, are we the "one permitted sandboxed
- // navigator", i.e. did we open aTargetDocShell?
- nsCOMPtr<nsIDocShell> permittedNavigator;
- aTargetDocShell->GetOnePermittedSandboxedNavigator(
- getter_AddRefs(permittedNavigator));
- if (permittedNavigator == this) {
- return false;
- }
- // If SANDBOXED_TOPLEVEL_NAVIGATION flag is not on, we are not sandboxed
- // from our top.
- if (!(sandboxFlags & SANDBOXED_TOPLEVEL_NAVIGATION)) {
- nsCOMPtr<nsIDocShellTreeItem> rootTreeItem;
- GetSameTypeRootTreeItem(getter_AddRefs(rootTreeItem));
- if (SameCOMIdentity(aTargetDocShell, rootTreeItem)) {
- return false;
- }
- }
- // Otherwise, we are sandboxed from aTargetDocShell.
- return true;
- }
- NS_IMETHODIMP
- nsDocShell::GetTreeOwner(nsIDocShellTreeOwner** aTreeOwner)
- {
- NS_ENSURE_ARG_POINTER(aTreeOwner);
- *aTreeOwner = mTreeOwner;
- NS_IF_ADDREF(*aTreeOwner);
- return NS_OK;
- }
- #ifdef DEBUG_DOCSHELL_FOCUS
- static void
- PrintDocTree(nsIDocShellTreeItem* aParentNode, int aLevel)
- {
- for (int32_t i = 0; i < aLevel; i++) {
- printf(" ");
- }
- int32_t childWebshellCount;
- aParentNode->GetChildCount(&childWebshellCount);
- nsCOMPtr<nsIDocShell> parentAsDocShell(do_QueryInterface(aParentNode));
- int32_t type = aParentNode->ItemType();
- nsCOMPtr<nsIPresShell> presShell = parentAsDocShell->GetPresShell();
- RefPtr<nsPresContext> presContext;
- parentAsDocShell->GetPresContext(getter_AddRefs(presContext));
- nsIDocument* doc = presShell->GetDocument();
- nsCOMPtr<nsPIDOMWindowOuter> domwin(doc->GetWindow());
- nsCOMPtr<nsIWidget> widget;
- nsViewManager* vm = presShell->GetViewManager();
- if (vm) {
- vm->GetWidget(getter_AddRefs(widget));
- }
- dom::Element* rootElement = doc->GetRootElement();
- printf("DS %p Ty %s Doc %p DW %p EM %p CN %p\n",
- (void*)parentAsDocShell.get(),
- type == nsIDocShellTreeItem::typeChrome ? "Chr" : "Con",
- (void*)doc, (void*)domwin.get(),
- (void*)presContext->EventStateManager(), (void*)rootElement);
- if (childWebshellCount > 0) {
- for (int32_t i = 0; i < childWebshellCount; i++) {
- nsCOMPtr<nsIDocShellTreeItem> child;
- aParentNode->GetChildAt(i, getter_AddRefs(child));
- PrintDocTree(child, aLevel + 1);
- }
- }
- }
- static void
- PrintDocTree(nsIDocShellTreeItem* aParentNode)
- {
- NS_ASSERTION(aParentNode, "Pointer is null!");
- nsCOMPtr<nsIDocShellTreeItem> parentItem;
- aParentNode->GetParent(getter_AddRefs(parentItem));
- while (parentItem) {
- nsCOMPtr<nsIDocShellTreeItem> tmp;
- parentItem->GetParent(getter_AddRefs(tmp));
- if (!tmp) {
- break;
- }
- parentItem = tmp;
- }
- if (!parentItem) {
- parentItem = aParentNode;
- }
- PrintDocTree(parentItem, 0);
- }
- #endif
- NS_IMETHODIMP
- nsDocShell::SetTreeOwner(nsIDocShellTreeOwner* aTreeOwner)
- {
- #ifdef DEBUG_DOCSHELL_FOCUS
- nsCOMPtr<nsIDocShellTreeItem> item(do_QueryInterface(aTreeOwner));
- if (item) {
- PrintDocTree(item);
- }
- #endif
- // Don't automatically set the progress based on the tree owner for frames
- if (!IsFrame()) {
- nsCOMPtr<nsIWebProgress> webProgress =
- do_QueryInterface(GetAsSupports(this));
- if (webProgress) {
- nsCOMPtr<nsIWebProgressListener> oldListener =
- do_QueryInterface(mTreeOwner);
- nsCOMPtr<nsIWebProgressListener> newListener =
- do_QueryInterface(aTreeOwner);
- if (oldListener) {
- webProgress->RemoveProgressListener(oldListener);
- }
- if (newListener) {
- webProgress->AddProgressListener(newListener,
- nsIWebProgress::NOTIFY_ALL);
- }
- }
- }
- mTreeOwner = aTreeOwner; // Weak reference per API
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext());
- NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
- if (child->ItemType() == mItemType) {
- child->SetTreeOwner(aTreeOwner);
- }
- }
- // Our tree owner has changed. Recompute scriptability.
- //
- // Note that this is near-redundant with the recomputation in
- // SetDocLoaderParent(), but not so for the root DocShell, where the call to
- // SetTreeOwner() happens after the initial AddDocLoaderAsChildOfRoot(),
- // and we never set another parent. Given that this is neither expensive nor
- // performance-critical, let's be safe and unconditionally recompute this
- // state whenever dependent state changes.
- RecomputeCanExecuteScripts();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetChildOffset(uint32_t aChildOffset)
- {
- mChildOffset = aChildOffset;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetHistoryID(uint64_t* aID)
- {
- *aID = mHistoryID;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetIsInUnload(bool* aIsInUnload)
- {
- *aIsInUnload = mFiredUnloadEvent;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetChildCount(int32_t* aChildCount)
- {
- NS_ENSURE_ARG_POINTER(aChildCount);
- *aChildCount = mChildList.Length();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::AddChild(nsIDocShellTreeItem* aChild)
- {
- NS_ENSURE_ARG_POINTER(aChild);
- RefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
- NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
- // Make sure we're not creating a loop in the docshell tree
- nsDocLoader* ancestor = this;
- do {
- if (childAsDocLoader == ancestor) {
- return NS_ERROR_ILLEGAL_VALUE;
- }
- ancestor = ancestor->GetParent();
- } while (ancestor);
- // Make sure to remove the child from its current parent.
- nsDocLoader* childsParent = childAsDocLoader->GetParent();
- if (childsParent) {
- nsresult rv = childsParent->RemoveChildLoader(childAsDocLoader);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- // Make sure to clear the treeowner in case this child is a different type
- // from us.
- aChild->SetTreeOwner(nullptr);
- nsresult res = AddChildLoader(childAsDocLoader);
- NS_ENSURE_SUCCESS(res, res);
- NS_ASSERTION(!mChildList.IsEmpty(),
- "child list must not be empty after a successful add");
- nsCOMPtr<nsIDocShell> childDocShell = do_QueryInterface(aChild);
- bool dynamic = false;
- childDocShell->GetCreatedDynamically(&dynamic);
- if (!dynamic) {
- nsCOMPtr<nsISHEntry> currentSH;
- bool oshe = false;
- GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
- if (currentSH) {
- currentSH->HasDynamicallyAddedChild(&dynamic);
- }
- }
- childDocShell->SetChildOffset(dynamic ? -1 : mChildList.Length() - 1);
- /* Set the child's global history if the parent has one */
- if (mUseGlobalHistory) {
- childDocShell->SetUseGlobalHistory(true);
- }
- if (aChild->ItemType() != mItemType) {
- return NS_OK;
- }
- aChild->SetTreeOwner(mTreeOwner);
- nsCOMPtr<nsIDocShell> childAsDocShell(do_QueryInterface(aChild));
- if (!childAsDocShell) {
- return NS_OK;
- }
- // charset, style-disabling, and zoom will be inherited in SetupNewViewer()
- // Now take this document's charset and set the child's parentCharset field
- // to it. We'll later use that field, in the loading process, for the
- // charset choosing algorithm.
- // If we fail, at any point, we just return NS_OK.
- // This code has some performance impact. But this will be reduced when
- // the current charset will finally be stored as an Atom, avoiding the
- // alias resolution extra look-up.
- // we are NOT going to propagate the charset is this Chrome's docshell
- if (mItemType == nsIDocShellTreeItem::typeChrome) {
- return NS_OK;
- }
- // get the parent's current charset
- if (!mContentViewer) {
- return NS_OK;
- }
- nsIDocument* doc = mContentViewer->GetDocument();
- if (!doc) {
- return NS_OK;
- }
- bool isWyciwyg = false;
- if (mCurrentURI) {
- // Check if the url is wyciwyg
- mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);
- }
- if (!isWyciwyg) {
- // If this docshell is loaded from a wyciwyg: URI, don't
- // advertise our charset since it does not in any way reflect
- // the actual source charset, which is what we're trying to
- // expose here.
- const nsACString& parentCS = doc->GetDocumentCharacterSet();
- int32_t charsetSource = doc->GetDocumentCharacterSetSource();
- // set the child's parentCharset
- childAsDocShell->SetParentCharset(parentCS,
- charsetSource,
- doc->NodePrincipal());
- }
- // printf("### 1 >>> Adding child. Parent CS = %s. ItemType = %d.\n",
- // NS_LossyConvertUTF16toASCII(parentCS).get(), mItemType);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::RemoveChild(nsIDocShellTreeItem* aChild)
- {
- NS_ENSURE_ARG_POINTER(aChild);
- RefPtr<nsDocLoader> childAsDocLoader = GetAsDocLoader(aChild);
- NS_ENSURE_TRUE(childAsDocLoader, NS_ERROR_UNEXPECTED);
- nsresult rv = RemoveChildLoader(childAsDocLoader);
- NS_ENSURE_SUCCESS(rv, rv);
- aChild->SetTreeOwner(nullptr);
- return nsDocLoader::AddDocLoaderAsChildOfRoot(childAsDocLoader);
- }
- NS_IMETHODIMP
- nsDocShell::GetChildAt(int32_t aIndex, nsIDocShellTreeItem** aChild)
- {
- NS_ENSURE_ARG_POINTER(aChild);
- #ifdef DEBUG
- if (aIndex < 0) {
- NS_WARNING("Negative index passed to GetChildAt");
- } else if (static_cast<uint32_t>(aIndex) >= mChildList.Length()) {
- NS_WARNING("Too large an index passed to GetChildAt");
- }
- #endif
- nsIDocumentLoader* child = ChildAt(aIndex);
- NS_ENSURE_TRUE(child, NS_ERROR_UNEXPECTED);
- return CallQueryInterface(child, aChild);
- }
- NS_IMETHODIMP
- nsDocShell::FindChildWithName(const nsAString& aName,
- bool aRecurse, bool aSameType,
- nsIDocShellTreeItem* aRequestor,
- nsIDocShellTreeItem* aOriginalRequestor,
- nsIDocShellTreeItem** aResult)
- {
- NS_ENSURE_ARG_POINTER(aResult);
- // if we don't find one, we return NS_OK and a null result
- *aResult = nullptr;
- if (aName.IsEmpty()) {
- return NS_OK;
- }
- nsXPIDLString childName;
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- nsCOMPtr<nsIDocShellTreeItem> child = do_QueryObject(iter.GetNext());
- NS_ENSURE_TRUE(child, NS_ERROR_FAILURE);
- int32_t childType = child->ItemType();
- if (aSameType && (childType != mItemType)) {
- continue;
- }
- bool childNameEquals = false;
- child->NameEquals(aName, &childNameEquals);
- if (childNameEquals && ItemIsActive(child) &&
- CanAccessItem(child, aOriginalRequestor)) {
- child.swap(*aResult);
- break;
- }
- // Only ask it to check children if it is same type
- if (childType != mItemType) {
- continue;
- }
- // Only ask the child if it isn't the requestor
- if (aRecurse && (aRequestor != child)) {
- // See if child contains the shell with the given name
- #ifdef DEBUG
- nsresult rv =
- #endif
- child->FindChildWithName(aName, true, aSameType,
- static_cast<nsIDocShellTreeItem*>(this),
- aOriginalRequestor, aResult);
- NS_ASSERTION(NS_SUCCEEDED(rv), "FindChildWithName should not fail here");
- if (*aResult) {
- // found it
- return NS_OK;
- }
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetChildSHEntry(int32_t aChildOffset, nsISHEntry** aResult)
- {
- nsresult rv = NS_OK;
- NS_ENSURE_ARG_POINTER(aResult);
- *aResult = nullptr;
- // A nsISHEntry for a child is *only* available when the parent is in
- // the progress of loading a document too...
- if (mLSHE) {
- /* Before looking for the subframe's url, check
- * the expiration status of the parent. If the parent
- * has expired from cache, then subframes will not be
- * loaded from history in certain situations.
- */
- bool parentExpired = false;
- mLSHE->GetExpirationStatus(&parentExpired);
- /* Get the parent's Load Type so that it can be set on the child too.
- * By default give a loadHistory value
- */
- uint32_t loadType = nsIDocShellLoadInfo::loadHistory;
- mLSHE->GetLoadType(&loadType);
- // If the user did a shift-reload on this frameset page,
- // we don't want to load the subframes from history.
- if (loadType == nsIDocShellLoadInfo::loadReloadBypassCache ||
- loadType == nsIDocShellLoadInfo::loadReloadBypassProxy ||
- loadType == nsIDocShellLoadInfo::loadReloadBypassProxyAndCache ||
- loadType == nsIDocShellLoadInfo::loadRefresh) {
- return rv;
- }
- /* If the user pressed reload and the parent frame has expired
- * from cache, we do not want to load the child frame from history.
- */
- if (parentExpired && (loadType == nsIDocShellLoadInfo::loadReloadNormal)) {
- // The parent has expired. Return null.
- *aResult = nullptr;
- return rv;
- }
- nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE));
- if (container) {
- // Get the child subframe from session history.
- rv = container->GetChildAt(aChildOffset, aResult);
- if (*aResult) {
- (*aResult)->SetLoadType(loadType);
- }
- }
- }
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::AddChildSHEntry(nsISHEntry* aCloneRef, nsISHEntry* aNewEntry,
- int32_t aChildOffset, uint32_t aLoadType,
- bool aCloneChildren)
- {
- nsresult rv = NS_OK;
- if (mLSHE && aLoadType != LOAD_PUSHSTATE) {
- /* You get here if you are currently building a
- * hierarchy ie.,you just visited a frameset page
- */
- nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE, &rv));
- if (container) {
- if (NS_FAILED(container->ReplaceChild(aNewEntry))) {
- rv = container->AddChild(aNewEntry, aChildOffset);
- }
- }
- } else if (!aCloneRef) {
- /* This is an initial load in some subframe. Just append it if we can */
- nsCOMPtr<nsISHContainer> container(do_QueryInterface(mOSHE, &rv));
- if (container) {
- rv = container->AddChild(aNewEntry, aChildOffset);
- }
- } else {
- rv = AddChildSHEntryInternal(aCloneRef, aNewEntry, aChildOffset,
- aLoadType, aCloneChildren);
- }
- return rv;
- }
- nsresult
- nsDocShell::AddChildSHEntryInternal(nsISHEntry* aCloneRef,
- nsISHEntry* aNewEntry,
- int32_t aChildOffset,
- uint32_t aLoadType,
- bool aCloneChildren)
- {
- nsresult rv = NS_OK;
- if (mSessionHistory) {
- /* You are currently in the rootDocShell.
- * You will get here when a subframe has a new url
- * to load and you have walked up the tree all the
- * way to the top to clone the current SHEntry hierarchy
- * and replace the subframe where a new url was loaded with
- * a new entry.
- */
- int32_t index = -1;
- nsCOMPtr<nsISHEntry> currentHE;
- mSessionHistory->GetIndex(&index);
- if (index < 0) {
- return NS_ERROR_FAILURE;
- }
- rv = mSessionHistory->GetEntryAtIndex(index, false,
- getter_AddRefs(currentHE));
- NS_ENSURE_TRUE(currentHE, NS_ERROR_FAILURE);
- nsCOMPtr<nsISHEntry> currentEntry(do_QueryInterface(currentHE));
- if (currentEntry) {
- uint32_t cloneID = 0;
- nsCOMPtr<nsISHEntry> nextEntry;
- aCloneRef->GetID(&cloneID);
- rv = CloneAndReplace(currentEntry, this, cloneID, aNewEntry,
- aCloneChildren, getter_AddRefs(nextEntry));
- if (NS_SUCCEEDED(rv)) {
- nsCOMPtr<nsISHistoryInternal> shPrivate =
- do_QueryInterface(mSessionHistory);
- NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
- rv = shPrivate->AddEntry(nextEntry, true);
- }
- }
- } else {
- /* Just pass this along */
- nsCOMPtr<nsIDocShell> parent =
- do_QueryInterface(GetAsSupports(mParent), &rv);
- if (parent) {
- rv = static_cast<nsDocShell*>(parent.get())->AddChildSHEntryInternal(
- aCloneRef, aNewEntry, aChildOffset, aLoadType, aCloneChildren);
- }
- }
- return rv;
- }
- nsresult
- nsDocShell::AddChildSHEntryToParent(nsISHEntry* aNewEntry, int32_t aChildOffset,
- bool aCloneChildren)
- {
- /* You will get here when you are in a subframe and
- * a new url has been loaded on you.
- * The mOSHE in this subframe will be the previous url's
- * mOSHE. This mOSHE will be used as the identification
- * for this subframe in the CloneAndReplace function.
- */
- // In this case, we will end up calling AddEntry, which increases the
- // current index by 1
- nsCOMPtr<nsISHistory> rootSH;
- GetRootSessionHistory(getter_AddRefs(rootSH));
- if (rootSH) {
- rootSH->GetIndex(&mPreviousTransIndex);
- }
- nsresult rv;
- nsCOMPtr<nsIDocShell> parent = do_QueryInterface(GetAsSupports(mParent), &rv);
- if (parent) {
- rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset, mLoadType,
- aCloneChildren);
- }
- if (rootSH) {
- rootSH->GetIndex(&mLoadedTransIndex);
- #ifdef DEBUG_PAGE_CACHE
- printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
- mLoadedTransIndex);
- #endif
- }
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::SetUseGlobalHistory(bool aUseGlobalHistory)
- {
- nsresult rv;
- mUseGlobalHistory = aUseGlobalHistory;
- if (!aUseGlobalHistory) {
- mGlobalHistory = nullptr;
- return NS_OK;
- }
- // No need to initialize mGlobalHistory if IHistory is available.
- nsCOMPtr<IHistory> history = services::GetHistoryService();
- if (history) {
- return NS_OK;
- }
- if (mGlobalHistory) {
- return NS_OK;
- }
- mGlobalHistory = do_GetService(NS_GLOBALHISTORY2_CONTRACTID, &rv);
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::GetUseGlobalHistory(bool* aUseGlobalHistory)
- {
- *aUseGlobalHistory = mUseGlobalHistory;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::RemoveFromSessionHistory()
- {
- nsCOMPtr<nsISHistoryInternal> internalHistory;
- nsCOMPtr<nsISHistory> sessionHistory;
- nsCOMPtr<nsIDocShellTreeItem> root;
- GetSameTypeRootTreeItem(getter_AddRefs(root));
- if (root) {
- nsCOMPtr<nsIWebNavigation> rootAsWebnav = do_QueryInterface(root);
- if (rootAsWebnav) {
- rootAsWebnav->GetSessionHistory(getter_AddRefs(sessionHistory));
- internalHistory = do_QueryInterface(sessionHistory);
- }
- }
- if (!internalHistory) {
- return NS_OK;
- }
- int32_t index = 0;
- sessionHistory->GetIndex(&index);
- AutoTArray<uint64_t, 16> ids({mHistoryID});
- internalHistory->RemoveEntries(ids, index);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetCreatedDynamically(bool aDynamic)
- {
- mDynamicallyCreated = aDynamic;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetCreatedDynamically(bool* aDynamic)
- {
- *aDynamic = mDynamicallyCreated;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetCurrentSHEntry(nsISHEntry** aEntry, bool* aOSHE)
- {
- *aOSHE = false;
- *aEntry = nullptr;
- if (mLSHE) {
- NS_ADDREF(*aEntry = mLSHE);
- } else if (mOSHE) {
- NS_ADDREF(*aEntry = mOSHE);
- *aOSHE = true;
- }
- return NS_OK;
- }
- nsIScriptGlobalObject*
- nsDocShell::GetScriptGlobalObject()
- {
- NS_ENSURE_SUCCESS(EnsureScriptEnvironment(), nullptr);
- return mScriptGlobal;
- }
- nsIDocument*
- nsDocShell::GetDocument()
- {
- NS_ENSURE_SUCCESS(EnsureContentViewer(), nullptr);
- return mContentViewer->GetDocument();
- }
- nsPIDOMWindowOuter*
- nsDocShell::GetWindow()
- {
- if (NS_FAILED(EnsureScriptEnvironment())) {
- return nullptr;
- }
- return mScriptGlobal->AsOuter();
- }
- NS_IMETHODIMP
- nsDocShell::SetDeviceSizeIsPageSize(bool aValue)
- {
- if (mDeviceSizeIsPageSize != aValue) {
- mDeviceSizeIsPageSize = aValue;
- RefPtr<nsPresContext> presContext;
- GetPresContext(getter_AddRefs(presContext));
- if (presContext) {
- presContext->MediaFeatureValuesChanged(nsRestyleHint(0));
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetDeviceSizeIsPageSize(bool* aValue)
- {
- *aValue = mDeviceSizeIsPageSize;
- return NS_OK;
- }
- void
- nsDocShell::ClearFrameHistory(nsISHEntry* aEntry)
- {
- nsCOMPtr<nsISHContainer> shcontainer = do_QueryInterface(aEntry);
- nsCOMPtr<nsISHistory> rootSH;
- GetRootSessionHistory(getter_AddRefs(rootSH));
- nsCOMPtr<nsISHistoryInternal> history = do_QueryInterface(rootSH);
- if (!history || !shcontainer) {
- return;
- }
- int32_t count = 0;
- shcontainer->GetChildCount(&count);
- AutoTArray<uint64_t, 16> ids;
- for (int32_t i = 0; i < count; ++i) {
- nsCOMPtr<nsISHEntry> child;
- shcontainer->GetChildAt(i, getter_AddRefs(child));
- if (child) {
- uint64_t id = 0;
- child->GetDocshellID(&id);
- ids.AppendElement(id);
- }
- }
- int32_t index = 0;
- rootSH->GetIndex(&index);
- history->RemoveEntries(ids, index);
- }
- //-------------------------------------
- //-- Helper Method for Print discovery
- //-------------------------------------
- bool
- nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog)
- {
- if (mIsPrintingOrPP && aDisplayErrorDialog) {
- DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nullptr, nullptr, nullptr);
- }
- return mIsPrintingOrPP;
- }
- bool
- nsDocShell::IsNavigationAllowed(bool aDisplayPrintErrorDialog,
- bool aCheckIfUnloadFired)
- {
- bool isAllowed = !IsPrintingOrPP(aDisplayPrintErrorDialog) &&
- (!aCheckIfUnloadFired || !mFiredUnloadEvent);
- if (!isAllowed) {
- return false;
- }
- if (!mContentViewer) {
- return true;
- }
- bool firingBeforeUnload;
- mContentViewer->GetBeforeUnloadFiring(&firingBeforeUnload);
- return !firingBeforeUnload;
- }
- //*****************************************************************************
- // nsDocShell::nsIWebNavigation
- //*****************************************************************************
- NS_IMETHODIMP
- nsDocShell::GetCanGoBack(bool* aCanGoBack)
- {
- if (!IsNavigationAllowed(false)) {
- *aCanGoBack = false;
- return NS_OK; // JS may not handle returning of an error code
- }
- nsresult rv;
- nsCOMPtr<nsISHistory> rootSH;
- rv = GetRootSessionHistory(getter_AddRefs(rootSH));
- nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
- NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
- rv = webnav->GetCanGoBack(aCanGoBack);
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::GetCanGoForward(bool* aCanGoForward)
- {
- if (!IsNavigationAllowed(false)) {
- *aCanGoForward = false;
- return NS_OK; // JS may not handle returning of an error code
- }
- nsresult rv;
- nsCOMPtr<nsISHistory> rootSH;
- rv = GetRootSessionHistory(getter_AddRefs(rootSH));
- nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
- NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
- rv = webnav->GetCanGoForward(aCanGoForward);
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::GoBack()
- {
- if (!IsNavigationAllowed()) {
- return NS_OK; // JS may not handle returning of an error code
- }
- nsresult rv;
- nsCOMPtr<nsISHistory> rootSH;
- rv = GetRootSessionHistory(getter_AddRefs(rootSH));
- nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
- NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
- rv = webnav->GoBack();
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::GoForward()
- {
- if (!IsNavigationAllowed()) {
- return NS_OK; // JS may not handle returning of an error code
- }
- nsresult rv;
- nsCOMPtr<nsISHistory> rootSH;
- rv = GetRootSessionHistory(getter_AddRefs(rootSH));
- nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
- NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
- rv = webnav->GoForward();
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::GotoIndex(int32_t aIndex)
- {
- if (!IsNavigationAllowed()) {
- return NS_OK; // JS may not handle returning of an error code
- }
- nsresult rv;
- nsCOMPtr<nsISHistory> rootSH;
- rv = GetRootSessionHistory(getter_AddRefs(rootSH));
- nsCOMPtr<nsIWebNavigation> webnav(do_QueryInterface(rootSH));
- NS_ENSURE_TRUE(webnav, NS_ERROR_FAILURE);
- rv = webnav->GotoIndex(aIndex);
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::LoadURI(const char16_t* aURI,
- uint32_t aLoadFlags,
- nsIURI* aReferringURI,
- nsIInputStream* aPostStream,
- nsIInputStream* aHeaderStream)
- {
- return LoadURIWithOptions(aURI, aLoadFlags, aReferringURI,
- mozilla::net::RP_Default, aPostStream,
- aHeaderStream, nullptr, nullptr);
- }
- NS_IMETHODIMP
- nsDocShell::LoadURIWithOptions(const char16_t* aURI,
- uint32_t aLoadFlags,
- nsIURI* aReferringURI,
- uint32_t aReferrerPolicy,
- nsIInputStream* aPostStream,
- nsIInputStream* aHeaderStream,
- nsIURI* aBaseURI,
- nsIPrincipal* aTriggeringPrincipal)
- {
- NS_ASSERTION((aLoadFlags & 0xf) == 0, "Unexpected flags");
- if (!IsNavigationAllowed()) {
- return NS_OK; // JS may not handle returning of an error code
- }
- nsCOMPtr<nsIURI> uri;
- nsCOMPtr<nsIInputStream> postStream(aPostStream);
- nsresult rv = NS_OK;
- // Create a URI from our string; if that succeeds, we want to
- // change aLoadFlags to not include the ALLOW_THIRD_PARTY_FIXUP
- // flag.
- NS_ConvertUTF16toUTF8 uriString(aURI);
- // Cleanup the empty spaces that might be on each end.
- uriString.Trim(" ");
- // Eliminate embedded newlines, which single-line text fields now allow:
- uriString.StripChars("\r\n");
- NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
- rv = NS_NewURI(getter_AddRefs(uri), uriString);
- if (uri) {
- aLoadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
- }
- nsCOMPtr<nsIURIFixupInfo> fixupInfo;
- if (sURIFixup) {
- // Call the fixup object. This will clobber the rv from NS_NewURI
- // above, but that's fine with us. Note that we need to do this even
- // if NS_NewURI returned a URI, because fixup handles nested URIs, etc
- // (things like view-source:mozilla.org for example).
- uint32_t fixupFlags = 0;
- if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
- fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
- }
- if (aLoadFlags & LOAD_FLAGS_FIXUP_SCHEME_TYPOS) {
- fixupFlags |= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS;
- }
- nsCOMPtr<nsIInputStream> fixupStream;
- rv = sURIFixup->GetFixupURIInfo(uriString, fixupFlags,
- getter_AddRefs(fixupStream),
- getter_AddRefs(fixupInfo));
- if (NS_SUCCEEDED(rv)) {
- fixupInfo->GetPreferredURI(getter_AddRefs(uri));
- fixupInfo->SetConsumer(GetAsSupports(this));
- }
- if (fixupStream) {
- // GetFixupURIInfo only returns a post data stream if it succeeded
- // and changed the URI, in which case we should override the
- // passed-in post data.
- postStream = fixupStream;
- }
- if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
- nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
- if (serv) {
- serv->NotifyObservers(fixupInfo, "keyword-uri-fixup", aURI);
- }
- }
- }
- // else no fixup service so just use the URI we created and see
- // what happens
- if (NS_ERROR_MALFORMED_URI == rv) {
- if (DisplayLoadError(rv, uri, aURI, nullptr) &&
- (aLoadFlags & LOAD_FLAGS_ERROR_LOAD_CHANGES_RV) != 0) {
- return NS_ERROR_LOAD_SHOWED_ERRORPAGE;
- }
- }
- if (NS_FAILED(rv) || !uri) {
- return NS_ERROR_FAILURE;
- }
- PopupControlState popupState;
- if (aLoadFlags & LOAD_FLAGS_ALLOW_POPUPS) {
- popupState = openAllowed;
- aLoadFlags &= ~LOAD_FLAGS_ALLOW_POPUPS;
- } else {
- popupState = openOverridden;
- }
- nsAutoPopupStatePusher statePusher(popupState);
- bool forceAllowDataURI =
- aLoadFlags & LOAD_FLAGS_FORCE_ALLOW_DATA_URI;
- // Don't pass certain flags that aren't needed and end up confusing
- // ConvertLoadTypeToDocShellLoadInfo. We do need to ensure that they are
- // passed to LoadURI though, since it uses them.
- uint32_t extraFlags = (aLoadFlags & EXTRA_LOAD_FLAGS);
- aLoadFlags &= ~EXTRA_LOAD_FLAGS;
- nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
- rv = CreateLoadInfo(getter_AddRefs(loadInfo));
- if (NS_FAILED(rv)) {
- return rv;
- }
- /*
- * If the user "Disables Protection on This Page", we have to make sure to
- * remember the users decision when opening links in child tabs [Bug 906190]
- */
- uint32_t loadType;
- if (aLoadFlags & LOAD_FLAGS_ALLOW_MIXED_CONTENT) {
- loadType = MAKE_LOAD_TYPE(LOAD_NORMAL_ALLOW_MIXED_CONTENT, aLoadFlags);
- } else {
- loadType = MAKE_LOAD_TYPE(LOAD_NORMAL, aLoadFlags);
- }
- loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(loadType));
- loadInfo->SetPostDataStream(postStream);
- loadInfo->SetReferrer(aReferringURI);
- loadInfo->SetReferrerPolicy(aReferrerPolicy);
- loadInfo->SetHeadersStream(aHeaderStream);
- loadInfo->SetBaseURI(aBaseURI);
- loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
- loadInfo->SetForceAllowDataURI(forceAllowDataURI);
- if (fixupInfo) {
- nsAutoString searchProvider, keyword;
- fixupInfo->GetKeywordProviderName(searchProvider);
- fixupInfo->GetKeywordAsSent(keyword);
- MaybeNotifyKeywordSearchLoading(searchProvider, keyword);
- }
- rv = LoadURI(uri, loadInfo, extraFlags, true);
- // Save URI string in case it's needed later when
- // sending to search engine service in EndPageLoad()
- mOriginalUriString = uriString;
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
- const char16_t* aURL,
- nsIChannel* aFailedChannel,
- bool* aDisplayedErrorPage)
- {
- *aDisplayedErrorPage = false;
- // Get prompt and string bundle servcies
- nsCOMPtr<nsIPrompt> prompter;
- nsCOMPtr<nsIStringBundle> stringBundle;
- GetPromptAndStringBundle(getter_AddRefs(prompter),
- getter_AddRefs(stringBundle));
- NS_ENSURE_TRUE(stringBundle, NS_ERROR_FAILURE);
- NS_ENSURE_TRUE(prompter, NS_ERROR_FAILURE);
- nsAutoString error;
- const uint32_t kMaxFormatStrArgs = 3;
- nsAutoString formatStrs[kMaxFormatStrArgs];
- uint32_t formatStrCount = 0;
- bool addHostPort = false;
- nsresult rv = NS_OK;
- nsAutoString messageStr;
- nsAutoCString cssClass;
- nsAutoCString errorPage;
- errorPage.AssignLiteral("neterror");
- // Turn the error code into a human readable error message.
- if (NS_ERROR_UNKNOWN_PROTOCOL == aError) {
- NS_ENSURE_ARG_POINTER(aURI);
- // Extract the schemes into a comma delimited list.
- nsAutoCString scheme;
- aURI->GetScheme(scheme);
- CopyASCIItoUTF16(scheme, formatStrs[0]);
- nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(aURI);
- while (nestedURI) {
- nsCOMPtr<nsIURI> tempURI;
- nsresult rv2;
- rv2 = nestedURI->GetInnerURI(getter_AddRefs(tempURI));
- if (NS_SUCCEEDED(rv2) && tempURI) {
- tempURI->GetScheme(scheme);
- formatStrs[0].AppendLiteral(", ");
- AppendASCIItoUTF16(scheme, formatStrs[0]);
- }
- nestedURI = do_QueryInterface(tempURI);
- }
- formatStrCount = 1;
- error.AssignLiteral("unknownProtocolFound");
- } else if (NS_ERROR_FILE_NOT_FOUND == aError) {
- NS_ENSURE_ARG_POINTER(aURI);
- error.AssignLiteral("fileNotFound");
- } else if (NS_ERROR_FILE_ACCESS_DENIED == aError) {
- NS_ENSURE_ARG_POINTER(aURI);
- error.AssignLiteral("fileAccessDenied");
- } else if (NS_ERROR_UNKNOWN_HOST == aError) {
- NS_ENSURE_ARG_POINTER(aURI);
- // Get the host
- nsAutoCString host;
- nsCOMPtr<nsIURI> innermostURI = NS_GetInnermostURI(aURI);
- innermostURI->GetHost(host);
- CopyUTF8toUTF16(host, formatStrs[0]);
- formatStrCount = 1;
- error.AssignLiteral("dnsNotFound");
- } else if (NS_ERROR_CONNECTION_REFUSED == aError) {
- NS_ENSURE_ARG_POINTER(aURI);
- addHostPort = true;
- error.AssignLiteral("connectionFailure");
- } else if (NS_ERROR_NET_INTERRUPT == aError) {
- NS_ENSURE_ARG_POINTER(aURI);
- addHostPort = true;
- error.AssignLiteral("netInterrupt");
- } else if (NS_ERROR_NET_TIMEOUT == aError) {
- NS_ENSURE_ARG_POINTER(aURI);
- // Get the host
- nsAutoCString host;
- aURI->GetHost(host);
- CopyUTF8toUTF16(host, formatStrs[0]);
- formatStrCount = 1;
- error.AssignLiteral("netTimeout");
- } else if (NS_ERROR_CSP_FRAME_ANCESTOR_VIOLATION == aError ||
- NS_ERROR_CSP_FORM_ACTION_VIOLATION == aError) {
- // CSP error
- cssClass.AssignLiteral("neterror");
- error.AssignLiteral("cspBlocked");
- } else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY) {
- nsCOMPtr<nsINSSErrorsService> nsserr =
- do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
- uint32_t errorClass;
- if (!nsserr || NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))) {
- errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL;
- }
- nsCOMPtr<nsISupports> securityInfo;
- nsCOMPtr<nsITransportSecurityInfo> tsi;
- if (aFailedChannel) {
- aFailedChannel->GetSecurityInfo(getter_AddRefs(securityInfo));
- }
- tsi = do_QueryInterface(securityInfo);
- if (tsi) {
- uint32_t securityState;
- tsi->GetSecurityState(&securityState);
- if (securityState & nsIWebProgressListener::STATE_USES_SSL_3) {
- error.AssignLiteral("sslv3Used");
- addHostPort = true;
- } else if (securityState & nsIWebProgressListener::STATE_USES_WEAK_CRYPTO) {
- error.AssignLiteral("weakCryptoUsed");
- addHostPort = true;
- } else {
- // Usually we should have aFailedChannel and get a detailed message
- tsi->GetErrorMessage(getter_Copies(messageStr));
- }
- } else {
- // No channel, let's obtain the generic error message
- if (nsserr) {
- nsserr->GetErrorMessage(aError, messageStr);
- }
- }
- if (!messageStr.IsEmpty()) {
- if (errorClass == nsINSSErrorsService::ERROR_CLASS_BAD_CERT) {
- error.AssignLiteral("nssBadCert");
- // If this is an HTTP Strict Transport Security host, don't allow
- // overrides (RFC 6797 section 12.1).
- uint32_t flags =
- UsePrivateBrowsing() ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
- bool isStsHost = false;
- if (XRE_IsParentProcess()) {
- nsCOMPtr<nsISiteSecurityService> sss =
- do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI,
- flags, nullptr, &isStsHost);
- NS_ENSURE_SUCCESS(rv, rv);
- } else {
- mozilla::dom::ContentChild* cc =
- mozilla::dom::ContentChild::GetSingleton();
- mozilla::ipc::URIParams uri;
- SerializeURI(aURI, uri);
- cc->SendIsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, flags,
- &isStsHost);
- }
- if (Preferences::GetBool(
- "browser.xul.error_pages.expert_bad_cert", false)) {
- cssClass.AssignLiteral("expertBadCert");
- }
- // HSTS takes precedence over the expert bad cert pref. We
- // never want to show the "Add Exception" button for these sites.
- if (isStsHost) {
- cssClass.AssignLiteral("badStsCert");
- }
- // See if an alternate cert error page is registered
- nsAdoptingCString alternateErrorPage =
- Preferences::GetCString("security.alternate_certificate_error_page");
- if (alternateErrorPage) {
- errorPage.Assign(alternateErrorPage);
- }
- } else {
- error.AssignLiteral("nssFailure2");
- }
- }
- } else if (NS_ERROR_PHISHING_URI == aError ||
- NS_ERROR_MALWARE_URI == aError ||
- NS_ERROR_UNWANTED_URI == aError) {
- nsAutoCString host;
- aURI->GetHost(host);
- CopyUTF8toUTF16(host, formatStrs[0]);
- formatStrCount = 1;
- // Malware and phishing detectors may want to use an alternate error
- // page, but if the pref's not set, we'll fall back on the standard page
- nsAdoptingCString alternateErrorPage =
- Preferences::GetCString("urlclassifier.alternate_error_page");
- if (alternateErrorPage) {
- errorPage.Assign(alternateErrorPage);
- }
- if (NS_ERROR_PHISHING_URI == aError) {
- error.AssignLiteral("deceptiveBlocked");
- } else if (NS_ERROR_MALWARE_URI == aError) {
- error.AssignLiteral("malwareBlocked");
- } else if (NS_ERROR_UNWANTED_URI == aError) {
- error.AssignLiteral("unwantedBlocked");
- }
- cssClass.AssignLiteral("blacklist");
- } else if (NS_ERROR_CONTENT_CRASHED == aError) {
- errorPage.AssignLiteral("tabcrashed");
- error.AssignLiteral("tabcrashed");
- nsCOMPtr<EventTarget> handler = mChromeEventHandler;
- if (handler) {
- nsCOMPtr<Element> element = do_QueryInterface(handler);
- element->GetAttribute(NS_LITERAL_STRING("crashedPageTitle"), messageStr);
- }
- // DisplayLoadError requires a non-empty messageStr to proceed and call
- // LoadErrorPage. If the page doesn't have a title, we will use a blank
- // space which will be trimmed and thus treated as empty by the front-end.
- if (messageStr.IsEmpty()) {
- messageStr.AssignLiteral(u" ");
- }
- } else {
- // Errors requiring simple formatting
- switch (aError) {
- case NS_ERROR_MALFORMED_URI:
- // URI is malformed
- error.AssignLiteral("malformedURI");
- break;
- case NS_ERROR_REDIRECT_LOOP:
- // Doc failed to load because the server generated too many redirects
- error.AssignLiteral("redirectLoop");
- break;
- case NS_ERROR_UNKNOWN_SOCKET_TYPE:
- // Doc failed to load because PSM is not installed
- error.AssignLiteral("unknownSocketType");
- break;
- case NS_ERROR_NET_RESET:
- // Doc failed to load because the server kept reseting the connection
- // before we could read any data from it
- error.AssignLiteral("netReset");
- break;
- case NS_ERROR_DOCUMENT_NOT_CACHED:
- // Doc failed to load because the cache does not contain a copy of
- // the document.
- error.AssignLiteral("notCached");
- break;
- case NS_ERROR_OFFLINE:
- // Doc failed to load because we are offline.
- error.AssignLiteral("netOffline");
- break;
- case NS_ERROR_DOCUMENT_IS_PRINTMODE:
- // Doc navigation attempted while Printing or Print Preview
- error.AssignLiteral("isprinting");
- break;
- case NS_ERROR_PORT_ACCESS_NOT_ALLOWED:
- // Port blocked for security reasons
- addHostPort = true;
- error.AssignLiteral("deniedPortAccess");
- break;
- case NS_ERROR_UNKNOWN_PROXY_HOST:
- // Proxy hostname could not be resolved.
- error.AssignLiteral("proxyResolveFailure");
- break;
- case NS_ERROR_PROXY_CONNECTION_REFUSED:
- // Proxy connection was refused.
- error.AssignLiteral("proxyConnectFailure");
- break;
- case NS_ERROR_INVALID_CONTENT_ENCODING:
- // Bad Content Encoding.
- error.AssignLiteral("contentEncodingError");
- break;
- case NS_ERROR_REMOTE_XUL:
- error.AssignLiteral("remoteXUL");
- break;
- case NS_ERROR_UNSAFE_CONTENT_TYPE:
- // Channel refused to load from an unrecognized content type.
- error.AssignLiteral("unsafeContentType");
- break;
- case NS_ERROR_CORRUPTED_CONTENT:
- // Broken Content Detected. e.g. Content-MD5 check failure.
- error.AssignLiteral("corruptedContentErrorv2");
- break;
- case NS_ERROR_INTERCEPTION_FAILED:
- // ServiceWorker intercepted request, but something went wrong.
- error.AssignLiteral("corruptedContentErrorv2");
- break;
- case NS_ERROR_NET_INADEQUATE_SECURITY:
- // Server negotiated bad TLS for HTTP/2.
- error.AssignLiteral("inadequateSecurityError");
- addHostPort = true;
- break;
- default:
- break;
- }
- }
- // Test if the error should be displayed
- if (error.IsEmpty()) {
- return NS_OK;
- }
- // Test if the error needs to be formatted
- if (!messageStr.IsEmpty()) {
- // already obtained message
- } else {
- if (addHostPort) {
- // Build up the host:port string.
- nsAutoCString hostport;
- if (aURI) {
- aURI->GetHostPort(hostport);
- } else {
- hostport.Assign('?');
- }
- CopyUTF8toUTF16(hostport, formatStrs[formatStrCount++]);
- }
- nsAutoCString spec;
- rv = NS_ERROR_NOT_AVAILABLE;
- if (aURI) {
- // displaying "file://" is aesthetically unpleasing and could even be
- // confusing to the user
- bool isFileURI = false;
- rv = aURI->SchemeIs("file", &isFileURI);
- if (NS_SUCCEEDED(rv) && isFileURI) {
- aURI->GetPath(spec);
- } else {
- aURI->GetSpec(spec);
- }
- nsAutoCString charset;
- // unescape and convert from origin charset
- aURI->GetOriginCharset(charset);
- nsCOMPtr<nsITextToSubURI> textToSubURI(
- do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv));
- if (NS_SUCCEEDED(rv)) {
- rv = textToSubURI->UnEscapeURIForUI(charset, spec,
- formatStrs[formatStrCount]);
- }
- } else {
- spec.Assign('?');
- }
- if (NS_FAILED(rv)) {
- CopyUTF8toUTF16(spec, formatStrs[formatStrCount]);
- }
- rv = NS_OK;
- ++formatStrCount;
- const char16_t* strs[kMaxFormatStrArgs];
- for (uint32_t i = 0; i < formatStrCount; i++) {
- strs[i] = formatStrs[i].get();
- }
- nsXPIDLString str;
- rv = stringBundle->FormatStringFromName(error.get(), strs, formatStrCount,
- getter_Copies(str));
- NS_ENSURE_SUCCESS(rv, rv);
- messageStr.Assign(str.get());
- }
- // Display the error as a page or an alert prompt
- NS_ENSURE_FALSE(messageStr.IsEmpty(), NS_ERROR_FAILURE);
- if (NS_ERROR_NET_INTERRUPT == aError || NS_ERROR_NET_RESET == aError) {
- bool isSecureURI = false;
- rv = aURI->SchemeIs("https", &isSecureURI);
- if (NS_SUCCEEDED(rv) && isSecureURI) {
- // Maybe TLS intolerant. Treat this as an SSL error.
- error.AssignLiteral("nssFailure2");
- }
- }
- if (UseErrorPages()) {
- // Display an error page
- nsresult loadedPage = LoadErrorPage(aURI, aURL, errorPage.get(),
- error.get(), messageStr.get(),
- cssClass.get(), aFailedChannel);
- *aDisplayedErrorPage = NS_SUCCEEDED(loadedPage);
- } else {
- // The prompter reqires that our private window has a document (or it
- // asserts). Satisfy that assertion now since GetDoc will force
- // creation of one if it hasn't already been created.
- if (mScriptGlobal) {
- Unused << mScriptGlobal->GetDoc();
- }
- // Display a message box
- prompter->Alert(nullptr, messageStr.get());
- }
- return NS_OK;
- }
- #define PREF_SAFEBROWSING_ALLOWOVERRIDE "browser.safebrowsing.allowOverride"
- NS_IMETHODIMP
- nsDocShell::LoadErrorPage(nsIURI* aURI, const char16_t* aURL,
- const char* aErrorPage,
- const char16_t* aErrorType,
- const char16_t* aDescription,
- const char* aCSSClass,
- nsIChannel* aFailedChannel)
- {
- #if defined(DEBUG)
- if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
- nsAutoCString chanName;
- if (aFailedChannel) {
- aFailedChannel->GetName(chanName);
- } else {
- chanName.AssignLiteral("<no channel>");
- }
- MOZ_LOG(gDocShellLog, LogLevel::Debug,
- ("nsDocShell[%p]::LoadErrorPage(\"%s\", \"%s\", {...}, [%s])\n", this,
- aURI->GetSpecOrDefault().get(), NS_ConvertUTF16toUTF8(aURL).get(),
- chanName.get()));
- }
- #endif
- mFailedChannel = aFailedChannel;
- mFailedURI = aURI;
- mFailedLoadType = mLoadType;
- if (mLSHE) {
- // Abandon mLSHE's BFCache entry and create a new one. This way, if
- // we go back or forward to another SHEntry with the same doc
- // identifier, the error page won't persist.
- mLSHE->AbandonBFCacheEntry();
- }
- nsAutoCString url;
- nsAutoCString charset;
- if (aURI) {
- nsresult rv = aURI->GetSpec(url);
- NS_ENSURE_SUCCESS(rv, rv);
- rv = aURI->GetOriginCharset(charset);
- NS_ENSURE_SUCCESS(rv, rv);
- } else if (aURL) {
- CopyUTF16toUTF8(aURL, url);
- } else {
- return NS_ERROR_INVALID_POINTER;
- }
- // Create a URL to pass all the error information through to the page.
- #undef SAFE_ESCAPE
- #define SAFE_ESCAPE(output, input, params) \
- if (NS_WARN_IF(!NS_Escape(input, output, params))) { \
- return NS_ERROR_OUT_OF_MEMORY; \
- }
- nsCString escapedUrl, escapedCharset, escapedError, escapedDescription,
- escapedCSSClass;
- SAFE_ESCAPE(escapedUrl, url, url_Path);
- SAFE_ESCAPE(escapedCharset, charset, url_Path);
- SAFE_ESCAPE(escapedError, NS_ConvertUTF16toUTF8(aErrorType), url_Path);
- SAFE_ESCAPE(escapedDescription,
- NS_ConvertUTF16toUTF8(aDescription), url_Path);
- if (aCSSClass) {
- nsCString cssClass(aCSSClass);
- SAFE_ESCAPE(escapedCSSClass, cssClass, url_Path);
- }
- nsCString errorPageUrl("about:");
- errorPageUrl.AppendASCII(aErrorPage);
- errorPageUrl.AppendLiteral("?e=");
- errorPageUrl.AppendASCII(escapedError.get());
- errorPageUrl.AppendLiteral("&u=");
- errorPageUrl.AppendASCII(escapedUrl.get());
- if ((strcmp(aErrorPage, "blocked") == 0) &&
- Preferences::GetBool(PREF_SAFEBROWSING_ALLOWOVERRIDE, true)) {
- errorPageUrl.AppendLiteral("&o=1");
- }
- if (!escapedCSSClass.IsEmpty()) {
- errorPageUrl.AppendLiteral("&s=");
- errorPageUrl.AppendASCII(escapedCSSClass.get());
- }
- errorPageUrl.AppendLiteral("&c=");
- errorPageUrl.AppendASCII(escapedCharset.get());
- nsAutoCString frameType(FrameTypeToString(mFrameType));
- errorPageUrl.AppendLiteral("&f=");
- errorPageUrl.AppendASCII(frameType.get());
- // Append the manifest URL if the error comes from an app.
- nsString manifestURL;
- nsresult rv = GetAppManifestURL(manifestURL);
- if (manifestURL.Length() > 0) {
- nsCString manifestParam;
- SAFE_ESCAPE(manifestParam, NS_ConvertUTF16toUTF8(manifestURL), url_Path);
- errorPageUrl.AppendLiteral("&m=");
- errorPageUrl.AppendASCII(manifestParam.get());
- }
- nsCOMPtr<nsICaptivePortalService> cps = do_GetService(NS_CAPTIVEPORTAL_CID);
- int32_t cpsState;
- if (cps && NS_SUCCEEDED(cps->GetState(&cpsState)) &&
- cpsState == nsICaptivePortalService::LOCKED_PORTAL) {
- errorPageUrl.AppendLiteral("&captive=true");
- }
- // netError.xhtml's getDescription only handles the "d" parameter at the
- // end of the URL, so append it last.
- errorPageUrl.AppendLiteral("&d=");
- errorPageUrl.AppendASCII(escapedDescription.get());
- nsCOMPtr<nsIURI> errorPageURI;
- rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
- NS_ENSURE_SUCCESS(rv, rv);
- return InternalLoad(errorPageURI, nullptr, false, false,
- nullptr, mozilla::net::RP_Default,
- nsContentUtils::GetSystemPrincipal(), nullptr,
- INTERNAL_LOAD_FLAGS_NONE, EmptyString(),
- nullptr, NullString(), nullptr, nullptr, LOAD_ERROR_PAGE,
- nullptr, true, NullString(), this, nullptr, nullptr,
- nullptr);
- }
- bool
- nsDocShell::IsReloadFlooding()
- {
- if (mReloadFloodGuardCount > kReloadLimit) {
- TimeStamp now = TimeStamp::Now();
- if (now - mReloadFloodGuardUpdated > TimeDuration::FromSeconds(kReloadTimeSecs)) {
- mReloadFloodGuardCount = 0;
- mReloadFloodGuardUpdated = now;
- mReloadFloodGuardReported = false;
- return false;
- }
- return true;
- }
- mReloadFloodGuardCount++;
- return false;
- }
- NS_IMETHODIMP
- nsDocShell::Reload(uint32_t aReloadFlags)
- {
- if (!IsNavigationAllowed()) {
- return NS_OK; // JS may not handle returning of an error code
- }
- nsresult rv;
- NS_ASSERTION(((aReloadFlags & 0xf) == 0),
- "Reload command not updated to use load flags!");
- NS_ASSERTION((aReloadFlags & EXTRA_LOAD_FLAGS) == 0,
- "Don't pass these flags to Reload");
- uint32_t loadType = MAKE_LOAD_TYPE(LOAD_RELOAD_NORMAL, aReloadFlags);
- NS_ENSURE_TRUE(IsValidLoadType(loadType), NS_ERROR_INVALID_ARG);
- // Send notifications to the HistoryListener if any, about the impending
- // reload
- nsCOMPtr<nsISHistory> rootSH;
- rv = GetRootSessionHistory(getter_AddRefs(rootSH));
- nsCOMPtr<nsISHistoryInternal> shistInt(do_QueryInterface(rootSH));
- bool canReload = true;
- if (rootSH) {
- shistInt->NotifyOnHistoryReload(mCurrentURI, aReloadFlags, &canReload);
- }
- // If we're being flooded with reload requests, we should abort early
- // from the reload logic.
- if (IsReloadFlooding()) {
- // Report a warning to the console to tell developers why their reload
- // failed.
- // Do this only if not yet marked reported so we only report it once per
- // flood interval.
- if (!mReloadFloodGuardReported) {
- #if 0
- nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
- NS_LITERAL_CSTRING("Reload"),
- GetDocument(),
- nsContentUtils::eDOM_PROPERTIES,
- "ReloadFloodingPrevented");
- #endif
- mReloadFloodGuardReported = true;
- }
- return NS_OK;
- }
- if (!canReload) {
- return NS_OK;
- }
- /* If you change this part of code, make sure bug 45297 does not re-occur */
- if (mOSHE) {
- rv = LoadHistoryEntry(mOSHE, loadType);
- } else if (mLSHE) { // In case a reload happened before the current load is done
- rv = LoadHistoryEntry(mLSHE, loadType);
- } else {
- nsCOMPtr<nsIDocument> doc(GetDocument());
- if (!doc) {
- return NS_OK;
- }
- // Do not inherit owner from document
- uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
- nsAutoString srcdoc;
- nsCOMPtr<nsIURI> baseURI;
- nsCOMPtr<nsIURI> originalURI;
- bool loadReplace = false;
- nsIPrincipal* triggeringPrincipal = doc->NodePrincipal();
- nsAutoString contentTypeHint;
- doc->GetContentType(contentTypeHint);
- if (doc->IsSrcdocDocument()) {
- doc->GetSrcdocData(srcdoc);
- flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
- baseURI = doc->GetBaseURI();
- }
- nsCOMPtr<nsIChannel> chan = doc->GetChannel();
- if (chan) {
- uint32_t loadFlags;
- chan->GetLoadFlags(&loadFlags);
- loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
- nsCOMPtr<nsIHttpChannel> httpChan(do_QueryInterface(chan));
- if (httpChan) {
- httpChan->GetOriginalURI(getter_AddRefs(originalURI));
- }
- }
- MOZ_ASSERT(triggeringPrincipal, "Need a valid triggeringPrincipal");
- // Stack variables to ensure changes to the member variables don't affect to
- // the call.
- nsCOMPtr<nsIURI> currentURI = mCurrentURI;
- nsCOMPtr<nsIURI> referrerURI = mReferrerURI;
- uint32_t referrerPolicy = mReferrerPolicy;
- rv = InternalLoad(currentURI,
- originalURI,
- loadReplace,
- false, // Is from processing frame attributes
- referrerURI,
- referrerPolicy,
- triggeringPrincipal,
- triggeringPrincipal,
- flags,
- EmptyString(), // No window target
- NS_LossyConvertUTF16toASCII(contentTypeHint).get(),
- NullString(), // No forced download
- nullptr, // No post data
- nullptr, // No headers data
- loadType, // Load type
- nullptr, // No SHEntry
- true,
- srcdoc, // srcdoc argument for iframe
- this, // For reloads we are the source
- baseURI,
- nullptr, // No nsIDocShell
- nullptr); // No nsIRequest
- }
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::Stop(uint32_t aStopFlags)
- {
- // Revoke any pending event related to content viewer restoration
- mRestorePresentationEvent.Revoke();
- if (mLoadType == LOAD_ERROR_PAGE) {
- if (mLSHE) {
- // Since error page loads never unset mLSHE, do so now
- SetHistoryEntry(&mOSHE, mLSHE);
- SetHistoryEntry(&mLSHE, nullptr);
- }
- mFailedChannel = nullptr;
- mFailedURI = nullptr;
- }
- if (nsIWebNavigation::STOP_CONTENT & aStopFlags) {
- // Stop the document loading and animations
- if (mContentViewer) {
- nsCOMPtr<nsIContentViewer> cv = mContentViewer;
- cv->Stop();
- }
- } else if (nsIWebNavigation::STOP_NETWORK & aStopFlags) {
- // Stop the document loading only
- if (mContentViewer) {
- RefPtr<nsIDocument> doc = mContentViewer->GetDocument();
- if (doc) {
- doc->StopDocumentLoad();
- }
- }
- }
- if (nsIWebNavigation::STOP_NETWORK & aStopFlags) {
- // Suspend any timers that were set for this loader. We'll clear
- // them out for good in CreateContentViewer.
- if (mRefreshURIList) {
- SuspendRefreshURIs();
- mSavedRefreshURIList.swap(mRefreshURIList);
- mRefreshURIList = nullptr;
- }
- // XXXbz We could also pass |this| to nsIURILoader::Stop. That will
- // just call Stop() on us as an nsIDocumentLoader... We need fewer
- // redundant apis!
- Stop();
- }
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- nsCOMPtr<nsIWebNavigation> shellAsNav(do_QueryObject(iter.GetNext()));
- if (shellAsNav) {
- shellAsNav->Stop(aStopFlags);
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetDocument(nsIDOMDocument** aDocument)
- {
- NS_ENSURE_ARG_POINTER(aDocument);
- NS_ENSURE_SUCCESS(EnsureContentViewer(), NS_ERROR_FAILURE);
- return mContentViewer->GetDOMDocument(aDocument);
- }
- NS_IMETHODIMP
- nsDocShell::GetCurrentURI(nsIURI** aURI)
- {
- NS_ENSURE_ARG_POINTER(aURI);
- if (mCurrentURI) {
- return NS_EnsureSafeToReturn(mCurrentURI, aURI);
- }
- *aURI = nullptr;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetReferringURI(nsIURI** aURI)
- {
- NS_ENSURE_ARG_POINTER(aURI);
- *aURI = mReferrerURI;
- NS_IF_ADDREF(*aURI);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetSessionHistory(nsISHistory* aSessionHistory)
- {
- NS_ENSURE_TRUE(aSessionHistory, NS_ERROR_FAILURE);
- // make sure that we are the root docshell and
- // set a handle to root docshell in SH.
- nsCOMPtr<nsIDocShellTreeItem> root;
- /* Get the root docshell. If *this* is the root docshell
- * then save a handle to *this* in SH. SH needs it to do
- * traversions thro' its entries
- */
- GetSameTypeRootTreeItem(getter_AddRefs(root));
- NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
- if (root.get() == static_cast<nsIDocShellTreeItem*>(this)) {
- mSessionHistory = aSessionHistory;
- nsCOMPtr<nsISHistoryInternal> shPrivate =
- do_QueryInterface(mSessionHistory);
- NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
- shPrivate->SetRootDocShell(this);
- return NS_OK;
- }
- return NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsDocShell::GetSessionHistory(nsISHistory** aSessionHistory)
- {
- NS_ENSURE_ARG_POINTER(aSessionHistory);
- *aSessionHistory = mSessionHistory;
- NS_IF_ADDREF(*aSessionHistory);
- return NS_OK;
- }
- //*****************************************************************************
- // nsDocShell::nsIWebPageDescriptor
- //*****************************************************************************
- NS_IMETHODIMP
- nsDocShell::LoadPage(nsISupports* aPageDescriptor, uint32_t aDisplayType)
- {
- nsCOMPtr<nsISHEntry> shEntryIn(do_QueryInterface(aPageDescriptor));
- // Currently, the opaque 'page descriptor' is an nsISHEntry...
- if (!shEntryIn) {
- return NS_ERROR_INVALID_POINTER;
- }
- // Now clone shEntryIn, since we might end up modifying it later on, and we
- // want a page descriptor to be reusable.
- nsCOMPtr<nsISHEntry> shEntry;
- nsresult rv = shEntryIn->Clone(getter_AddRefs(shEntry));
- NS_ENSURE_SUCCESS(rv, rv);
- // Give our cloned shEntry a new bfcache entry so this load is independent
- // of all other loads. (This is important, in particular, for bugs 582795
- // and 585298.)
- rv = shEntry->AbandonBFCacheEntry();
- NS_ENSURE_SUCCESS(rv, rv);
- //
- // load the page as view-source
- //
- if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE == aDisplayType) {
- nsCOMPtr<nsIURI> oldUri, newUri;
- nsCString spec, newSpec;
- // Create a new view-source URI and replace the original.
- rv = shEntry->GetURI(getter_AddRefs(oldUri));
- if (NS_FAILED(rv)) {
- return rv;
- }
- oldUri->GetSpec(spec);
- newSpec.AppendLiteral("view-source:");
- newSpec.Append(spec);
- rv = NS_NewURI(getter_AddRefs(newUri), newSpec);
- if (NS_FAILED(rv)) {
- return rv;
- }
- shEntry->SetURI(newUri);
- shEntry->SetOriginalURI(nullptr);
- // shEntry's current triggering principal is whoever loaded that page initially.
- // But now we're doing another load of the page, via an API that is only exposed
- // to system code. The triggering principal for this load should be the system
- // principal.
- shEntry->SetTriggeringPrincipal(nsContentUtils::GetSystemPrincipal());
- }
- rv = LoadHistoryEntry(shEntry, LOAD_HISTORY);
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::GetCurrentDescriptor(nsISupports** aPageDescriptor)
- {
- NS_PRECONDITION(aPageDescriptor, "Null out param?");
- *aPageDescriptor = nullptr;
- nsISHEntry* src = mOSHE ? mOSHE : mLSHE;
- if (src) {
- nsCOMPtr<nsISHEntry> dest;
- nsresult rv = src->Clone(getter_AddRefs(dest));
- if (NS_FAILED(rv)) {
- return rv;
- }
- // null out inappropriate cloned attributes...
- dest->SetParent(nullptr);
- dest->SetIsSubFrame(false);
- return CallQueryInterface(dest, aPageDescriptor);
- }
- return NS_ERROR_NOT_AVAILABLE;
- }
- //*****************************************************************************
- // nsDocShell::nsIBaseWindow
- //*****************************************************************************
- NS_IMETHODIMP
- nsDocShell::InitWindow(nativeWindow aParentNativeWindow,
- nsIWidget* aParentWidget, int32_t aX, int32_t aY,
- int32_t aWidth, int32_t aHeight)
- {
- SetParentWidget(aParentWidget);
- SetPositionAndSize(aX, aY, aWidth, aHeight, 0);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::Create()
- {
- if (mCreated) {
- // We've already been created
- return NS_OK;
- }
- NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
- "Unexpected item type in docshell");
- NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
- mCreated = true;
- if (gValidateOrigin == 0xffffffff) {
- // Check pref to see if we should prevent frameset spoofing
- gValidateOrigin =
- Preferences::GetBool("browser.frame.validate_origin", true);
- }
- // Should we use XUL error pages instead of alerts if possible?
- mUseErrorPages =
- Preferences::GetBool("browser.xul.error_pages.enabled", mUseErrorPages);
- if (!gAddedPreferencesVarCache) {
- Preferences::AddBoolVarCache(&sUseErrorPages,
- "browser.xul.error_pages.enabled",
- mUseErrorPages);
- gAddedPreferencesVarCache = true;
- }
- mDisableMetaRefreshWhenInactive =
- Preferences::GetBool("browser.meta_refresh_when_inactive.disabled",
- mDisableMetaRefreshWhenInactive);
- mDeviceSizeIsPageSize =
- Preferences::GetBool("docshell.device_size_is_page_size",
- mDeviceSizeIsPageSize);
- nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
- if (serv) {
- const char* msg = mItemType == typeContent ?
- NS_WEBNAVIGATION_CREATE : NS_CHROME_WEBNAVIGATION_CREATE;
- serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::Destroy()
- {
- NS_ASSERTION(mItemType == typeContent || mItemType == typeChrome,
- "Unexpected item type in docshell");
- if (!mIsBeingDestroyed) {
- nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
- if (serv) {
- const char* msg = mItemType == typeContent ?
- NS_WEBNAVIGATION_DESTROY : NS_CHROME_WEBNAVIGATION_DESTROY;
- serv->NotifyObservers(GetAsSupports(this), msg, nullptr);
- }
- }
- mIsBeingDestroyed = true;
- // Make sure we don't record profile timeline markers anymore
- SetRecordProfileTimelineMarkers(false);
- // Remove our pref observers
- if (mObserveErrorPages) {
- mObserveErrorPages = false;
- }
- // Make sure to blow away our mLoadingURI just in case. No loads
- // from inside this pagehide.
- mLoadingURI = nullptr;
- // Fire unload event before we blow anything away.
- (void)FirePageHideNotification(true);
- // Clear pointers to any detached nsEditorData that's lying
- // around in shistory entries. Breaks cycle. See bug 430921.
- if (mOSHE) {
- mOSHE->SetEditorData(nullptr);
- }
- if (mLSHE) {
- mLSHE->SetEditorData(nullptr);
- }
- // Note: mContentListener can be null if Init() failed and we're being
- // called from the destructor.
- if (mContentListener) {
- mContentListener->DropDocShellReference();
- mContentListener->SetParentContentListener(nullptr);
- // Note that we do NOT set mContentListener to null here; that
- // way if someone tries to do a load in us after this point
- // the nsDSURIContentListener will block it. All of which
- // means that we should do this before calling Stop(), of
- // course.
- }
- // Stop any URLs that are currently being loaded...
- Stop(nsIWebNavigation::STOP_ALL);
- mEditorData = nullptr;
- mTransferableHookData = nullptr;
- // Save the state of the current document, before destroying the window.
- // This is needed to capture the state of a frameset when the new document
- // causes the frameset to be destroyed...
- PersistLayoutHistoryState();
- // Remove this docshell from its parent's child list
- nsCOMPtr<nsIDocShellTreeItem> docShellParentAsItem =
- do_QueryInterface(GetAsSupports(mParent));
- if (docShellParentAsItem) {
- docShellParentAsItem->RemoveChild(this);
- }
- if (mContentViewer) {
- mContentViewer->Close(nullptr);
- mContentViewer->Destroy();
- mContentViewer = nullptr;
- }
- nsDocLoader::Destroy();
- mParentWidget = nullptr;
- mCurrentURI = nullptr;
- if (mScriptGlobal) {
- mScriptGlobal->DetachFromDocShell();
- mScriptGlobal = nullptr;
- }
- if (mSessionHistory) {
- // We want to destroy these content viewers now rather than
- // letting their destruction wait for the session history
- // entries to get garbage collected. (Bug 488394)
- nsCOMPtr<nsISHistoryInternal> shPrivate =
- do_QueryInterface(mSessionHistory);
- if (shPrivate) {
- shPrivate->EvictAllContentViewers();
- }
- mSessionHistory = nullptr;
- }
- SetTreeOwner(nullptr);
- mOnePermittedSandboxedNavigator = nullptr;
- // required to break ref cycle
- mSecurityUI = nullptr;
- // Cancel any timers that were set for this docshell; this is needed
- // to break the cycle between us and the timers.
- CancelRefreshURITimers();
- if (UsePrivateBrowsing()) {
- mPrivateBrowsingId = 0;
- mOriginAttributes.SyncAttributesWithPrivateBrowsing(false);
- if (mAffectPrivateSessionLifetime) {
- DecreasePrivateDocShellCount();
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetUnscaledDevicePixelsPerCSSPixel(double* aScale)
- {
- if (mParentWidget) {
- *aScale = mParentWidget->GetDefaultScale().scale;
- return NS_OK;
- }
- nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
- if (ownerWindow) {
- return ownerWindow->GetUnscaledDevicePixelsPerCSSPixel(aScale);
- }
- *aScale = 1.0;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetDevicePixelsPerDesktopPixel(double* aScale)
- {
- if (mParentWidget) {
- *aScale = mParentWidget->GetDesktopToDeviceScale().scale;
- return NS_OK;
- }
- nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
- if (ownerWindow) {
- return ownerWindow->GetDevicePixelsPerDesktopPixel(aScale);
- }
- *aScale = 1.0;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetPosition(int32_t aX, int32_t aY)
- {
- mBounds.x = aX;
- mBounds.y = aY;
- if (mContentViewer) {
- NS_ENSURE_SUCCESS(mContentViewer->Move(aX, aY), NS_ERROR_FAILURE);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetPositionDesktopPix(int32_t aX, int32_t aY)
- {
- nsCOMPtr<nsIBaseWindow> ownerWindow(do_QueryInterface(mTreeOwner));
- if (ownerWindow) {
- return ownerWindow->SetPositionDesktopPix(aX, aY);
- }
- double scale = 1.0;
- GetDevicePixelsPerDesktopPixel(&scale);
- return SetPosition(NSToIntRound(aX * scale), NSToIntRound(aY * scale));
- }
- NS_IMETHODIMP
- nsDocShell::GetPosition(int32_t* aX, int32_t* aY)
- {
- return GetPositionAndSize(aX, aY, nullptr, nullptr);
- }
- NS_IMETHODIMP
- nsDocShell::SetSize(int32_t aWidth, int32_t aHeight, bool aRepaint)
- {
- int32_t x = 0, y = 0;
- GetPosition(&x, &y);
- return SetPositionAndSize(x, y, aWidth, aHeight,
- aRepaint ? nsIBaseWindow::eRepaint : 0);
- }
- NS_IMETHODIMP
- nsDocShell::GetSize(int32_t* aWidth, int32_t* aHeight)
- {
- return GetPositionAndSize(nullptr, nullptr, aWidth, aHeight);
- }
- NS_IMETHODIMP
- nsDocShell::SetPositionAndSize(int32_t aX, int32_t aY, int32_t aWidth,
- int32_t aHeight, uint32_t aFlags)
- {
- mBounds.x = aX;
- mBounds.y = aY;
- mBounds.width = aWidth;
- mBounds.height = aHeight;
- // Hold strong ref, since SetBounds can make us null out mContentViewer
- nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
- if (viewer) {
- uint32_t cvflags = (aFlags & nsIBaseWindow::eDelayResize) ?
- nsIContentViewer::eDelayResize : 0;
- // XXX Border figured in here or is that handled elsewhere?
- nsresult rv = viewer->SetBoundsWithFlags(mBounds, cvflags);
- NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aWidth,
- int32_t* aHeight)
- {
- if (mParentWidget) {
- // ensure size is up-to-date if window has changed resolution
- LayoutDeviceIntRect r = mParentWidget->GetClientBounds();
- SetPositionAndSize(mBounds.x, mBounds.y, r.width, r.height, 0);
- }
- // We should really consider just getting this information from
- // our window instead of duplicating the storage and code...
- if (aWidth || aHeight) {
- // Caller wants to know our size; make sure to give them up to
- // date information.
- nsCOMPtr<nsIDocument> doc(do_GetInterface(GetAsSupports(mParent)));
- if (doc) {
- doc->FlushPendingNotifications(Flush_Layout);
- }
- }
- DoGetPositionAndSize(aX, aY, aWidth, aHeight);
- return NS_OK;
- }
- void
- nsDocShell::DoGetPositionAndSize(int32_t* aX, int32_t* aY, int32_t* aWidth,
- int32_t* aHeight)
- {
- if (aX) {
- *aX = mBounds.x;
- }
- if (aY) {
- *aY = mBounds.y;
- }
- if (aWidth) {
- *aWidth = mBounds.width;
- }
- if (aHeight) {
- *aHeight = mBounds.height;
- }
- }
- NS_IMETHODIMP
- nsDocShell::Repaint(bool aForce)
- {
- nsCOMPtr<nsIPresShell> presShell = GetPresShell();
- NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE);
- nsViewManager* viewManager = presShell->GetViewManager();
- NS_ENSURE_TRUE(viewManager, NS_ERROR_FAILURE);
- viewManager->InvalidateAllViews();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetParentWidget(nsIWidget** aParentWidget)
- {
- NS_ENSURE_ARG_POINTER(aParentWidget);
- *aParentWidget = mParentWidget;
- NS_IF_ADDREF(*aParentWidget);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetParentWidget(nsIWidget* aParentWidget)
- {
- mParentWidget = aParentWidget;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetParentNativeWindow(nativeWindow* aParentNativeWindow)
- {
- NS_ENSURE_ARG_POINTER(aParentNativeWindow);
- if (mParentWidget) {
- *aParentNativeWindow = mParentWidget->GetNativeData(NS_NATIVE_WIDGET);
- } else {
- *aParentNativeWindow = nullptr;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetParentNativeWindow(nativeWindow aParentNativeWindow)
- {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- NS_IMETHODIMP
- nsDocShell::GetNativeHandle(nsAString& aNativeHandle)
- {
- // the nativeHandle should be accessed from nsIXULWindow
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- NS_IMETHODIMP
- nsDocShell::GetVisibility(bool* aVisibility)
- {
- NS_ENSURE_ARG_POINTER(aVisibility);
- *aVisibility = false;
- if (!mContentViewer) {
- return NS_OK;
- }
- nsCOMPtr<nsIPresShell> presShell = GetPresShell();
- if (!presShell) {
- return NS_OK;
- }
- // get the view manager
- nsViewManager* vm = presShell->GetViewManager();
- NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
- // get the root view
- nsView* view = vm->GetRootView(); // views are not ref counted
- NS_ENSURE_TRUE(view, NS_ERROR_FAILURE);
- // if our root view is hidden, we are not visible
- if (view->GetVisibility() == nsViewVisibility_kHide) {
- return NS_OK;
- }
- // otherwise, we must walk up the document and view trees checking
- // for a hidden view, unless we're an off screen browser, which
- // would make this test meaningless.
- RefPtr<nsDocShell> docShell = this;
- RefPtr<nsDocShell> parentItem = docShell->GetParentDocshell();
- while (parentItem) {
- presShell = docShell->GetPresShell();
- nsCOMPtr<nsIPresShell> pPresShell = parentItem->GetPresShell();
- // Null-check for crash in bug 267804
- if (!pPresShell) {
- NS_NOTREACHED("parent docshell has null pres shell");
- return NS_OK;
- }
- vm = presShell->GetViewManager();
- if (vm) {
- view = vm->GetRootView();
- }
- if (view) {
- view = view->GetParent(); // anonymous inner view
- if (view) {
- view = view->GetParent(); // subdocumentframe's view
- }
- }
- nsIFrame* frame = view ? view->GetFrame() : nullptr;
- bool isDocShellOffScreen = false;
- docShell->GetIsOffScreenBrowser(&isDocShellOffScreen);
- if (frame &&
- !frame->IsVisibleConsideringAncestors(
- nsIFrame::VISIBILITY_CROSS_CHROME_CONTENT_BOUNDARY) &&
- !isDocShellOffScreen) {
- return NS_OK;
- }
- docShell = parentItem;
- parentItem = docShell->GetParentDocshell();
- }
- nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
- if (!treeOwnerAsWin) {
- *aVisibility = true;
- return NS_OK;
- }
- // Check with the tree owner as well to give embedders a chance to
- // expose visibility as well.
- return treeOwnerAsWin->GetVisibility(aVisibility);
- }
- NS_IMETHODIMP
- nsDocShell::SetIsOffScreenBrowser(bool aIsOffScreen)
- {
- mIsOffScreenBrowser = aIsOffScreen;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetIsOffScreenBrowser(bool* aIsOffScreen)
- {
- *aIsOffScreen = mIsOffScreenBrowser;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetIsActive(bool aIsActive)
- {
- // We disallow setting active on chrome docshells.
- if (mItemType == nsIDocShellTreeItem::typeChrome) {
- return NS_ERROR_INVALID_ARG;
- }
- // Keep track ourselves.
- mIsActive = aIsActive;
- // Clear prerender flag if necessary.
- mIsPrerendered &= !aIsActive;
- // Tell the PresShell about it.
- nsCOMPtr<nsIPresShell> pshell = GetPresShell();
- if (pshell) {
- pshell->SetIsActive(aIsActive);
- }
- // Tell the window about it
- if (mScriptGlobal) {
- mScriptGlobal->SetIsBackground(!aIsActive);
- if (nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc()) {
- // Update orientation when the top-level browsing context becomes active.
- // We make an exception for apps because they currently rely on
- // orientation locks persisting across browsing contexts.
- if (aIsActive && !GetIsApp()) {
- nsCOMPtr<nsIDocShellTreeItem> parent;
- GetSameTypeParent(getter_AddRefs(parent));
- if (!parent) {
- // We only care about the top-level browsing context.
- uint16_t orientation = OrientationLock();
- ScreenOrientation::UpdateActiveOrientationLock(orientation);
- }
- }
- doc->PostVisibilityUpdateEvent();
- }
- }
- // Tell the nsDOMNavigationTiming about it
- RefPtr<nsDOMNavigationTiming> timing = mTiming;
- if (!timing && mContentViewer) {
- nsIDocument* doc = mContentViewer->GetDocument();
- if (doc) {
- timing = doc->GetNavigationTiming();
- }
- }
- if (timing) {
- timing->NotifyDocShellStateChanged(
- aIsActive ? nsDOMNavigationTiming::DocShellState::eActive
- : nsDOMNavigationTiming::DocShellState::eInactive);
- }
- // Recursively tell all of our children, but don't tell <iframe mozbrowser>
- // children; they handle their state separately.
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext());
- if (!docshell) {
- continue;
- }
- if (!docshell->GetIsMozBrowserOrApp()) {
- docshell->SetIsActive(aIsActive);
- }
- }
- // Restart or stop meta refresh timers if necessary
- if (mDisableMetaRefreshWhenInactive) {
- if (mIsActive) {
- ResumeRefreshURIs();
- } else {
- SuspendRefreshURIs();
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetIsActive(bool* aIsActive)
- {
- *aIsActive = mIsActive;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetIsPrerendered()
- {
- MOZ_ASSERT(!mIsPrerendered,
- "SetIsPrerendered() called on already prerendered docshell");
- SetIsActive(false);
- mIsPrerendered = true;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetIsPrerendered(bool* aIsPrerendered)
- {
- *aIsPrerendered = mIsPrerendered;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetIsAppTab(bool aIsAppTab)
- {
- mIsAppTab = aIsAppTab;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetIsAppTab(bool* aIsAppTab)
- {
- *aIsAppTab = mIsAppTab;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetSandboxFlags(uint32_t aSandboxFlags)
- {
- mSandboxFlags = aSandboxFlags;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetSandboxFlags(uint32_t* aSandboxFlags)
- {
- *aSandboxFlags = mSandboxFlags;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetOnePermittedSandboxedNavigator(nsIDocShell* aSandboxedNavigator)
- {
- if (mOnePermittedSandboxedNavigator) {
- NS_ERROR("One Permitted Sandboxed Navigator should only be set once.");
- return NS_OK;
- }
- mOnePermittedSandboxedNavigator = do_GetWeakReference(aSandboxedNavigator);
- NS_ASSERTION(mOnePermittedSandboxedNavigator,
- "One Permitted Sandboxed Navigator must support weak references.");
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetOnePermittedSandboxedNavigator(nsIDocShell** aSandboxedNavigator)
- {
- NS_ENSURE_ARG_POINTER(aSandboxedNavigator);
- nsCOMPtr<nsIDocShell> permittedNavigator =
- do_QueryReferent(mOnePermittedSandboxedNavigator);
- permittedNavigator.forget(aSandboxedNavigator);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetDefaultLoadFlags(uint32_t aDefaultLoadFlags)
- {
- mDefaultLoadFlags = aDefaultLoadFlags;
- // Tell the load group to set these flags all requests in the group
- if (mLoadGroup) {
- mLoadGroup->SetDefaultLoadFlags(aDefaultLoadFlags);
- } else {
- NS_WARNING("nsDocShell::SetDefaultLoadFlags has no loadGroup to propagate the flags to");
- }
- // Recursively tell all of our children. We *do not* skip
- // <iframe mozbrowser> children - if someone sticks custom flags in this
- // docShell then they too get the same flags.
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- nsCOMPtr<nsIDocShell> docshell = do_QueryObject(iter.GetNext());
- if (!docshell) {
- continue;
- }
- docshell->SetDefaultLoadFlags(aDefaultLoadFlags);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetDefaultLoadFlags(uint32_t* aDefaultLoadFlags)
- {
- *aDefaultLoadFlags = mDefaultLoadFlags;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetMixedContentChannel(nsIChannel* aMixedContentChannel)
- {
- #ifdef DEBUG
- // if the channel is non-null
- if (aMixedContentChannel) {
- // Get the root docshell.
- nsCOMPtr<nsIDocShellTreeItem> root;
- GetSameTypeRootTreeItem(getter_AddRefs(root));
- NS_WARNING_ASSERTION(root.get() == static_cast<nsIDocShellTreeItem*>(this),
- "Setting mMixedContentChannel on a docshell that is "
- "not the root docshell");
- }
- #endif
- mMixedContentChannel = aMixedContentChannel;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetFailedChannel(nsIChannel** aFailedChannel)
- {
- NS_ENSURE_ARG_POINTER(aFailedChannel);
- nsIDocument* doc = GetDocument();
- if (!doc) {
- *aFailedChannel = nullptr;
- return NS_OK;
- }
- NS_IF_ADDREF(*aFailedChannel = doc->GetFailedChannel());
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetMixedContentChannel(nsIChannel** aMixedContentChannel)
- {
- NS_ENSURE_ARG_POINTER(aMixedContentChannel);
- NS_IF_ADDREF(*aMixedContentChannel = mMixedContentChannel);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetAllowMixedContentAndConnectionData(bool* aRootHasSecureConnection,
- bool* aAllowMixedContent,
- bool* aIsRootDocShell)
- {
- *aRootHasSecureConnection = true;
- *aAllowMixedContent = false;
- *aIsRootDocShell = false;
- nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
- GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
- NS_ASSERTION(sameTypeRoot,
- "No document shell root tree item from document shell tree item!");
- *aIsRootDocShell =
- sameTypeRoot.get() == static_cast<nsIDocShellTreeItem*>(this);
- // now get the document from sameTypeRoot
- nsCOMPtr<nsIDocument> rootDoc = sameTypeRoot->GetDocument();
- if (rootDoc) {
- nsCOMPtr<nsIPrincipal> rootPrincipal = rootDoc->NodePrincipal();
- // For things with system principal (e.g. scratchpad) there is no uri
- // aRootHasSecureConnection should be false.
- nsCOMPtr<nsIURI> rootUri;
- if (nsContentUtils::IsSystemPrincipal(rootPrincipal) ||
- NS_FAILED(rootPrincipal->GetURI(getter_AddRefs(rootUri))) || !rootUri ||
- NS_FAILED(rootUri->SchemeIs("https", aRootHasSecureConnection))) {
- *aRootHasSecureConnection = false;
- }
- // Check the root doc's channel against the root docShell's
- // mMixedContentChannel to see if they are the same. If they are the same,
- // the user has overriden the block.
- nsCOMPtr<nsIDocShell> rootDocShell = do_QueryInterface(sameTypeRoot);
- nsCOMPtr<nsIChannel> mixedChannel;
- rootDocShell->GetMixedContentChannel(getter_AddRefs(mixedChannel));
- *aAllowMixedContent =
- mixedChannel && (mixedChannel == rootDoc->GetChannel());
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetVisibility(bool aVisibility)
- {
- // Show()/Hide() may change mContentViewer.
- nsCOMPtr<nsIContentViewer> cv = mContentViewer;
- if (!cv) {
- return NS_OK;
- }
- if (aVisibility) {
- cv->Show();
- } else {
- cv->Hide();
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetEnabled(bool* aEnabled)
- {
- NS_ENSURE_ARG_POINTER(aEnabled);
- *aEnabled = true;
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- NS_IMETHODIMP
- nsDocShell::SetEnabled(bool aEnabled)
- {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
- NS_IMETHODIMP
- nsDocShell::SetFocus()
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetMainWidget(nsIWidget** aMainWidget)
- {
- // We don't create our own widget, so simply return the parent one.
- return GetParentWidget(aMainWidget);
- }
- NS_IMETHODIMP
- nsDocShell::GetTitle(char16_t** aTitle)
- {
- NS_ENSURE_ARG_POINTER(aTitle);
- *aTitle = ToNewUnicode(mTitle);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetTitle(const char16_t* aTitle)
- {
- // Store local title
- mTitle = aTitle;
- nsCOMPtr<nsIDocShellTreeItem> parent;
- GetSameTypeParent(getter_AddRefs(parent));
- // When title is set on the top object it should then be passed to the
- // tree owner.
- if (!parent) {
- nsCOMPtr<nsIBaseWindow> treeOwnerAsWin(do_QueryInterface(mTreeOwner));
- if (treeOwnerAsWin) {
- treeOwnerAsWin->SetTitle(aTitle);
- }
- }
- AssertOriginAttributesMatchPrivateBrowsing();
- if (mCurrentURI && mLoadType != LOAD_ERROR_PAGE && mUseGlobalHistory &&
- !UsePrivateBrowsing()) {
- nsCOMPtr<IHistory> history = services::GetHistoryService();
- if (history) {
- history->SetURITitle(mCurrentURI, mTitle);
- } else if (mGlobalHistory) {
- mGlobalHistory->SetPageTitle(mCurrentURI, nsString(mTitle));
- }
- }
- // Update SessionHistory with the document's title.
- if (mOSHE && mLoadType != LOAD_BYPASS_HISTORY &&
- mLoadType != LOAD_ERROR_PAGE) {
- mOSHE->SetTitle(mTitle);
- }
- return NS_OK;
- }
- nsresult
- nsDocShell::GetCurScrollPos(int32_t aScrollOrientation, int32_t* aCurPos)
- {
- NS_ENSURE_ARG_POINTER(aCurPos);
- nsIScrollableFrame* sf = GetRootScrollFrame();
- if (!sf) {
- return NS_ERROR_FAILURE;
- }
- nsPoint pt = sf->GetScrollPosition();
- switch (aScrollOrientation) {
- case ScrollOrientation_X:
- *aCurPos = pt.x;
- return NS_OK;
- case ScrollOrientation_Y:
- *aCurPos = pt.y;
- return NS_OK;
- default:
- NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
- }
- }
- nsresult
- nsDocShell::SetCurScrollPosEx(int32_t aCurHorizontalPos,
- int32_t aCurVerticalPos)
- {
- nsIScrollableFrame* sf = GetRootScrollFrame();
- NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
- sf->ScrollTo(nsPoint(aCurHorizontalPos, aCurVerticalPos),
- nsIScrollableFrame::INSTANT);
- return NS_OK;
- }
- //*****************************************************************************
- // nsDocShell::nsIScrollable
- //*****************************************************************************
- NS_IMETHODIMP
- nsDocShell::GetDefaultScrollbarPreferences(int32_t aScrollOrientation,
- int32_t* aScrollbarPref)
- {
- NS_ENSURE_ARG_POINTER(aScrollbarPref);
- switch (aScrollOrientation) {
- case ScrollOrientation_X:
- *aScrollbarPref = mDefaultScrollbarPref.x;
- return NS_OK;
- case ScrollOrientation_Y:
- *aScrollbarPref = mDefaultScrollbarPref.y;
- return NS_OK;
- default:
- NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
- }
- return NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsDocShell::SetDefaultScrollbarPreferences(int32_t aScrollOrientation,
- int32_t aScrollbarPref)
- {
- switch (aScrollOrientation) {
- case ScrollOrientation_X:
- mDefaultScrollbarPref.x = aScrollbarPref;
- return NS_OK;
- case ScrollOrientation_Y:
- mDefaultScrollbarPref.y = aScrollbarPref;
- return NS_OK;
- default:
- NS_ENSURE_TRUE(false, NS_ERROR_INVALID_ARG);
- }
- return NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsDocShell::GetScrollbarVisibility(bool* aVerticalVisible,
- bool* aHorizontalVisible)
- {
- nsIScrollableFrame* sf = GetRootScrollFrame();
- NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
- uint32_t scrollbarVisibility = sf->GetScrollbarVisibility();
- if (aVerticalVisible) {
- *aVerticalVisible =
- (scrollbarVisibility & nsIScrollableFrame::VERTICAL) != 0;
- }
- if (aHorizontalVisible) {
- *aHorizontalVisible =
- (scrollbarVisibility & nsIScrollableFrame::HORIZONTAL) != 0;
- }
- return NS_OK;
- }
- //*****************************************************************************
- // nsDocShell::nsITextScroll
- //*****************************************************************************
- NS_IMETHODIMP
- nsDocShell::ScrollByLines(int32_t aNumLines)
- {
- nsIScrollableFrame* sf = GetRootScrollFrame();
- NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
- sf->ScrollBy(nsIntPoint(0, aNumLines), nsIScrollableFrame::LINES,
- nsIScrollableFrame::SMOOTH);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::ScrollByPages(int32_t aNumPages)
- {
- nsIScrollableFrame* sf = GetRootScrollFrame();
- NS_ENSURE_TRUE(sf, NS_ERROR_FAILURE);
- sf->ScrollBy(nsIntPoint(0, aNumPages), nsIScrollableFrame::PAGES,
- nsIScrollableFrame::SMOOTH);
- return NS_OK;
- }
- //*****************************************************************************
- // nsDocShell::nsIRefreshURI
- //*****************************************************************************
- NS_IMETHODIMP
- nsDocShell::RefreshURI(nsIURI* aURI,
- int32_t aDelay, bool aRepeat,
- bool aMetaRefresh,
- nsIPrincipal* aPrincipal)
- {
- NS_ENSURE_ARG(aURI);
- /* Check if Meta refresh/redirects are permitted. Some
- * embedded applications may not want to do this.
- * Must do this before sending out NOTIFY_REFRESH events
- * because listeners may have side effects (e.g. displaying a
- * button to manually trigger the refresh later).
- */
- bool allowRedirects = true;
- GetAllowMetaRedirects(&allowRedirects);
- if (!allowRedirects) {
- return NS_OK;
- }
- // If any web progress listeners are listening for NOTIFY_REFRESH events,
- // give them a chance to block this refresh.
- bool sameURI;
- nsresult rv = aURI->Equals(mCurrentURI, &sameURI);
- if (NS_FAILED(rv)) {
- sameURI = false;
- }
- if (!RefreshAttempted(this, aURI, aDelay, sameURI)) {
- return NS_OK;
- }
- nsRefreshTimer* refreshTimer = new nsRefreshTimer();
- uint32_t busyFlags = 0;
- GetBusyFlags(&busyFlags);
- nsCOMPtr<nsISupports> dataRef = refreshTimer; // Get the ref count to 1
- refreshTimer->mDocShell = this;
- refreshTimer->mPrincipal = aPrincipal;
- refreshTimer->mURI = aURI;
- refreshTimer->mDelay = aDelay;
- refreshTimer->mRepeat = aRepeat;
- refreshTimer->mMetaRefresh = aMetaRefresh;
- if (!mRefreshURIList) {
- mRefreshURIList = nsArray::Create();
- }
- if (busyFlags & BUSY_FLAGS_BUSY || (!mIsActive && mDisableMetaRefreshWhenInactive)) {
- // We don't want to create the timer right now. Instead queue up the request
- // and trigger the timer in EndPageLoad() or whenever we become active.
- mRefreshURIList->AppendElement(refreshTimer, /*weak =*/ false);
- } else {
- // There is no page loading going on right now. Create the
- // timer and fire it right away.
- nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
- NS_ENSURE_TRUE(timer, NS_ERROR_FAILURE);
- mRefreshURIList->AppendElement(timer, /*weak =*/ false); // owning timer ref
- timer->InitWithCallback(refreshTimer, aDelay, nsITimer::TYPE_ONE_SHOT);
- }
- return NS_OK;
- }
- nsresult
- nsDocShell::ForceRefreshURIFromTimer(nsIURI* aURI,
- int32_t aDelay,
- bool aMetaRefresh,
- nsITimer* aTimer,
- nsIPrincipal* aPrincipal)
- {
- NS_PRECONDITION(aTimer, "Must have a timer here");
- // Remove aTimer from mRefreshURIList if needed
- if (mRefreshURIList) {
- uint32_t n = 0;
- mRefreshURIList->GetLength(&n);
- for (uint32_t i = 0; i < n; ++i) {
- nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
- if (timer == aTimer) {
- mRefreshURIList->RemoveElementAt(i);
- break;
- }
- }
- }
- return ForceRefreshURI(aURI, aDelay, aMetaRefresh, aPrincipal);
- }
- NS_IMETHODIMP
- nsDocShell::ForceRefreshURI(nsIURI* aURI, int32_t aDelay, bool aMetaRefresh, nsIPrincipal* aPrincipal)
- {
- NS_ENSURE_ARG(aURI);
- nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
- CreateLoadInfo(getter_AddRefs(loadInfo));
- NS_ENSURE_TRUE(loadInfo, NS_ERROR_OUT_OF_MEMORY);
- /* We do need to pass in a referrer, but we don't want it to
- * be sent to the server.
- */
- loadInfo->SetSendReferrer(false);
- /* for most refreshes the current URI is an appropriate
- * internal referrer
- */
- loadInfo->SetReferrer(mCurrentURI);
- // Set the triggering pricipal to aPrincipal if available, or current
- // document's principal otherwise.
- nsCOMPtr<nsIPrincipal> principal = aPrincipal;
- if (!principal) {
- nsCOMPtr<nsIDocument> doc = GetDocument();
- if (!doc) {
- return NS_ERROR_FAILURE;
- }
- principal = doc->NodePrincipal();
- }
- loadInfo->SetTriggeringPrincipal(principal);
- loadInfo->SetPrincipalIsExplicit(true);
- /* Check if this META refresh causes a redirection
- * to another site.
- */
- bool equalUri = false;
- nsresult rv = aURI->Equals(mCurrentURI, &equalUri);
- if (NS_SUCCEEDED(rv) && (!equalUri) && aMetaRefresh &&
- aDelay <= REFRESH_REDIRECT_TIMER) {
- /* It is a META refresh based redirection within the threshold time
- * we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
- * Pass a REPLACE flag to LoadURI().
- */
- loadInfo->SetLoadType(nsIDocShellLoadInfo::loadNormalReplace);
- /* for redirects we mimic HTTP, which passes the
- * original referrer
- */
- nsCOMPtr<nsIURI> internalReferrer;
- GetReferringURI(getter_AddRefs(internalReferrer));
- if (internalReferrer) {
- loadInfo->SetReferrer(internalReferrer);
- }
- } else {
- loadInfo->SetLoadType(nsIDocShellLoadInfo::loadRefresh);
- }
- /*
- * LoadURI(...) will cancel all refresh timers... This causes the
- * Timer and its refreshData instance to be released...
- */
- LoadURI(aURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL, true);
- return NS_OK;
- }
- nsresult
- nsDocShell::SetupRefreshURIFromHeader(nsIURI* aBaseURI,
- nsIPrincipal* aPrincipal,
- const nsACString& aHeader)
- {
- // Refresh headers are parsed with the following format in mind
- // <META HTTP-EQUIV=REFRESH CONTENT="5; URL=http://uri">
- // By the time we are here, the following is true:
- // header = "REFRESH"
- // content = "5; URL=http://uri" // note the URL attribute is
- // optional, if it is absent, the currently loaded url is used.
- // Also note that the seconds and URL separator can be either
- // a ';' or a ','. The ',' separator should be illegal but CNN
- // is using it.
- //
- // We need to handle the following strings, where
- // - X is a set of digits
- // - URI is either a relative or absolute URI
- //
- // Note that URI should start with "url=" but we allow omission
- //
- // "" || ";" || ","
- // empty string. use the currently loaded URI
- // and refresh immediately.
- // "X" || "X;" || "X,"
- // Refresh the currently loaded URI in X seconds.
- // "X; URI" || "X, URI"
- // Refresh using URI as the destination in X seconds.
- // "URI" || "; URI" || ", URI"
- // Refresh immediately using URI as the destination.
- //
- // Currently, anything immediately following the URI, if
- // separated by any char in the set "'\"\t\r\n " will be
- // ignored. So "10; url=go.html ; foo=bar" will work,
- // and so will "10; url='go.html'; foo=bar". However,
- // "10; url=go.html; foo=bar" will result in the uri
- // "go.html;" since ';' and ',' are valid uri characters.
- //
- // Note that we need to remove any tokens wrapping the URI.
- // These tokens currently include spaces, double and single
- // quotes.
- // when done, seconds is 0 or the given number of seconds
- // uriAttrib is empty or the URI specified
- MOZ_ASSERT(aPrincipal);
- nsAutoCString uriAttrib;
- int32_t seconds = 0;
- bool specifiesSeconds = false;
- nsACString::const_iterator iter, tokenStart, doneIterating;
- aHeader.BeginReading(iter);
- aHeader.EndReading(doneIterating);
- // skip leading whitespace
- while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
- ++iter;
- }
- tokenStart = iter;
- // skip leading + and -
- if (iter != doneIterating && (*iter == '-' || *iter == '+')) {
- ++iter;
- }
- // parse number
- while (iter != doneIterating && (*iter >= '0' && *iter <= '9')) {
- seconds = seconds * 10 + (*iter - '0');
- specifiesSeconds = true;
- ++iter;
- }
- if (iter != doneIterating) {
- // if we started with a '-', number is negative
- if (*tokenStart == '-') {
- seconds = -seconds;
- }
- // skip to next ';' or ','
- nsACString::const_iterator iterAfterDigit = iter;
- while (iter != doneIterating && !(*iter == ';' || *iter == ',')) {
- if (specifiesSeconds) {
- // Non-whitespace characters here mean that the string is
- // malformed but tolerate sites that specify a decimal point,
- // even though meta refresh only works on whole seconds.
- if (iter == iterAfterDigit &&
- !nsCRT::IsAsciiSpace(*iter) && *iter != '.') {
- // The characters between the seconds and the next
- // section are just garbage!
- // e.g. content="2a0z+,URL=http://www.mozilla.org/"
- // Just ignore this redirect.
- return NS_ERROR_FAILURE;
- } else if (nsCRT::IsAsciiSpace(*iter)) {
- // We've had at least one whitespace so tolerate the mistake
- // and drop through.
- // e.g. content="10 foo"
- ++iter;
- break;
- }
- }
- ++iter;
- }
- // skip any remaining whitespace
- while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
- ++iter;
- }
- // skip ';' or ','
- if (iter != doneIterating && (*iter == ';' || *iter == ',')) {
- ++iter;
- }
- // skip whitespace
- while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
- ++iter;
- }
- }
- // possible start of URI
- tokenStart = iter;
- // skip "url = " to real start of URI
- if (iter != doneIterating && (*iter == 'u' || *iter == 'U')) {
- ++iter;
- if (iter != doneIterating && (*iter == 'r' || *iter == 'R')) {
- ++iter;
- if (iter != doneIterating && (*iter == 'l' || *iter == 'L')) {
- ++iter;
- // skip whitespace
- while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
- ++iter;
- }
- if (iter != doneIterating && *iter == '=') {
- ++iter;
- // skip whitespace
- while (iter != doneIterating && nsCRT::IsAsciiSpace(*iter)) {
- ++iter;
- }
- // found real start of URI
- tokenStart = iter;
- }
- }
- }
- }
- // skip a leading '"' or '\''.
- bool isQuotedURI = false;
- if (tokenStart != doneIterating &&
- (*tokenStart == '"' || *tokenStart == '\'')) {
- isQuotedURI = true;
- ++tokenStart;
- }
- // set iter to start of URI
- iter = tokenStart;
- // tokenStart here points to the beginning of URI
- // grab the rest of the URI
- while (iter != doneIterating) {
- if (isQuotedURI && (*iter == '"' || *iter == '\'')) {
- break;
- }
- ++iter;
- }
- // move iter one back if the last character is a '"' or '\''
- if (iter != tokenStart && isQuotedURI) {
- --iter;
- if (!(*iter == '"' || *iter == '\'')) {
- ++iter;
- }
- }
- // URI is whatever's contained from tokenStart to iter.
- // note: if tokenStart == doneIterating, so is iter.
- nsresult rv = NS_OK;
- nsCOMPtr<nsIURI> uri;
- bool specifiesURI = false;
- if (tokenStart == iter) {
- uri = aBaseURI;
- } else {
- uriAttrib = Substring(tokenStart, iter);
- // NS_NewURI takes care of any whitespace surrounding the URL
- rv = NS_NewURI(getter_AddRefs(uri), uriAttrib, nullptr, aBaseURI);
- specifiesURI = true;
- }
- // No URI or seconds were specified
- if (!specifiesSeconds && !specifiesURI) {
- // Do nothing because the alternative is to spin around in a refresh
- // loop forever!
- return NS_ERROR_FAILURE;
- }
- if (NS_SUCCEEDED(rv)) {
- nsCOMPtr<nsIScriptSecurityManager> securityManager(
- do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv));
- if (NS_SUCCEEDED(rv)) {
- rv = securityManager->CheckLoadURIWithPrincipal(
- aPrincipal, uri,
- nsIScriptSecurityManager::LOAD_IS_AUTOMATIC_DOCUMENT_REPLACEMENT);
- if (NS_SUCCEEDED(rv)) {
- bool isjs = true;
- rv = NS_URIChainHasFlags(
- uri, nsIProtocolHandler::URI_OPENING_EXECUTES_SCRIPT, &isjs);
- NS_ENSURE_SUCCESS(rv, rv);
- if (isjs) {
- return NS_ERROR_FAILURE;
- }
- }
- if (NS_SUCCEEDED(rv)) {
- // Since we can't travel back in time yet, just pretend
- // negative numbers do nothing at all.
- if (seconds < 0) {
- return NS_ERROR_FAILURE;
- }
- rv = RefreshURI(uri, seconds * 1000, false, true, aPrincipal);
- }
- }
- }
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::SetupRefreshURI(nsIChannel* aChannel)
- {
- nsresult rv;
- nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel, &rv));
- if (NS_SUCCEEDED(rv)) {
- nsAutoCString refreshHeader;
- rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("refresh"),
- refreshHeader);
- if (!refreshHeader.IsEmpty()) {
- nsCOMPtr<nsIScriptSecurityManager> secMan =
- do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIPrincipal> principal;
- rv = secMan->GetChannelResultPrincipal(aChannel,
- getter_AddRefs(principal));
- NS_ENSURE_SUCCESS(rv, rv);
- SetupReferrerFromChannel(aChannel);
- rv = SetupRefreshURIFromHeader(mCurrentURI, principal, refreshHeader);
- if (NS_SUCCEEDED(rv)) {
- return NS_REFRESHURI_HEADER_FOUND;
- }
- }
- }
- return rv;
- }
- static void
- DoCancelRefreshURITimers(nsIMutableArray* aTimerList)
- {
- if (!aTimerList) {
- return;
- }
- uint32_t n = 0;
- aTimerList->GetLength(&n);
- while (n) {
- nsCOMPtr<nsITimer> timer(do_QueryElementAt(aTimerList, --n));
- aTimerList->RemoveElementAt(n); // bye bye owning timer ref
- if (timer) {
- timer->Cancel();
- }
- }
- }
- NS_IMETHODIMP
- nsDocShell::CancelRefreshURITimers()
- {
- DoCancelRefreshURITimers(mRefreshURIList);
- DoCancelRefreshURITimers(mSavedRefreshURIList);
- mRefreshURIList = nullptr;
- mSavedRefreshURIList = nullptr;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetRefreshPending(bool* aResult)
- {
- if (!mRefreshURIList) {
- *aResult = false;
- return NS_OK;
- }
- uint32_t count;
- nsresult rv = mRefreshURIList->GetLength(&count);
- if (NS_SUCCEEDED(rv)) {
- *aResult = (count != 0);
- }
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::SuspendRefreshURIs()
- {
- if (mRefreshURIList) {
- uint32_t n = 0;
- mRefreshURIList->GetLength(&n);
- for (uint32_t i = 0; i < n; ++i) {
- nsCOMPtr<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
- if (!timer) {
- continue; // this must be a nsRefreshURI already
- }
- // Replace this timer object with a nsRefreshTimer object.
- nsCOMPtr<nsITimerCallback> callback;
- timer->GetCallback(getter_AddRefs(callback));
- timer->Cancel();
- nsCOMPtr<nsITimerCallback> rt = do_QueryInterface(callback);
- NS_ASSERTION(rt,
- "RefreshURIList timer callbacks should only be RefreshTimer objects");
- mRefreshURIList->ReplaceElementAt(rt, i, /*weak =*/ false);
- }
- }
- // Suspend refresh URIs for our child shells as well.
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
- if (shell) {
- shell->SuspendRefreshURIs();
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::ResumeRefreshURIs()
- {
- RefreshURIFromQueue();
- // Resume refresh URIs for our child shells as well.
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- nsCOMPtr<nsIDocShell> shell = do_QueryObject(iter.GetNext());
- if (shell) {
- shell->ResumeRefreshURIs();
- }
- }
- return NS_OK;
- }
- nsresult
- nsDocShell::RefreshURIFromQueue()
- {
- if (!mRefreshURIList) {
- return NS_OK;
- }
- uint32_t n = 0;
- mRefreshURIList->GetLength(&n);
- while (n) {
- nsCOMPtr<nsITimerCallback> refreshInfo =
- do_QueryElementAt(mRefreshURIList, --n);
- if (refreshInfo) {
- // This is the nsRefreshTimer object, waiting to be
- // setup in a timer object and fired.
- // Create the timer and trigger it.
- uint32_t delay =
- static_cast<nsRefreshTimer*>(
- static_cast<nsITimerCallback*>(refreshInfo))->GetDelay();
- nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
- if (timer) {
- // Replace the nsRefreshTimer element in the queue with
- // its corresponding timer object, so that in case another
- // load comes through before the timer can go off, the timer will
- // get cancelled in CancelRefreshURITimer()
- mRefreshURIList->ReplaceElementAt(timer, n, /*weak =*/ false);
- timer->InitWithCallback(refreshInfo, delay, nsITimer::TYPE_ONE_SHOT);
- }
- }
- }
- return NS_OK;
- }
- //*****************************************************************************
- // nsDocShell::nsIContentViewerContainer
- //*****************************************************************************
- NS_IMETHODIMP
- nsDocShell::Embed(nsIContentViewer* aContentViewer,
- const char* aCommand, nsISupports* aExtraInfo)
- {
- // Save the LayoutHistoryState of the previous document, before
- // setting up new document
- PersistLayoutHistoryState();
- nsresult rv = SetupNewViewer(aContentViewer);
- NS_ENSURE_SUCCESS(rv, rv);
- // If we are loading a wyciwyg url from history, change the base URI for
- // the document to the original http url that created the document.write().
- // This makes sure that all relative urls in a document.written page loaded
- // via history work properly.
- if (mCurrentURI &&
- (mLoadType & LOAD_CMD_HISTORY ||
- mLoadType == LOAD_RELOAD_NORMAL ||
- mLoadType == LOAD_RELOAD_CHARSET_CHANGE)) {
- bool isWyciwyg = false;
- // Check if the url is wyciwyg
- rv = mCurrentURI->SchemeIs("wyciwyg", &isWyciwyg);
- if (isWyciwyg && NS_SUCCEEDED(rv)) {
- SetBaseUrlForWyciwyg(aContentViewer);
- }
- }
- // XXX What if SetupNewViewer fails?
- if (mLSHE) {
- // Restore the editing state, if it's stored in session history.
- if (mLSHE->HasDetachedEditor()) {
- ReattachEditorToWindow(mLSHE);
- }
- // Set history.state
- SetDocCurrentStateObj(mLSHE);
- SetHistoryEntry(&mOSHE, mLSHE);
- }
- bool updateHistory = true;
- // Determine if this type of load should update history
- switch (mLoadType) {
- case LOAD_NORMAL_REPLACE:
- case LOAD_STOP_CONTENT_AND_REPLACE:
- case LOAD_RELOAD_BYPASS_CACHE:
- case LOAD_RELOAD_BYPASS_PROXY:
- case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
- case LOAD_REPLACE_BYPASS_CACHE:
- updateHistory = false;
- break;
- default:
- break;
- }
- if (!updateHistory) {
- SetLayoutHistoryState(nullptr);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetIsPrinting(bool aIsPrinting)
- {
- mIsPrintingOrPP = aIsPrinting;
- return NS_OK;
- }
- //*****************************************************************************
- // nsDocShell::nsIWebProgressListener
- //*****************************************************************************
- NS_IMETHODIMP
- nsDocShell::OnProgressChange(nsIWebProgress* aProgress,
- nsIRequest* aRequest,
- int32_t aCurSelfProgress,
- int32_t aMaxSelfProgress,
- int32_t aCurTotalProgress,
- int32_t aMaxTotalProgress)
- {
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::OnStateChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
- uint32_t aStateFlags, nsresult aStatus)
- {
- if ((~aStateFlags & (STATE_START | STATE_IS_NETWORK)) == 0) {
- // Save timing statistics.
- nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
- nsCOMPtr<nsIURI> uri;
- channel->GetURI(getter_AddRefs(uri));
- nsAutoCString aURI;
- uri->GetAsciiSpec(aURI);
- nsCOMPtr<nsIWyciwygChannel> wcwgChannel(do_QueryInterface(aRequest));
- nsCOMPtr<nsIWebProgress> webProgress =
- do_QueryInterface(GetAsSupports(this));
- // We don't update navigation timing for wyciwyg channels
- if (this == aProgress && !wcwgChannel) {
- MaybeInitTiming();
- mTiming->NotifyFetchStart(uri,
- ConvertLoadTypeToNavigationType(mLoadType));
- }
- // Was the wyciwyg document loaded on this docshell?
- if (wcwgChannel && !mLSHE && (mItemType == typeContent) &&
- aProgress == webProgress.get()) {
- bool equalUri = true;
- // Store the wyciwyg url in session history, only if it is
- // being loaded fresh for the first time. We don't want
- // multiple entries for successive loads
- if (mCurrentURI &&
- NS_SUCCEEDED(uri->Equals(mCurrentURI, &equalUri)) &&
- !equalUri) {
- nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
- GetSameTypeParent(getter_AddRefs(parentAsItem));
- nsCOMPtr<nsIDocShell> parentDS(do_QueryInterface(parentAsItem));
- bool inOnLoadHandler = false;
- if (parentDS) {
- parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
- }
- if (inOnLoadHandler) {
- // We're handling parent's load event listener, which causes
- // document.write in a subdocument.
- // Need to clear the session history for all child
- // docshells so that we can handle them like they would
- // all be added dynamically.
- nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentAsItem);
- if (parent) {
- bool oshe = false;
- nsCOMPtr<nsISHEntry> entry;
- parent->GetCurrentSHEntry(getter_AddRefs(entry), &oshe);
- static_cast<nsDocShell*>(parent.get())->ClearFrameHistory(entry);
- }
- }
- // This is a document.write(). Get the made-up url
- // from the channel and store it in session history.
- // Pass false for aCloneChildren, since we're creating
- // a new DOM here.
- AddToSessionHistory(uri, wcwgChannel, nullptr, nullptr, false,
- getter_AddRefs(mLSHE));
- SetCurrentURI(uri, aRequest, true, 0);
- // Save history state of the previous page
- PersistLayoutHistoryState();
- // We'll never get an Embed() for this load, so just go ahead
- // and SetHistoryEntry now.
- SetHistoryEntry(&mOSHE, mLSHE);
- }
- }
- // Page has begun to load
- mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_BEFORE_PAGE_LOAD;
- if ((aStateFlags & STATE_RESTORING) == 0) {
- // Show the progress cursor if the pref is set
- if (nsContentUtils::UseActivityCursor()) {
- nsCOMPtr<nsIWidget> mainWidget;
- GetMainWidget(getter_AddRefs(mainWidget));
- if (mainWidget) {
- mainWidget->SetCursor(eCursor_spinning);
- }
- }
- }
- } else if ((~aStateFlags & (STATE_TRANSFERRING | STATE_IS_DOCUMENT)) == 0) {
- // Page is loading
- mBusyFlags = BUSY_FLAGS_BUSY | BUSY_FLAGS_PAGE_LOADING;
- } else if ((aStateFlags & STATE_STOP) && (aStateFlags & STATE_IS_NETWORK)) {
- // Page has finished loading
- mBusyFlags = BUSY_FLAGS_NONE;
- // Hide the progress cursor if the pref is set
- if (nsContentUtils::UseActivityCursor()) {
- nsCOMPtr<nsIWidget> mainWidget;
- GetMainWidget(getter_AddRefs(mainWidget));
- if (mainWidget) {
- mainWidget->SetCursor(eCursor_standard);
- }
- }
- }
- if ((~aStateFlags & (STATE_IS_DOCUMENT | STATE_STOP)) == 0) {
- nsCOMPtr<nsIWebProgress> webProgress =
- do_QueryInterface(GetAsSupports(this));
- // Is the document stop notification for this document?
- if (aProgress == webProgress.get()) {
- nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
- EndPageLoad(aProgress, channel, aStatus);
- }
- }
- // note that redirect state changes will go through here as well, but it
- // is better to handle those in OnRedirectStateChange where more
- // information is available.
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::OnLocationChange(nsIWebProgress* aProgress, nsIRequest* aRequest,
- nsIURI* aURI, uint32_t aFlags)
- {
- NS_NOTREACHED("notification excluded in AddProgressListener(...)");
- return NS_OK;
- }
- void
- nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
- nsIChannel* aNewChannel,
- uint32_t aRedirectFlags,
- uint32_t aStateFlags)
- {
- NS_ASSERTION(aStateFlags & STATE_REDIRECTING,
- "Calling OnRedirectStateChange when there is no redirect");
- // If mixed content is allowed for the old channel, we forward
- // the permission to the new channel if it has the same origin
- // as the old one.
- if (mMixedContentChannel && mMixedContentChannel == aOldChannel) {
- nsresult rv = nsContentUtils::CheckSameOrigin(mMixedContentChannel, aNewChannel);
- if (NS_SUCCEEDED(rv)) {
- SetMixedContentChannel(aNewChannel); // Same origin: forward permission.
- } else {
- SetMixedContentChannel(nullptr); // Different origin: clear mMixedContentChannel.
- }
- }
- if (!(aStateFlags & STATE_IS_DOCUMENT)) {
- return; // not a toplevel document
- }
- nsCOMPtr<nsIURI> oldURI, newURI;
- aOldChannel->GetURI(getter_AddRefs(oldURI));
- aNewChannel->GetURI(getter_AddRefs(newURI));
- if (!oldURI || !newURI) {
- return;
- }
- // Below a URI visit is saved (see AddURIVisit method doc).
- // The visit chain looks something like:
- // ...
- // Site N - 1
- // => Site N
- // (redirect to =>) Site N + 1 (we are here!)
- // Get N - 1 and transition type
- nsCOMPtr<nsIURI> previousURI;
- uint32_t previousFlags = 0;
- ExtractLastVisit(aOldChannel, getter_AddRefs(previousURI), &previousFlags);
- if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL ||
- ChannelIsPost(aOldChannel)) {
- // 1. Internal redirects are ignored because they are specific to the
- // channel implementation.
- // 2. POSTs are not saved by global history.
- //
- // Regardless, we need to propagate the previous visit to the new
- // channel.
- SaveLastVisit(aNewChannel, previousURI, previousFlags);
- } else {
- nsCOMPtr<nsIURI> referrer;
- // Treat referrer as null if there is an error getting it.
- (void)NS_GetReferrerFromChannel(aOldChannel, getter_AddRefs(referrer));
- // Get the HTTP response code, if available.
- uint32_t responseStatus = 0;
- nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aOldChannel);
- if (httpChannel) {
- (void)httpChannel->GetResponseStatus(&responseStatus);
- }
- // Add visit N -1 => N
- AddURIVisit(oldURI, referrer, previousURI, previousFlags, responseStatus);
- // Since N + 1 could be the final destination, we will not save N => N + 1
- // here. OnNewURI will do that, so we will cache it.
- SaveLastVisit(aNewChannel, oldURI, aRedirectFlags);
- }
- // check if the new load should go through the application cache.
- nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
- do_QueryInterface(aNewChannel);
- if (appCacheChannel) {
- if (GeckoProcessType_Default != XRE_GetProcessType()) {
- // Permission will be checked in the parent process.
- appCacheChannel->SetChooseApplicationCache(true);
- } else {
- nsCOMPtr<nsIScriptSecurityManager> secMan =
- do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
- if (secMan) {
- nsCOMPtr<nsIPrincipal> principal;
- secMan->GetDocShellCodebasePrincipal(newURI, this,
- getter_AddRefs(principal));
- appCacheChannel->SetChooseApplicationCache(
- NS_ShouldCheckAppCache(principal, UsePrivateBrowsing()));
- }
- }
- }
- if (!(aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL) &&
- mLoadType & (LOAD_CMD_RELOAD | LOAD_CMD_HISTORY)) {
- mLoadType = LOAD_NORMAL_REPLACE;
- SetHistoryEntry(&mLSHE, nullptr);
- }
- }
- NS_IMETHODIMP
- nsDocShell::OnStatusChange(nsIWebProgress* aWebProgress,
- nsIRequest* aRequest,
- nsresult aStatus, const char16_t* aMessage)
- {
- NS_NOTREACHED("notification excluded in AddProgressListener(...)");
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::OnSecurityChange(nsIWebProgress* aWebProgress,
- nsIRequest* aRequest, uint32_t aState)
- {
- NS_NOTREACHED("notification excluded in AddProgressListener(...)");
- return NS_OK;
- }
- nsresult
- nsDocShell::EndPageLoad(nsIWebProgress* aProgress,
- nsIChannel* aChannel, nsresult aStatus)
- {
- if (!aChannel) {
- return NS_ERROR_NULL_POINTER;
- }
- nsCOMPtr<nsIConsoleReportCollector> reporter = do_QueryInterface(aChannel);
- if (reporter) {
- reporter->FlushConsoleReports(GetDocument());
- }
- nsCOMPtr<nsIURI> url;
- nsresult rv = aChannel->GetURI(getter_AddRefs(url));
- if (NS_FAILED(rv)) {
- return rv;
- }
- nsCOMPtr<nsITimedChannel> timingChannel = do_QueryInterface(aChannel);
- if (timingChannel) {
- TimeStamp channelCreationTime;
- rv = timingChannel->GetChannelCreation(&channelCreationTime);
- if (NS_SUCCEEDED(rv) && !channelCreationTime.IsNull()) {
- nsCOMPtr<nsPILoadGroupInternal> internalLoadGroup =
- do_QueryInterface(mLoadGroup);
- if (internalLoadGroup) {
- internalLoadGroup->OnEndPageLoad(aChannel);
- }
- }
- }
- // Timing is picked up by the window, we don't need it anymore
- mTiming = nullptr;
- // clean up reload state for meta charset
- if (eCharsetReloadRequested == mCharsetReloadState) {
- mCharsetReloadState = eCharsetReloadStopOrigional;
- } else {
- mCharsetReloadState = eCharsetReloadInit;
- }
- // Save a pointer to the currently-loading history entry.
- // nsDocShell::EndPageLoad will clear mLSHE, but we may need this history
- // entry further down in this method.
- nsCOMPtr<nsISHEntry> loadingSHE = mLSHE;
- mozilla::Unused << loadingSHE; // XXX: Not sure if we need this anymore
- //
- // one of many safeguards that prevent death and destruction if
- // someone is so very very rude as to bring this window down
- // during this load handler.
- //
- nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
- // Notify the ContentViewer that the Document has finished loading. This
- // will cause any OnLoad(...) and PopState(...) handlers to fire.
- if (!mEODForCurrentDocument && mContentViewer) {
- mIsExecutingOnLoadHandler = true;
- mContentViewer->LoadComplete(aStatus);
- mIsExecutingOnLoadHandler = false;
- mEODForCurrentDocument = true;
- // If all documents have completed their loading
- // favor native event dispatch priorities
- // over performance
- if (--gNumberOfDocumentsLoading == 0) {
- // Hint to use normal native event dispatch priorities
- FavorPerformanceHint(false);
- }
- }
- /* Check if the httpChannel has any cache-control related response headers,
- * like no-store, no-cache. If so, update SHEntry so that
- * when a user goes back/forward to this page, we appropriately do
- * form value restoration or load from server.
- */
- nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
- if (!httpChannel) {
- // HttpChannel could be hiding underneath a Multipart channel.
- GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
- }
- if (httpChannel) {
- // figure out if SH should be saving layout state.
- bool discardLayoutState = ShouldDiscardLayoutState(httpChannel);
- if (mLSHE && discardLayoutState && (mLoadType & LOAD_CMD_NORMAL) &&
- (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_ERROR_PAGE)) {
- mLSHE->SetSaveLayoutStateFlag(false);
- }
- }
- // Clear mLSHE after calling the onLoadHandlers. This way, if the
- // onLoadHandler tries to load something different in
- // itself or one of its children, we can deal with it appropriately.
- if (mLSHE) {
- mLSHE->SetLoadType(nsIDocShellLoadInfo::loadHistory);
- // Clear the mLSHE reference to indicate document loading is done one
- // way or another.
- SetHistoryEntry(&mLSHE, nullptr);
- }
- // if there's a refresh header in the channel, this method
- // will set it up for us.
- if (mIsActive || !mDisableMetaRefreshWhenInactive)
- RefreshURIFromQueue();
- // Test whether this is the top frame or a subframe
- bool isTopFrame = true;
- nsCOMPtr<nsIDocShellTreeItem> targetParentTreeItem;
- rv = GetSameTypeParent(getter_AddRefs(targetParentTreeItem));
- if (NS_SUCCEEDED(rv) && targetParentTreeItem) {
- isTopFrame = false;
- }
- //
- // If the page load failed, then deal with the error condition...
- // Errors are handled as follows:
- // 1. Check to see if it's a file not found error or bad content
- // encoding error.
- // 2. Send the URI to a keyword server (if enabled)
- // 3. If the error was DNS failure, then add www and .com to the URI
- // (if appropriate).
- // 4. Throw an error dialog box...
- //
- if (url && NS_FAILED(aStatus)) {
- if (aStatus == NS_ERROR_FILE_NOT_FOUND ||
- aStatus == NS_ERROR_FILE_ACCESS_DENIED ||
- aStatus == NS_ERROR_CORRUPTED_CONTENT ||
- aStatus == NS_ERROR_INVALID_CONTENT_ENCODING) {
- DisplayLoadError(aStatus, url, nullptr, aChannel);
- return NS_OK;
- } else if (aStatus == NS_ERROR_INVALID_SIGNATURE) {
- // NS_ERROR_INVALID_SIGNATURE indicates a content-signature error.
- // This currently only happens in case a remote about page fails.
- // We have to load a fallback in this case.
- // XXX: We always load about blank here, firefox has to overwrite this if
- // it wants to display something else.
- return LoadURI(u"about:blank", // URI string
- nsIChannel::LOAD_NORMAL, // Load flags
- nullptr, // Referring URI
- nullptr, // Post data stream
- nullptr); // Headers stream
- }
- // Handle iframe document not loading error because source was
- // a tracking URL. We make a note of this iframe node by including
- // it in a dedicated array of blocked tracking nodes under its parent
- // document. (document of parent window of blocked document)
- if (isTopFrame == false && aStatus == NS_ERROR_TRACKING_URI) {
- // frameElement is our nsIContent to be annotated
- nsCOMPtr<nsIDOMElement> frameElement;
- nsPIDOMWindowOuter* thisWindow = GetWindow();
- if (!thisWindow) {
- return NS_OK;
- }
- frameElement = thisWindow->GetFrameElement();
- if (!frameElement) {
- return NS_OK;
- }
- // Parent window
- nsCOMPtr<nsIDocShellTreeItem> parentItem;
- GetSameTypeParent(getter_AddRefs(parentItem));
- if (!parentItem) {
- return NS_OK;
- }
- nsCOMPtr<nsIDocument> parentDoc;
- parentDoc = parentItem->GetDocument();
- if (!parentDoc) {
- return NS_OK;
- }
- nsCOMPtr<nsIContent> cont = do_QueryInterface(frameElement);
- parentDoc->AddBlockedTrackingNode(cont);
- return NS_OK;
- }
- if (sURIFixup) {
- //
- // Try and make an alternative URI from the old one
- //
- nsCOMPtr<nsIURI> newURI;
- nsCOMPtr<nsIInputStream> newPostData;
- nsAutoCString oldSpec;
- url->GetSpec(oldSpec);
- //
- // First try keyword fixup
- //
- nsAutoString keywordProviderName, keywordAsSent;
- if (aStatus == NS_ERROR_UNKNOWN_HOST && mAllowKeywordFixup) {
- bool keywordsEnabled = Preferences::GetBool("keyword.enabled", false);
- nsAutoCString host;
- url->GetHost(host);
- nsAutoCString scheme;
- url->GetScheme(scheme);
- int32_t dotLoc = host.FindChar('.');
- // we should only perform a keyword search under the following
- // conditions:
- // (0) Pref keyword.enabled is true
- // (1) the url scheme is http (or https)
- // (2) the url does not have a protocol scheme
- // If we don't enforce such a policy, then we end up doing
- // keyword searchs on urls we don't intend like imap, file,
- // mailbox, etc. This could lead to a security problem where we
- // send data to the keyword server that we shouldn't be.
- // Someone needs to clean up keywords in general so we can
- // determine on a per url basis if we want keywords
- // enabled...this is just a bandaid...
- if (keywordsEnabled && !scheme.IsEmpty() &&
- (scheme.Find("http") != 0)) {
- keywordsEnabled = false;
- }
- if (keywordsEnabled && (kNotFound == dotLoc)) {
- nsCOMPtr<nsIURIFixupInfo> info;
- // only send non-qualified hosts to the keyword server
- if (!mOriginalUriString.IsEmpty()) {
- sURIFixup->KeywordToURI(mOriginalUriString,
- getter_AddRefs(newPostData),
- getter_AddRefs(info));
- } else {
- //
- // If this string was passed through nsStandardURL by
- // chance, then it may have been converted from UTF-8 to
- // ACE, which would result in a completely bogus keyword
- // query. Here we try to recover the original Unicode
- // value, but this is not 100% correct since the value may
- // have been normalized per the IDN normalization rules.
- //
- // Since we don't have access to the exact original string
- // that was entered by the user, this will just have to do.
- bool isACE;
- nsAutoCString utf8Host;
- nsCOMPtr<nsIIDNService> idnSrv =
- do_GetService(NS_IDNSERVICE_CONTRACTID);
- if (idnSrv &&
- NS_SUCCEEDED(idnSrv->IsACE(host, &isACE)) && isACE &&
- NS_SUCCEEDED(idnSrv->ConvertACEtoUTF8(host, utf8Host))) {
- sURIFixup->KeywordToURI(utf8Host,
- getter_AddRefs(newPostData),
- getter_AddRefs(info));
- } else {
- sURIFixup->KeywordToURI(host,
- getter_AddRefs(newPostData),
- getter_AddRefs(info));
- }
- }
- info->GetPreferredURI(getter_AddRefs(newURI));
- if (newURI) {
- info->GetKeywordAsSent(keywordAsSent);
- info->GetKeywordProviderName(keywordProviderName);
- }
- } // end keywordsEnabled
- }
- //
- // Now try change the address, e.g. turn http://foo into
- // http://www.foo.com
- //
- if (aStatus == NS_ERROR_UNKNOWN_HOST ||
- aStatus == NS_ERROR_NET_RESET) {
- bool doCreateAlternate = true;
- // Skip fixup for anything except a normal document load
- // operation on the topframe.
- if (mLoadType != LOAD_NORMAL || !isTopFrame) {
- doCreateAlternate = false;
- } else {
- // Test if keyword lookup produced a new URI or not
- if (newURI) {
- bool sameURI = false;
- url->Equals(newURI, &sameURI);
- if (!sameURI) {
- // Keyword lookup made a new URI so no need to try
- // an alternate one.
- doCreateAlternate = false;
- }
- }
- if (doCreateAlternate) {
- // Skip doing this if our channel was redirected, because we
- // shouldn't be guessing things about the post-redirect URI.
- nsLoadFlags loadFlags = 0;
- if (NS_FAILED(aChannel->GetLoadFlags(&loadFlags)) ||
- (loadFlags & nsIChannel::LOAD_REPLACE)) {
- doCreateAlternate = false;
- }
- }
- }
- if (doCreateAlternate) {
- newURI = nullptr;
- newPostData = nullptr;
- keywordProviderName.Truncate();
- keywordAsSent.Truncate();
- sURIFixup->CreateFixupURI(oldSpec,
- nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
- getter_AddRefs(newPostData),
- getter_AddRefs(newURI));
- }
- }
- // Did we make a new URI that is different to the old one? If so
- // load it.
- //
- if (newURI) {
- // Make sure the new URI is different from the old one,
- // otherwise there's little point trying to load it again.
- bool sameURI = false;
- url->Equals(newURI, &sameURI);
- if (!sameURI) {
- nsAutoCString newSpec;
- newURI->GetSpec(newSpec);
- NS_ConvertUTF8toUTF16 newSpecW(newSpec);
- // This notification is meant for Firefox Health Report so it
- // can increment counts from the search engine
- MaybeNotifyKeywordSearchLoading(keywordProviderName, keywordAsSent);
- return LoadURI(newSpecW.get(), // URI string
- LOAD_FLAGS_NONE, // Load flags
- nullptr, // Referring URI
- newPostData, // Post data stream
- nullptr); // Headers stream
- }
- }
- }
- // Well, fixup didn't work :-(
- // It is time to throw an error dialog box, and be done with it...
- // Errors to be shown only on top-level frames
- if ((aStatus == NS_ERROR_UNKNOWN_HOST ||
- aStatus == NS_ERROR_CONNECTION_REFUSED ||
- aStatus == NS_ERROR_UNKNOWN_PROXY_HOST ||
- aStatus == NS_ERROR_PROXY_CONNECTION_REFUSED) &&
- (isTopFrame || UseErrorPages())) {
- DisplayLoadError(aStatus, url, nullptr, aChannel);
- } else if (aStatus == NS_ERROR_NET_TIMEOUT ||
- aStatus == NS_ERROR_REDIRECT_LOOP ||
- aStatus == NS_ERROR_UNKNOWN_SOCKET_TYPE ||
- aStatus == NS_ERROR_NET_INTERRUPT ||
- aStatus == NS_ERROR_NET_RESET ||
- aStatus == NS_ERROR_OFFLINE ||
- aStatus == NS_ERROR_MALWARE_URI ||
- aStatus == NS_ERROR_PHISHING_URI ||
- aStatus == NS_ERROR_UNWANTED_URI ||
- aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
- aStatus == NS_ERROR_REMOTE_XUL ||
- aStatus == NS_ERROR_INTERCEPTION_FAILED ||
- aStatus == NS_ERROR_NET_INADEQUATE_SECURITY ||
- NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) {
- // Errors to be shown for any frame
- DisplayLoadError(aStatus, url, nullptr, aChannel);
- } else if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) {
- // Non-caching channels will simply return NS_ERROR_OFFLINE.
- // Caching channels would have to look at their flags to work
- // out which error to return. Or we can fix up the error here.
- if (!(mLoadType & LOAD_CMD_HISTORY)) {
- aStatus = NS_ERROR_OFFLINE;
- }
- DisplayLoadError(aStatus, url, nullptr, aChannel);
- }
- } else if (url && NS_SUCCEEDED(aStatus)) {
- // If we have a host
- mozilla::net::PredictorLearnRedirect(url, aChannel, this);
- }
- return NS_OK;
- }
- //*****************************************************************************
- // nsDocShell: Content Viewer Management
- //*****************************************************************************
- nsresult
- nsDocShell::EnsureContentViewer()
- {
- if (mContentViewer) {
- return NS_OK;
- }
- if (mIsBeingDestroyed) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsIURI> baseURI;
- nsIPrincipal* principal = GetInheritedPrincipal(false);
- nsCOMPtr<nsIDocShellTreeItem> parentItem;
- GetSameTypeParent(getter_AddRefs(parentItem));
- if (parentItem) {
- if (nsCOMPtr<nsPIDOMWindowOuter> domWin = GetWindow()) {
- nsCOMPtr<Element> parentElement = domWin->GetFrameElementInternal();
- if (parentElement) {
- baseURI = parentElement->GetBaseURI();
- }
- }
- }
- nsresult rv = CreateAboutBlankContentViewer(principal, baseURI);
- NS_ENSURE_STATE(mContentViewer);
- if (NS_SUCCEEDED(rv)) {
- nsCOMPtr<nsIDocument> doc(GetDocument());
- NS_ASSERTION(doc,
- "Should have doc if CreateAboutBlankContentViewer "
- "succeeded!");
- doc->SetIsInitialDocument(true);
- }
- return rv;
- }
- nsresult
- nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal,
- nsIURI* aBaseURI,
- bool aTryToSaveOldPresentation)
- {
- nsCOMPtr<nsIDocument> blankDoc;
- nsCOMPtr<nsIContentViewer> viewer;
- nsresult rv = NS_ERROR_FAILURE;
- /* mCreatingDocument should never be true at this point. However, it's
- a theoretical possibility. We want to know about it and make it stop,
- and this sounds like a job for an assertion. */
- NS_ASSERTION(!mCreatingDocument,
- "infinite(?) loop creating document averted");
- if (mCreatingDocument) {
- return NS_ERROR_FAILURE;
- }
- // mContentViewer->PermitUnload may release |this| docshell.
- nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
- AutoRestore<bool> creatingDocument(mCreatingDocument);
- mCreatingDocument = true;
- if (aPrincipal && !nsContentUtils::IsSystemPrincipal(aPrincipal) &&
- mItemType != typeChrome) {
- MOZ_ASSERT(ChromeUtils::IsOriginAttributesEqualIgnoringAddonId(
- BasePrincipal::Cast(aPrincipal)->OriginAttributesRef(),
- mOriginAttributes));
- }
- // Make sure timing is created. But first record whether we had it
- // already, so we don't clobber the timing for an in-progress load.
- bool hadTiming = mTiming;
- MaybeInitTiming();
- if (mContentViewer) {
- // We've got a content viewer already. Make sure the user
- // permits us to discard the current document and replace it
- // with about:blank. And also ensure we fire the unload events
- // in the current document.
- // Unload gets fired first for
- // document loaded from the session history.
- mTiming->NotifyBeforeUnload();
- bool okToUnload;
- rv = mContentViewer->PermitUnload(&okToUnload);
- if (NS_SUCCEEDED(rv) && !okToUnload) {
- // The user chose not to unload the page, interrupt the load.
- return NS_ERROR_FAILURE;
- }
- mSavingOldViewer = aTryToSaveOldPresentation &&
- CanSavePresentation(LOAD_NORMAL, nullptr, nullptr);
- if (mTiming) {
- mTiming->NotifyUnloadAccepted(mCurrentURI);
- }
- // Make sure to blow away our mLoadingURI just in case. No loads
- // from inside this pagehide.
- mLoadingURI = nullptr;
- // Stop any in-progress loading, so that we don't accidentally trigger any
- // PageShow notifications from Embed() interrupting our loading below.
- Stop();
- // Notify the current document that it is about to be unloaded!!
- //
- // It is important to fire the unload() notification *before* any state
- // is changed within the DocShell - otherwise, javascript will get the
- // wrong information :-(
- //
- (void)FirePageHideNotification(!mSavingOldViewer);
- }
- // Now make sure we don't think we're in the middle of firing unload after
- // this point. This will make us fire unload when the about:blank document
- // unloads... but that's ok, more or less. Would be nice if it fired load
- // too, of course.
- mFiredUnloadEvent = false;
- nsCOMPtr<nsIDocumentLoaderFactory> docFactory =
- nsContentUtils::FindInternalContentViewer(NS_LITERAL_CSTRING("text/html"));
- if (docFactory) {
- nsCOMPtr<nsIPrincipal> principal;
- if (mSandboxFlags & SANDBOXED_ORIGIN) {
- if (aPrincipal) {
- principal = nsNullPrincipal::CreateWithInheritedAttributes(aPrincipal);
- } else {
- principal = nsNullPrincipal::CreateWithInheritedAttributes(this);
- }
- } else {
- principal = aPrincipal;
- }
- // generate (about:blank) document to load
- docFactory->CreateBlankDocument(mLoadGroup, principal,
- getter_AddRefs(blankDoc));
- if (blankDoc) {
- // Hack: set the base URI manually, since this document never
- // got Reset() with a channel.
- blankDoc->SetBaseURI(aBaseURI);
- blankDoc->SetContainer(this);
- // Copy our sandbox flags to the document. These are immutable
- // after being set here.
- blankDoc->SetSandboxFlags(mSandboxFlags);
- // create a content viewer for us and the new document
- docFactory->CreateInstanceForDocument(
- NS_ISUPPORTS_CAST(nsIDocShell*, this), blankDoc, "view",
- getter_AddRefs(viewer));
- // hook 'em up
- if (viewer) {
- viewer->SetContainer(this);
- rv = Embed(viewer, "", 0);
- NS_ENSURE_SUCCESS(rv, rv);
- SetCurrentURI(blankDoc->GetDocumentURI(), nullptr, true, 0);
- rv = mIsBeingDestroyed ? NS_ERROR_NOT_AVAILABLE : NS_OK;
- }
- }
- }
- // The transient about:blank viewer doesn't have a session history entry.
- SetHistoryEntry(&mOSHE, nullptr);
- // Clear out our mTiming like we would in EndPageLoad, if we didn't
- // have one before entering this function.
- if (!hadTiming) {
- mTiming = nullptr;
- mBlankTiming = true;
- }
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::CreateAboutBlankContentViewer(nsIPrincipal* aPrincipal)
- {
- return CreateAboutBlankContentViewer(aPrincipal, nullptr);
- }
- bool
- nsDocShell::CanSavePresentation(uint32_t aLoadType,
- nsIRequest* aNewRequest,
- nsIDocument* aNewDocument)
- {
- if (!mOSHE) {
- return false; // no entry to save into
- }
- nsCOMPtr<nsIContentViewer> viewer;
- mOSHE->GetContentViewer(getter_AddRefs(viewer));
- if (viewer) {
- NS_WARNING("mOSHE already has a content viewer!");
- return false;
- }
- // Only save presentation for "normal" loads and link loads. Anything else
- // probably wants to refetch the page, so caching the old presentation
- // would be incorrect.
- if (aLoadType != LOAD_NORMAL &&
- aLoadType != LOAD_HISTORY &&
- aLoadType != LOAD_LINK &&
- aLoadType != LOAD_STOP_CONTENT &&
- aLoadType != LOAD_STOP_CONTENT_AND_REPLACE &&
- aLoadType != LOAD_ERROR_PAGE) {
- return false;
- }
- // If the session history entry has the saveLayoutState flag set to false,
- // then we should not cache the presentation.
- bool canSaveState;
- mOSHE->GetSaveLayoutStateFlag(&canSaveState);
- if (!canSaveState) {
- return false;
- }
- // If the document is not done loading, don't cache it.
- if (!mScriptGlobal || mScriptGlobal->IsLoading()) {
- return false;
- }
- if (mScriptGlobal->WouldReuseInnerWindow(aNewDocument)) {
- return false;
- }
- // Avoid doing the work of saving the presentation state in the case where
- // the content viewer cache is disabled.
- if (nsSHistory::GetMaxTotalViewers() == 0) {
- return false;
- }
- // Don't cache the content viewer if we're in a subframe and the subframe
- // pref is disabled.
- bool cacheFrames =
- Preferences::GetBool("browser.sessionhistory.cache_subframes", false);
- if (!cacheFrames) {
- nsCOMPtr<nsIDocShellTreeItem> root;
- GetSameTypeParent(getter_AddRefs(root));
- if (root && root != this) {
- return false; // this is a subframe load
- }
- }
- // If the document does not want its presentation cached, then don't.
- nsCOMPtr<nsIDocument> doc = mScriptGlobal->GetExtantDoc();
- return doc && doc->CanSavePresentation(aNewRequest);
- }
- void
- nsDocShell::ReattachEditorToWindow(nsISHEntry* aSHEntry)
- {
- NS_ASSERTION(!mEditorData,
- "Why reattach an editor when we already have one?");
- NS_ASSERTION(aSHEntry && aSHEntry->HasDetachedEditor(),
- "Reattaching when there's not a detached editor.");
- if (mEditorData || !aSHEntry) {
- return;
- }
- mEditorData = aSHEntry->ForgetEditorData();
- if (mEditorData) {
- #ifdef DEBUG
- nsresult rv =
- #endif
- mEditorData->ReattachToWindow(this);
- NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to reattach editing session");
- }
- }
- void
- nsDocShell::DetachEditorFromWindow()
- {
- if (!mEditorData || mEditorData->WaitingForLoad()) {
- // If there's nothing to detach, or if the editor data is actually set
- // up for the _new_ page that's coming in, don't detach.
- return;
- }
- NS_ASSERTION(!mOSHE || !mOSHE->HasDetachedEditor(),
- "Detaching editor when it's already detached.");
- nsresult res = mEditorData->DetachFromWindow();
- NS_ASSERTION(NS_SUCCEEDED(res), "Failed to detach editor");
- if (NS_SUCCEEDED(res)) {
- // Make mOSHE hold the owning ref to the editor data.
- if (mOSHE) {
- mOSHE->SetEditorData(mEditorData.forget());
- } else {
- mEditorData = nullptr;
- }
- }
- #ifdef DEBUG
- {
- bool isEditable;
- GetEditable(&isEditable);
- NS_ASSERTION(!isEditable,
- "Window is still editable after detaching editor.");
- }
- #endif // DEBUG
- }
- nsresult
- nsDocShell::CaptureState()
- {
- if (!mOSHE || mOSHE == mLSHE) {
- // No entry to save into, or we're replacing the existing entry.
- return NS_ERROR_FAILURE;
- }
- if (!mScriptGlobal) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsISupports> windowState = mScriptGlobal->SaveWindowState();
- NS_ENSURE_TRUE(windowState, NS_ERROR_FAILURE);
- #ifdef DEBUG_PAGE_CACHE
- nsCOMPtr<nsIURI> uri;
- mOSHE->GetURI(getter_AddRefs(uri));
- nsAutoCString spec;
- if (uri) {
- uri->GetSpec(spec);
- }
- printf("Saving presentation into session history\n");
- printf(" SH URI: %s\n", spec.get());
- #endif
- nsresult rv = mOSHE->SetWindowState(windowState);
- NS_ENSURE_SUCCESS(rv, rv);
- // Suspend refresh URIs and save off the timer queue
- rv = mOSHE->SetRefreshURIList(mSavedRefreshURIList);
- NS_ENSURE_SUCCESS(rv, rv);
- // Capture the current content viewer bounds.
- if (mContentViewer) {
- nsIntRect bounds;
- mContentViewer->GetBounds(bounds);
- rv = mOSHE->SetViewerBounds(bounds);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- // Capture the docshell hierarchy.
- mOSHE->ClearChildShells();
- uint32_t childCount = mChildList.Length();
- for (uint32_t i = 0; i < childCount; ++i) {
- nsCOMPtr<nsIDocShellTreeItem> childShell = do_QueryInterface(ChildAt(i));
- NS_ASSERTION(childShell, "null child shell");
- mOSHE->AddChildShell(childShell);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::RestorePresentationEvent::Run()
- {
- if (mDocShell && NS_FAILED(mDocShell->RestoreFromHistory())) {
- NS_WARNING("RestoreFromHistory failed");
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::BeginRestore(nsIContentViewer* aContentViewer, bool aTop)
- {
- nsresult rv;
- if (!aContentViewer) {
- rv = EnsureContentViewer();
- NS_ENSURE_SUCCESS(rv, rv);
- aContentViewer = mContentViewer;
- }
- // Dispatch events for restoring the presentation. We try to simulate
- // the progress notifications loading the document would cause, so we add
- // the document's channel to the loadgroup to initiate stateChange
- // notifications.
- nsCOMPtr<nsIDOMDocument> domDoc;
- aContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
- nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
- if (doc) {
- nsIChannel* channel = doc->GetChannel();
- if (channel) {
- mEODForCurrentDocument = false;
- mIsRestoringDocument = true;
- mLoadGroup->AddRequest(channel, nullptr);
- mIsRestoringDocument = false;
- }
- }
- if (!aTop) {
- // This point corresponds to us having gotten OnStartRequest or
- // STATE_START, so do the same thing that CreateContentViewer does at
- // this point to ensure that unload/pagehide events for this document
- // will fire when it's unloaded again.
- mFiredUnloadEvent = false;
- // For non-top frames, there is no notion of making sure that the
- // previous document is in the domwindow when STATE_START notifications
- // happen. We can just call BeginRestore for all of the child shells
- // now.
- rv = BeginRestoreChildren();
- NS_ENSURE_SUCCESS(rv, rv);
- }
- return NS_OK;
- }
- nsresult
- nsDocShell::BeginRestoreChildren()
- {
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
- if (child) {
- nsresult rv = child->BeginRestore(nullptr, false);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::FinishRestore()
- {
- // First we call finishRestore() on our children. In the simulated load,
- // all of the child frames finish loading before the main document.
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
- if (child) {
- child->FinishRestore();
- }
- }
- if (mOSHE && mOSHE->HasDetachedEditor()) {
- ReattachEditorToWindow(mOSHE);
- }
- nsCOMPtr<nsIDocument> doc = GetDocument();
- if (doc) {
- // Finally, we remove the request from the loadgroup. This will
- // cause onStateChange(STATE_STOP) to fire, which will fire the
- // pageshow event to the chrome.
- nsIChannel* channel = doc->GetChannel();
- if (channel) {
- mIsRestoringDocument = true;
- mLoadGroup->RemoveRequest(channel, nullptr, NS_OK);
- mIsRestoringDocument = false;
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetRestoringDocument(bool* aRestoring)
- {
- *aRestoring = mIsRestoringDocument;
- return NS_OK;
- }
- nsresult
- nsDocShell::RestorePresentation(nsISHEntry* aSHEntry, bool* aRestoring)
- {
- NS_ASSERTION(mLoadType & LOAD_CMD_HISTORY,
- "RestorePresentation should only be called for history loads");
- nsCOMPtr<nsIContentViewer> viewer;
- aSHEntry->GetContentViewer(getter_AddRefs(viewer));
- #ifdef DEBUG_PAGE_CACHE
- nsCOMPtr<nsIURI> uri;
- aSHEntry->GetURI(getter_AddRefs(uri));
- nsAutoCString spec;
- if (uri) {
- uri->GetSpec(spec);
- }
- #endif
- *aRestoring = false;
- if (!viewer) {
- #ifdef DEBUG_PAGE_CACHE
- printf("no saved presentation for uri: %s\n", spec.get());
- #endif
- return NS_OK;
- }
- // We need to make sure the content viewer's container is this docshell.
- // In subframe navigation, it's possible for the docshell that the
- // content viewer was originally loaded into to be replaced with a
- // different one. We don't currently support restoring the presentation
- // in that case.
- nsCOMPtr<nsIDocShell> container;
- viewer->GetContainer(getter_AddRefs(container));
- if (!::SameCOMIdentity(container, GetAsSupports(this))) {
- #ifdef DEBUG_PAGE_CACHE
- printf("No valid container, clearing presentation\n");
- #endif
- aSHEntry->SetContentViewer(nullptr);
- return NS_ERROR_FAILURE;
- }
- NS_ASSERTION(mContentViewer != viewer, "Restoring existing presentation");
- #ifdef DEBUG_PAGE_CACHE
- printf("restoring presentation from session history: %s\n", spec.get());
- #endif
- SetHistoryEntry(&mLSHE, aSHEntry);
- // Post an event that will remove the request after we've returned
- // to the event loop. This mimics the way it is called by nsIChannel
- // implementations.
- // Revoke any pending restore (just in case)
- NS_ASSERTION(!mRestorePresentationEvent.IsPending(),
- "should only have one RestorePresentationEvent");
- mRestorePresentationEvent.Revoke();
- RefPtr<RestorePresentationEvent> evt = new RestorePresentationEvent(this);
- nsresult rv = NS_DispatchToCurrentThread(evt);
- if (NS_SUCCEEDED(rv)) {
- mRestorePresentationEvent = evt.get();
- // The rest of the restore processing will happen on our event
- // callback.
- *aRestoring = true;
- }
- return rv;
- }
- namespace {
- class MOZ_STACK_CLASS PresentationEventForgetter
- {
- public:
- explicit PresentationEventForgetter(
- nsRevocableEventPtr<nsDocShell::RestorePresentationEvent>&
- aRestorePresentationEvent)
- : mRestorePresentationEvent(aRestorePresentationEvent)
- , mEvent(aRestorePresentationEvent.get())
- {
- }
- ~PresentationEventForgetter()
- {
- Forget();
- }
- void Forget()
- {
- if (mRestorePresentationEvent.get() == mEvent) {
- mRestorePresentationEvent.Forget();
- mEvent = nullptr;
- }
- }
- private:
- nsRevocableEventPtr<nsDocShell::RestorePresentationEvent>&
- mRestorePresentationEvent;
- RefPtr<nsDocShell::RestorePresentationEvent> mEvent;
- };
- } // namespace
- nsresult
- nsDocShell::RestoreFromHistory()
- {
- MOZ_ASSERT(mRestorePresentationEvent.IsPending());
- PresentationEventForgetter forgetter(mRestorePresentationEvent);
- // This section of code follows the same ordering as CreateContentViewer.
- if (!mLSHE) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsIContentViewer> viewer;
- mLSHE->GetContentViewer(getter_AddRefs(viewer));
- if (!viewer) {
- return NS_ERROR_FAILURE;
- }
- if (mSavingOldViewer) {
- // We determined that it was safe to cache the document presentation
- // at the time we initiated the new load. We need to check whether
- // it's still safe to do so, since there may have been DOM mutations
- // or new requests initiated.
- nsCOMPtr<nsIDOMDocument> domDoc;
- viewer->GetDOMDocument(getter_AddRefs(domDoc));
- nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
- nsIRequest* request = nullptr;
- if (doc) {
- request = doc->GetChannel();
- }
- mSavingOldViewer = CanSavePresentation(mLoadType, request, doc);
- }
- nsCOMPtr<nsIContentViewer> oldCv(mContentViewer);
- nsCOMPtr<nsIContentViewer> newCv(viewer);
- int32_t minFontSize = 0;
- float textZoom = 1.0f;
- float pageZoom = 1.0f;
- float overrideDPPX = 0.0f;
- bool styleDisabled = false;
- if (oldCv && newCv) {
- oldCv->GetMinFontSize(&minFontSize);
- oldCv->GetTextZoom(&textZoom);
- oldCv->GetFullZoom(&pageZoom);
- oldCv->GetOverrideDPPX(&overrideDPPX);
- oldCv->GetAuthorStyleDisabled(&styleDisabled);
- }
- // Protect against mLSHE going away via a load triggered from
- // pagehide or unload.
- nsCOMPtr<nsISHEntry> origLSHE = mLSHE;
- // Make sure to blow away our mLoadingURI just in case. No loads
- // from inside this pagehide.
- mLoadingURI = nullptr;
- // Notify the old content viewer that it's being hidden.
- FirePageHideNotification(!mSavingOldViewer);
- // If mLSHE was changed as a result of the pagehide event, then
- // something else was loaded. Don't finish restoring.
- if (mLSHE != origLSHE) {
- return NS_OK;
- }
- // Add the request to our load group. We do this before swapping out
- // the content viewers so that consumers of STATE_START can access
- // the old document. We only deal with the toplevel load at this time --
- // to be consistent with normal document loading, subframes cannot start
- // loading until after data arrives, which is after STATE_START completes.
- RefPtr<RestorePresentationEvent> currentPresentationRestoration =
- mRestorePresentationEvent.get();
- Stop();
- // Make sure we're still restoring the same presentation.
- // If we aren't, docshell is in process doing another load already.
- NS_ENSURE_STATE(currentPresentationRestoration ==
- mRestorePresentationEvent.get());
- BeginRestore(viewer, true);
- NS_ENSURE_STATE(currentPresentationRestoration ==
- mRestorePresentationEvent.get());
- forgetter.Forget();
- // Set mFiredUnloadEvent = false so that the unload handler for the
- // *new* document will fire.
- mFiredUnloadEvent = false;
- mURIResultedInDocument = true;
- nsCOMPtr<nsISHistory> rootSH;
- GetRootSessionHistory(getter_AddRefs(rootSH));
- if (rootSH) {
- nsCOMPtr<nsISHistoryInternal> hist = do_QueryInterface(rootSH);
- rootSH->GetIndex(&mPreviousTransIndex);
- hist->UpdateIndex();
- rootSH->GetIndex(&mLoadedTransIndex);
- #ifdef DEBUG_PAGE_CACHE
- printf("Previous index: %d, Loaded index: %d\n\n", mPreviousTransIndex,
- mLoadedTransIndex);
- #endif
- }
- // Rather than call Embed(), we will retrieve the viewer from the session
- // history entry and swap it in.
- // XXX can we refactor this so that we can just call Embed()?
- PersistLayoutHistoryState();
- nsresult rv;
- if (mContentViewer) {
- if (mSavingOldViewer && NS_FAILED(CaptureState())) {
- if (mOSHE) {
- mOSHE->SyncPresentationState();
- }
- mSavingOldViewer = false;
- }
- }
- mSavedRefreshURIList = nullptr;
- // In cases where we use a transient about:blank viewer between loads,
- // we never show the transient viewer, so _its_ previous viewer is never
- // unhooked from the view hierarchy. Destroy any such previous viewer now,
- // before we grab the root view sibling, so that we don't grab a view
- // that's about to go away.
- if (mContentViewer) {
- nsCOMPtr<nsIContentViewer> previousViewer;
- mContentViewer->GetPreviousViewer(getter_AddRefs(previousViewer));
- if (previousViewer) {
- mContentViewer->SetPreviousViewer(nullptr);
- previousViewer->Destroy();
- }
- }
- // Save off the root view's parent and sibling so that we can insert the
- // new content viewer's root view at the same position. Also save the
- // bounds of the root view's widget.
- nsView* rootViewSibling = nullptr;
- nsView* rootViewParent = nullptr;
- nsIntRect newBounds(0, 0, 0, 0);
- nsCOMPtr<nsIPresShell> oldPresShell = GetPresShell();
- if (oldPresShell) {
- nsViewManager* vm = oldPresShell->GetViewManager();
- if (vm) {
- nsView* oldRootView = vm->GetRootView();
- if (oldRootView) {
- rootViewSibling = oldRootView->GetNextSibling();
- rootViewParent = oldRootView->GetParent();
- mContentViewer->GetBounds(newBounds);
- }
- }
- }
- nsCOMPtr<nsIContent> container;
- nsCOMPtr<nsIDocument> sibling;
- if (rootViewParent && rootViewParent->GetParent()) {
- nsIFrame* frame = rootViewParent->GetParent()->GetFrame();
- container = frame ? frame->GetContent() : nullptr;
- }
- if (rootViewSibling) {
- nsIFrame* frame = rootViewSibling->GetFrame();
- sibling =
- frame ? frame->PresContext()->PresShell()->GetDocument() : nullptr;
- }
- // Transfer ownership to mContentViewer. By ensuring that either the
- // docshell or the session history, but not both, have references to the
- // content viewer, we prevent the viewer from being torn down after
- // Destroy() is called.
- if (mContentViewer) {
- mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr);
- viewer->SetPreviousViewer(mContentViewer);
- }
- if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
- // We don't plan to save a viewer in mOSHE; tell it to drop
- // any other state it's holding.
- mOSHE->SyncPresentationState();
- }
- // Order the mContentViewer setup just like Embed does.
- mContentViewer = nullptr;
- // Now that we're about to switch documents, forget all of our children.
- // Note that we cached them as needed up in CaptureState above.
- DestroyChildren();
- mContentViewer.swap(viewer);
- // Grab all of the related presentation from the SHEntry now.
- // Clearing the viewer from the SHEntry will clear all of this state.
- nsCOMPtr<nsISupports> windowState;
- mLSHE->GetWindowState(getter_AddRefs(windowState));
- mLSHE->SetWindowState(nullptr);
- bool sticky;
- mLSHE->GetSticky(&sticky);
- nsCOMPtr<nsIDOMDocument> domDoc;
- mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
- nsCOMArray<nsIDocShellTreeItem> childShells;
- int32_t i = 0;
- nsCOMPtr<nsIDocShellTreeItem> child;
- while (NS_SUCCEEDED(mLSHE->ChildShellAt(i++, getter_AddRefs(child))) &&
- child) {
- childShells.AppendObject(child);
- }
- // get the previous content viewer size
- nsIntRect oldBounds(0, 0, 0, 0);
- mLSHE->GetViewerBounds(oldBounds);
- // Restore the refresh URI list. The refresh timers will be restarted
- // when EndPageLoad() is called.
- nsCOMPtr<nsIMutableArray> refreshURIList;
- mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIList));
- // Reattach to the window object.
- mIsRestoringDocument = true; // for MediaDocument::BecomeInteractive
- rv = mContentViewer->Open(windowState, mLSHE);
- mIsRestoringDocument = false;
- // Hack to keep nsDocShellEditorData alive across the
- // SetContentViewer(nullptr) call below.
- nsAutoPtr<nsDocShellEditorData> data(mLSHE->ForgetEditorData());
- // Now remove it from the cached presentation.
- mLSHE->SetContentViewer(nullptr);
- mEODForCurrentDocument = false;
- mLSHE->SetEditorData(data.forget());
- #ifdef DEBUG
- {
- nsCOMPtr<nsIMutableArray> refreshURIs;
- mLSHE->GetRefreshURIList(getter_AddRefs(refreshURIs));
- nsCOMPtr<nsIDocShellTreeItem> childShell;
- mLSHE->ChildShellAt(0, getter_AddRefs(childShell));
- NS_ASSERTION(!refreshURIs && !childShell,
- "SHEntry should have cleared presentation state");
- }
- #endif
- // Restore the sticky state of the viewer. The viewer has set this state
- // on the history entry in Destroy() just before marking itself non-sticky,
- // to avoid teardown of the presentation.
- mContentViewer->SetSticky(sticky);
- NS_ENSURE_SUCCESS(rv, rv);
- // mLSHE is now our currently-loaded document.
- SetHistoryEntry(&mOSHE, mLSHE);
- // XXX special wyciwyg handling in Embed()?
- // We aren't going to restore any items from the LayoutHistoryState,
- // but we don't want them to stay around in case the page is reloaded.
- SetLayoutHistoryState(nullptr);
- // This is the end of our Embed() replacement
- mSavingOldViewer = false;
- mEODForCurrentDocument = false;
- // Tell the event loop to favor plevents over user events, see comments
- // in CreateContentViewer.
- if (++gNumberOfDocumentsLoading == 1) {
- FavorPerformanceHint(true);
- }
- if (oldCv && newCv) {
- newCv->SetMinFontSize(minFontSize);
- newCv->SetTextZoom(textZoom);
- newCv->SetFullZoom(pageZoom);
- newCv->SetOverrideDPPX(overrideDPPX);
- newCv->SetAuthorStyleDisabled(styleDisabled);
- }
- nsCOMPtr<nsIDocument> document = do_QueryInterface(domDoc);
- if (document) {
- RefPtr<nsDocShell> parent = GetParentDocshell();
- if (parent) {
- nsCOMPtr<nsIDocument> d = parent->GetDocument();
- if (d) {
- if (d->EventHandlingSuppressed()) {
- document->SuppressEventHandling(nsIDocument::eEvents,
- d->EventHandlingSuppressed());
- }
- // Ick, it'd be nicer to not rewalk all of the subdocs here.
- if (d->AnimationsPaused()) {
- document->SuppressEventHandling(nsIDocument::eAnimationsOnly,
- d->AnimationsPaused());
- }
- }
- }
- // Use the uri from the mLSHE we had when we entered this function
- // (which need not match the document's URI if anchors are involved),
- // since that's the history entry we're loading. Note that if we use
- // origLSHE we don't have to worry about whether the entry in question
- // is still mLSHE or whether it's now mOSHE.
- nsCOMPtr<nsIURI> uri;
- origLSHE->GetURI(getter_AddRefs(uri));
- SetCurrentURI(uri, document->GetChannel(), true, 0);
- }
- // This is the end of our CreateContentViewer() replacement.
- // Now we simulate a load. First, we restore the state of the javascript
- // window object.
- nsCOMPtr<nsPIDOMWindowOuter> privWin = GetWindow();
- NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface");
- // Now, dispatch a title change event which would happen as the
- // <head> is parsed.
- document->NotifyPossibleTitleChange(false);
- // Now we simulate appending child docshells for subframes.
- for (i = 0; i < childShells.Count(); ++i) {
- nsIDocShellTreeItem* childItem = childShells.ObjectAt(i);
- nsCOMPtr<nsIDocShell> childShell = do_QueryInterface(childItem);
- // Make sure to not clobber the state of the child. Since AddChild
- // always clobbers it, save it off first.
- bool allowPlugins;
- childShell->GetAllowPlugins(&allowPlugins);
- bool allowJavascript;
- childShell->GetAllowJavascript(&allowJavascript);
- bool allowRedirects;
- childShell->GetAllowMetaRedirects(&allowRedirects);
- bool allowSubframes;
- childShell->GetAllowSubframes(&allowSubframes);
- bool allowImages;
- childShell->GetAllowImages(&allowImages);
- bool allowMedia = childShell->GetAllowMedia();
- bool allowDNSPrefetch;
- childShell->GetAllowDNSPrefetch(&allowDNSPrefetch);
- bool allowContentRetargeting = childShell->GetAllowContentRetargeting();
- bool allowContentRetargetingOnChildren =
- childShell->GetAllowContentRetargetingOnChildren();
- uint32_t defaultLoadFlags;
- childShell->GetDefaultLoadFlags(&defaultLoadFlags);
- // this.AddChild(child) calls child.SetDocLoaderParent(this), meaning that
- // the child inherits our state. Among other things, this means that the
- // child inherits our mIsActive, mIsPrerendered and mPrivateBrowsingId,
- // which is what we want.
- AddChild(childItem);
- childShell->SetAllowPlugins(allowPlugins);
- childShell->SetAllowJavascript(allowJavascript);
- childShell->SetAllowMetaRedirects(allowRedirects);
- childShell->SetAllowSubframes(allowSubframes);
- childShell->SetAllowImages(allowImages);
- childShell->SetAllowMedia(allowMedia);
- childShell->SetAllowDNSPrefetch(allowDNSPrefetch);
- childShell->SetAllowContentRetargeting(allowContentRetargeting);
- childShell->SetAllowContentRetargetingOnChildren(
- allowContentRetargetingOnChildren);
- childShell->SetDefaultLoadFlags(defaultLoadFlags);
- rv = childShell->BeginRestore(nullptr, false);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- // Make sure to restore the window state after adding the child shells back
- // to the tree. This is necessary for Thaw() and Resume() to propagate
- // properly.
- rv = privWin->RestoreWindowState(windowState);
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIPresShell> shell = GetPresShell();
- // We may be displayed on a different monitor (or in a different
- // HiDPI mode) than when we got into the history list. So we need
- // to check if this has happened. See bug 838239.
- // Because the prescontext normally handles resolution changes via
- // a runnable (see nsPresContext::UIResolutionChanged), its device
- // context won't be -immediately- updated as a result of calling
- // shell->BackingScaleFactorChanged().
- // But we depend on that device context when adjusting the view size
- // via mContentViewer->SetBounds(newBounds) below. So we need to
- // explicitly tell it to check for changed resolution here.
- if (shell && shell->GetPresContext()->DeviceContext()->CheckDPIChange()) {
- shell->BackingScaleFactorChanged();
- }
- nsViewManager* newVM = shell ? shell->GetViewManager() : nullptr;
- nsView* newRootView = newVM ? newVM->GetRootView() : nullptr;
- // Insert the new root view at the correct location in the view tree.
- if (container) {
- nsSubDocumentFrame* subDocFrame =
- do_QueryFrame(container->GetPrimaryFrame());
- rootViewParent = subDocFrame ? subDocFrame->EnsureInnerView() : nullptr;
- } else {
- rootViewParent = nullptr;
- }
- if (sibling &&
- sibling->GetShell() &&
- sibling->GetShell()->GetViewManager()) {
- rootViewSibling = sibling->GetShell()->GetViewManager()->GetRootView();
- } else {
- rootViewSibling = nullptr;
- }
- if (rootViewParent && newRootView &&
- newRootView->GetParent() != rootViewParent) {
- nsViewManager* parentVM = rootViewParent->GetViewManager();
- if (parentVM) {
- // InsertChild(parent, child, sib, true) inserts the child after
- // sib in content order, which is before sib in view order. BUT
- // when sib is null it inserts at the end of the the document
- // order, i.e., first in view order. But when oldRootSibling is
- // null, the old root as at the end of the view list --- last in
- // content order --- and we want to call InsertChild(parent, child,
- // nullptr, false) in that case.
- parentVM->InsertChild(rootViewParent, newRootView,
- rootViewSibling,
- rootViewSibling ? true : false);
- NS_ASSERTION(newRootView->GetNextSibling() == rootViewSibling,
- "error in InsertChild");
- }
- }
- nsCOMPtr<nsPIDOMWindowInner> privWinInner = privWin->GetCurrentInnerWindow();
- // If parent is suspended, increase suspension count.
- // This can't be done as early as event suppression since this
- // depends on docshell tree.
- privWinInner->SyncStateFromParentWindow();
- // Now that all of the child docshells have been put into place, we can
- // restart the timers for the window and all of the child frames.
- privWinInner->Resume();
- // Restore the refresh URI list. The refresh timers will be restarted
- // when EndPageLoad() is called.
- mRefreshURIList = refreshURIList;
- // Meta-refresh timers have been restarted for this shell, but not
- // for our children. Walk the child shells and restart their timers.
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(mChildList);
- while (iter.HasMore()) {
- nsCOMPtr<nsIDocShell> child = do_QueryObject(iter.GetNext());
- if (child) {
- child->ResumeRefreshURIs();
- }
- }
- // Make sure this presentation is the same size as the previous
- // presentation. If this is not the same size we showed it at last time,
- // then we need to resize the widget.
- // XXXbryner This interacts poorly with Firefox's infobar. If the old
- // presentation had the infobar visible, then we will resize the new
- // presentation to that smaller size. However, firing the locationchanged
- // event will hide the infobar, which will immediately resize the window
- // back to the larger size. A future optimization might be to restore
- // the presentation at the "wrong" size, then fire the locationchanged
- // event and check whether the docshell's new size is the same as the
- // cached viewer size (skipping the resize if they are equal).
- if (newRootView) {
- if (!newBounds.IsEmpty() && !newBounds.IsEqualEdges(oldBounds)) {
- #ifdef DEBUG_PAGE_CACHE
- printf("resize widget(%d, %d, %d, %d)\n", newBounds.x,
- newBounds.y, newBounds.width, newBounds.height);
- #endif
- mContentViewer->SetBounds(newBounds);
- } else {
- nsIScrollableFrame* rootScrollFrame =
- shell->GetRootScrollFrameAsScrollableExternal();
- if (rootScrollFrame) {
- rootScrollFrame->PostScrolledAreaEventForCurrentArea();
- }
- }
- }
- // The FinishRestore call below can kill these, null them out so we don't
- // have invalid pointer lying around.
- newRootView = rootViewSibling = rootViewParent = nullptr;
- newVM = nullptr;
- // Simulate the completion of the load.
- nsDocShell::FinishRestore();
- // Restart plugins, and paint the content.
- if (shell) {
- shell->Thaw();
- }
- return privWin->FireDelayedDOMEvents();
- }
- nsresult
- nsDocShell::CreateContentViewer(const nsACString& aContentType,
- nsIRequest* aRequest,
- nsIStreamListener** aContentHandler)
- {
- *aContentHandler = nullptr;
- // Can we check the content type of the current content viewer
- // and reuse it without destroying it and re-creating it?
- NS_ASSERTION(mLoadGroup, "Someone ignored return from Init()?");
- // Instantiate the content viewer object
- nsCOMPtr<nsIContentViewer> viewer;
- nsresult rv = NewContentViewerObj(aContentType, aRequest, mLoadGroup,
- aContentHandler, getter_AddRefs(viewer));
- if (NS_FAILED(rv)) {
- return rv;
- }
- // Notify the current document that it is about to be unloaded!!
- //
- // It is important to fire the unload() notification *before* any state
- // is changed within the DocShell - otherwise, javascript will get the
- // wrong information :-(
- //
- if (mSavingOldViewer) {
- // We determined that it was safe to cache the document presentation
- // at the time we initiated the new load. We need to check whether
- // it's still safe to do so, since there may have been DOM mutations
- // or new requests initiated.
- nsCOMPtr<nsIDOMDocument> domDoc;
- viewer->GetDOMDocument(getter_AddRefs(domDoc));
- nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
- mSavingOldViewer = CanSavePresentation(mLoadType, aRequest, doc);
- }
- NS_ASSERTION(!mLoadingURI, "Re-entering unload?");
- nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(aRequest);
- if (aOpenedChannel) {
- aOpenedChannel->GetURI(getter_AddRefs(mLoadingURI));
- }
- FirePageHideNotification(!mSavingOldViewer);
- mLoadingURI = nullptr;
- // Set mFiredUnloadEvent = false so that the unload handler for the
- // *new* document will fire.
- mFiredUnloadEvent = false;
- // we've created a new document so go ahead and call
- // OnLoadingSite(), but don't fire OnLocationChange()
- // notifications before we've called Embed(). See bug 284993.
- mURIResultedInDocument = true;
- if (mLoadType == LOAD_ERROR_PAGE) {
- // We need to set the SH entry and our current URI here and not
- // at the moment we load the page. We want the same behavior
- // of Stop() as for a normal page load. See bug 514232 for details.
- // Revert mLoadType to load type to state the page load failed,
- // following function calls need it.
- mLoadType = mFailedLoadType;
- nsCOMPtr<nsIChannel> failedChannel = mFailedChannel;
- nsIDocument* doc = viewer->GetDocument();
- if (doc) {
- doc->SetFailedChannel(failedChannel);
- }
- // Make sure we have a URI to set currentURI.
- nsCOMPtr<nsIURI> failedURI;
- nsCOMPtr<nsIPrincipal> triggeringPrincipal;
- if (failedChannel) {
- NS_GetFinalChannelURI(failedChannel, getter_AddRefs(failedURI));
- } else {
- // if there is no failed channel we have to explicitly provide
- // a triggeringPrincipal for the history entry.
- triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
- }
- if (!failedURI) {
- failedURI = mFailedURI;
- }
- if (!failedURI) {
- // We need a URI object to store a session history entry, so make up a URI
- NS_NewURI(getter_AddRefs(failedURI), "about:blank");
- }
- // When we don't have failedURI, something wrong will happen. See
- // bug 291876.
- MOZ_ASSERT(failedURI, "We don't have a URI for history APIs.");
- mFailedChannel = nullptr;
- mFailedURI = nullptr;
- // Create an shistory entry for the old load.
- if (failedURI) {
- bool errorOnLocationChangeNeeded = OnNewURI(
- failedURI, failedChannel, triggeringPrincipal,
- nullptr, mLoadType, false, false, false);
- if (errorOnLocationChangeNeeded) {
- FireOnLocationChange(this, failedChannel, failedURI,
- LOCATION_CHANGE_ERROR_PAGE);
- }
- }
- // Be sure to have a correct mLSHE, it may have been cleared by
- // EndPageLoad. See bug 302115.
- if (mSessionHistory && !mLSHE) {
- int32_t idx;
- mSessionHistory->GetRequestedIndex(&idx);
- if (idx == -1) {
- mSessionHistory->GetIndex(&idx);
- }
- mSessionHistory->GetEntryAtIndex(idx, false, getter_AddRefs(mLSHE));
- }
- mLoadType = LOAD_ERROR_PAGE;
- }
- bool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, false);
- // let's try resetting the load group if we need to...
- nsCOMPtr<nsILoadGroup> currentLoadGroup;
- NS_ENSURE_SUCCESS(
- aOpenedChannel->GetLoadGroup(getter_AddRefs(currentLoadGroup)),
- NS_ERROR_FAILURE);
- if (currentLoadGroup != mLoadGroup) {
- nsLoadFlags loadFlags = 0;
- // Cancel any URIs that are currently loading...
- // XXX: Need to do this eventually Stop();
- //
- // Retarget the document to this loadgroup...
- //
- /* First attach the channel to the right loadgroup
- * and then remove from the old loadgroup. This
- * puts the notifications in the right order and
- * we don't null-out mLSHE in OnStateChange() for
- * all redirected urls
- */
- aOpenedChannel->SetLoadGroup(mLoadGroup);
- // Mark the channel as being a document URI...
- aOpenedChannel->GetLoadFlags(&loadFlags);
- loadFlags |= nsIChannel::LOAD_DOCUMENT_URI;
- aOpenedChannel->SetLoadFlags(loadFlags);
- mLoadGroup->AddRequest(aRequest, nullptr);
- if (currentLoadGroup) {
- currentLoadGroup->RemoveRequest(aRequest, nullptr, NS_BINDING_RETARGETED);
- }
- // Update the notification callbacks, so that progress and
- // status information are sent to the right docshell...
- aOpenedChannel->SetNotificationCallbacks(this);
- }
- NS_ENSURE_SUCCESS(Embed(viewer, "", nullptr), NS_ERROR_FAILURE);
- mSavedRefreshURIList = nullptr;
- mSavingOldViewer = false;
- mEODForCurrentDocument = false;
- // if this document is part of a multipart document,
- // the ID can be used to distinguish it from the other parts.
- nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aRequest));
- if (multiPartChannel) {
- nsCOMPtr<nsIPresShell> shell = GetPresShell();
- if (NS_SUCCEEDED(rv) && shell) {
- nsIDocument* doc = shell->GetDocument();
- if (doc) {
- uint32_t partID;
- multiPartChannel->GetPartID(&partID);
- doc->SetPartID(partID);
- }
- }
- }
- // Give hint to native plevent dispatch mechanism. If a document
- // is loading the native plevent dispatch mechanism should favor
- // performance over normal native event dispatch priorities.
- if (++gNumberOfDocumentsLoading == 1) {
- // Hint to favor performance for the plevent notification mechanism.
- // We want the pages to load as fast as possible even if its means
- // native messages might be starved.
- FavorPerformanceHint(true);
- }
- if (onLocationChangeNeeded) {
- FireOnLocationChange(this, aRequest, mCurrentURI, 0);
- }
- return NS_OK;
- }
- nsresult
- nsDocShell::NewContentViewerObj(const nsACString& aContentType,
- nsIRequest* aRequest, nsILoadGroup* aLoadGroup,
- nsIStreamListener** aContentHandler,
- nsIContentViewer** aViewer)
- {
- nsCOMPtr<nsIChannel> aOpenedChannel = do_QueryInterface(aRequest);
- nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
- nsContentUtils::FindInternalContentViewer(aContentType);
- if (!docLoaderFactory) {
- return NS_ERROR_FAILURE;
- }
- // Now create an instance of the content viewer nsLayoutDLF makes the
- // determination if it should be a "view-source" instead of "view"
- nsresult rv = docLoaderFactory->CreateInstance("view",
- aOpenedChannel,
- aLoadGroup, aContentType,
- this,
- nullptr,
- aContentHandler,
- aViewer);
- NS_ENSURE_SUCCESS(rv, rv);
- (*aViewer)->SetContainer(this);
- return NS_OK;
- }
- nsresult
- nsDocShell::SetupNewViewer(nsIContentViewer* aNewViewer)
- {
- //
- // Copy content viewer state from previous or parent content viewer.
- //
- // The following logic is mirrored in nsHTMLDocument::StartDocumentLoad!
- //
- // Do NOT to maintain a reference to the old content viewer outside
- // of this "copying" block, or it will not be destroyed until the end of
- // this routine and all <SCRIPT>s and event handlers fail! (bug 20315)
- //
- // In this block of code, if we get an error result, we return it
- // but if we get a null pointer, that's perfectly legal for parent
- // and parentContentViewer.
- //
- int32_t x = 0;
- int32_t y = 0;
- int32_t cx = 0;
- int32_t cy = 0;
- // This will get the size from the current content viewer or from the
- // Init settings
- DoGetPositionAndSize(&x, &y, &cx, &cy);
- nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
- NS_ENSURE_SUCCESS(GetSameTypeParent(getter_AddRefs(parentAsItem)),
- NS_ERROR_FAILURE);
- nsCOMPtr<nsIDocShell> parent(do_QueryInterface(parentAsItem));
- nsAutoCString forceCharset;
- nsAutoCString hintCharset;
- int32_t hintCharsetSource;
- int32_t minFontSize;
- float textZoom;
- float pageZoom;
- float overrideDPPX;
- bool styleDisabled;
- // |newMUDV| also serves as a flag to set the data from the above vars
- nsCOMPtr<nsIContentViewer> newCv;
- if (mContentViewer || parent) {
- nsCOMPtr<nsIContentViewer> oldCv;
- if (mContentViewer) {
- // Get any interesting state from old content viewer
- // XXX: it would be far better to just reuse the document viewer ,
- // since we know we're just displaying the same document as before
- oldCv = mContentViewer;
- // Tell the old content viewer to hibernate in session history when
- // it is destroyed.
- if (mSavingOldViewer && NS_FAILED(CaptureState())) {
- if (mOSHE) {
- mOSHE->SyncPresentationState();
- }
- mSavingOldViewer = false;
- }
- } else {
- // No old content viewer, so get state from parent's content viewer
- parent->GetContentViewer(getter_AddRefs(oldCv));
- }
- if (oldCv) {
- newCv = aNewViewer;
- if (newCv) {
- NS_ENSURE_SUCCESS(oldCv->GetForceCharacterSet(forceCharset),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(oldCv->GetHintCharacterSet(hintCharset),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(oldCv->GetHintCharacterSetSource(&hintCharsetSource),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(oldCv->GetMinFontSize(&minFontSize),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(oldCv->GetTextZoom(&textZoom),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(oldCv->GetFullZoom(&pageZoom),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(oldCv->GetOverrideDPPX(&overrideDPPX),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(oldCv->GetAuthorStyleDisabled(&styleDisabled),
- NS_ERROR_FAILURE);
- }
- }
- }
- nscolor bgcolor = NS_RGBA(0, 0, 0, 0);
- // Ensure that the content viewer is destroyed *after* the GC - bug 71515
- nsCOMPtr<nsIContentViewer> contentViewer = mContentViewer;
- if (contentViewer) {
- // Stop any activity that may be happening in the old document before
- // releasing it...
- contentViewer->Stop();
- // Try to extract the canvas background color from the old
- // presentation shell, so we can use it for the next document.
- nsCOMPtr<nsIPresShell> shell;
- contentViewer->GetPresShell(getter_AddRefs(shell));
- if (shell) {
- bgcolor = shell->GetCanvasBackground();
- }
- contentViewer->Close(mSavingOldViewer ? mOSHE.get() : nullptr);
- aNewViewer->SetPreviousViewer(contentViewer);
- }
- if (mOSHE && (!mContentViewer || !mSavingOldViewer)) {
- // We don't plan to save a viewer in mOSHE; tell it to drop
- // any other state it's holding.
- mOSHE->SyncPresentationState();
- }
- mContentViewer = nullptr;
- // Now that we're about to switch documents, forget all of our children.
- // Note that we cached them as needed up in CaptureState above.
- DestroyChildren();
- mContentViewer = aNewViewer;
- nsCOMPtr<nsIWidget> widget;
- NS_ENSURE_SUCCESS(GetMainWidget(getter_AddRefs(widget)), NS_ERROR_FAILURE);
- nsIntRect bounds(x, y, cx, cy);
- mContentViewer->SetNavigationTiming(mTiming);
- if (NS_FAILED(mContentViewer->Init(widget, bounds))) {
- nsCOMPtr<nsIContentViewer> viewer = mContentViewer;
- viewer->Close(nullptr);
- viewer->Destroy();
- mContentViewer = nullptr;
- mCurrentURI = nullptr;
- NS_WARNING("ContentViewer Initialization failed");
- return NS_ERROR_FAILURE;
- }
- // If we have old state to copy, set the old state onto the new content
- // viewer
- if (newCv) {
- NS_ENSURE_SUCCESS(newCv->SetForceCharacterSet(forceCharset),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(newCv->SetHintCharacterSet(hintCharset),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(newCv->SetHintCharacterSetSource(hintCharsetSource),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(newCv->SetMinFontSize(minFontSize),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(newCv->SetTextZoom(textZoom),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(newCv->SetFullZoom(pageZoom),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(newCv->SetOverrideDPPX(overrideDPPX),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(newCv->SetAuthorStyleDisabled(styleDisabled),
- NS_ERROR_FAILURE);
- }
- // Stuff the bgcolor from the old pres shell into the new
- // pres shell. This improves page load continuity.
- nsCOMPtr<nsIPresShell> shell;
- mContentViewer->GetPresShell(getter_AddRefs(shell));
- if (shell) {
- shell->SetCanvasBackground(bgcolor);
- }
- // XXX: It looks like the LayoutState gets restored again in Embed()
- // right after the call to SetupNewViewer(...)
- // We don't show the mContentViewer yet, since we want to draw the old page
- // until we have enough of the new page to show. Just return with the new
- // viewer still set to hidden.
- return NS_OK;
- }
- nsresult
- nsDocShell::SetDocCurrentStateObj(nsISHEntry* aShEntry)
- {
- NS_ENSURE_STATE(mContentViewer);
- nsCOMPtr<nsIDocument> document = GetDocument();
- NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
- nsCOMPtr<nsIStructuredCloneContainer> scContainer;
- if (aShEntry) {
- nsresult rv = aShEntry->GetStateData(getter_AddRefs(scContainer));
- NS_ENSURE_SUCCESS(rv, rv);
- // If aShEntry is null, just set the document's state object to null.
- }
- // It's OK for scContainer too be null here; that just means there's no
- // state data associated with this history entry.
- document->SetStateObject(scContainer);
- return NS_OK;
- }
- nsresult
- nsDocShell::CheckLoadingPermissions()
- {
- // This method checks whether the caller may load content into
- // this docshell. Even though we've done our best to hide windows
- // from code that doesn't have the right to access them, it's
- // still possible for an evil site to open a window and access
- // frames in the new window through window.frames[] (which is
- // allAccess for historic reasons), so we still need to do this
- // check on load.
- nsresult rv = NS_OK;
- if (!gValidateOrigin || !IsFrame()) {
- // Origin validation was turned off, or we're not a frame.
- // Permit all loads.
- return rv;
- }
- // Note - The check for a current JSContext here isn't necessarily sensical.
- // It's just designed to preserve the old semantics during a mass-conversion
- // patch.
- if (!nsContentUtils::GetCurrentJSContext()) {
- return NS_OK;
- }
- // Check if the caller is from the same origin as this docshell,
- // or any of its ancestors.
- nsCOMPtr<nsIDocShellTreeItem> item(this);
- do {
- nsCOMPtr<nsIScriptGlobalObject> sgo = do_GetInterface(item);
- nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(sgo));
- nsIPrincipal* p;
- if (!sop || !(p = sop->GetPrincipal())) {
- return NS_ERROR_UNEXPECTED;
- }
- if (nsContentUtils::SubjectPrincipal()->Subsumes(p)) {
- // Same origin, permit load
- return NS_OK;
- }
- nsCOMPtr<nsIDocShellTreeItem> tmp;
- item->GetSameTypeParent(getter_AddRefs(tmp));
- item.swap(tmp);
- } while (item);
- return NS_ERROR_DOM_PROP_ACCESS_DENIED;
- }
- //*****************************************************************************
- // nsDocShell: Site Loading
- //*****************************************************************************
- namespace {
- #ifdef MOZ_PLACES
- // Callback used by CopyFavicon to inform the favicon service that one URI
- // (mNewURI) has the same favicon URI (OnComplete's aFaviconURI) as another.
- class nsCopyFaviconCallback final : public nsIFaviconDataCallback
- {
- public:
- NS_DECL_ISUPPORTS
- nsCopyFaviconCallback(mozIAsyncFavicons* aSvc,
- nsIURI* aNewURI,
- nsIPrincipal* aLoadingPrincipal,
- bool aInPrivateBrowsing)
- : mSvc(aSvc)
- , mNewURI(aNewURI)
- , mLoadingPrincipal(aLoadingPrincipal)
- , mInPrivateBrowsing(aInPrivateBrowsing)
- {
- }
- NS_IMETHOD
- OnComplete(nsIURI* aFaviconURI, uint32_t aDataLen,
- const uint8_t* aData, const nsACString& aMimeType) override
- {
- // Continue only if there is an associated favicon.
- if (!aFaviconURI) {
- return NS_OK;
- }
- MOZ_ASSERT(aDataLen == 0,
- "We weren't expecting the callback to deliver data.");
- nsCOMPtr<mozIPlacesPendingOperation> po;
- return mSvc->SetAndFetchFaviconForPage(
- mNewURI, aFaviconURI, false,
- mInPrivateBrowsing ? nsIFaviconService::FAVICON_LOAD_PRIVATE :
- nsIFaviconService::FAVICON_LOAD_NON_PRIVATE,
- nullptr, mLoadingPrincipal, getter_AddRefs(po));
- }
- private:
- ~nsCopyFaviconCallback() {}
- nsCOMPtr<mozIAsyncFavicons> mSvc;
- nsCOMPtr<nsIURI> mNewURI;
- nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
- bool mInPrivateBrowsing;
- };
- NS_IMPL_ISUPPORTS(nsCopyFaviconCallback, nsIFaviconDataCallback)
- #endif
- } // namespace
- void
- nsDocShell::CopyFavicon(nsIURI* aOldURI,
- nsIURI* aNewURI,
- nsIPrincipal* aLoadingPrincipal,
- bool aInPrivateBrowsing)
- {
- if (XRE_IsContentProcess()) {
- dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
- if (contentChild) {
- mozilla::ipc::URIParams oldURI, newURI;
- SerializeURI(aOldURI, oldURI);
- SerializeURI(aNewURI, newURI);
- contentChild->SendCopyFavicon(oldURI, newURI,
- IPC::Principal(aLoadingPrincipal),
- aInPrivateBrowsing);
- }
- return;
- }
- #ifdef MOZ_PLACES
- nsCOMPtr<mozIAsyncFavicons> favSvc =
- do_GetService("@mozilla.org/browser/favicon-service;1");
- if (favSvc) {
- nsCOMPtr<nsIFaviconDataCallback> callback =
- new nsCopyFaviconCallback(favSvc, aNewURI,
- aLoadingPrincipal,
- aInPrivateBrowsing);
- favSvc->GetFaviconURLForPage(aOldURI, callback);
- }
- #endif
- }
- class InternalLoadEvent : public Runnable
- {
- public:
- InternalLoadEvent(nsDocShell* aDocShell, nsIURI* aURI,
- nsIURI* aOriginalURI, bool aLoadReplace,
- bool aIsFromProcessingFrameAttributes,
- nsIURI* aReferrer, uint32_t aReferrerPolicy,
- nsIPrincipal* aTriggeringPrincipal,
- nsIPrincipal* aPrincipalToInherit, uint32_t aFlags,
- const char* aTypeHint, nsIInputStream* aPostData,
- nsIInputStream* aHeadersData, uint32_t aLoadType,
- nsISHEntry* aSHEntry, bool aFirstParty,
- const nsAString& aSrcdoc, nsIDocShell* aSourceDocShell,
- nsIURI* aBaseURI)
- : mSrcdoc(aSrcdoc)
- , mDocShell(aDocShell)
- , mURI(aURI)
- , mOriginalURI(aOriginalURI)
- , mLoadReplace(aLoadReplace)
- , mIsFromProcessingFrameAttributes(aIsFromProcessingFrameAttributes)
- , mReferrer(aReferrer)
- , mReferrerPolicy(aReferrerPolicy)
- , mTriggeringPrincipal(aTriggeringPrincipal)
- , mPrincipalToInherit(aPrincipalToInherit)
- , mPostData(aPostData)
- , mHeadersData(aHeadersData)
- , mSHEntry(aSHEntry)
- , mFlags(aFlags)
- , mLoadType(aLoadType)
- , mFirstParty(aFirstParty)
- , mSourceDocShell(aSourceDocShell)
- , mBaseURI(aBaseURI)
- {
- // Make sure to keep null things null as needed
- if (aTypeHint) {
- mTypeHint = aTypeHint;
- }
- }
- NS_IMETHOD
- Run() override
- {
- return mDocShell->InternalLoad(mURI, mOriginalURI,
- mLoadReplace,
- mIsFromProcessingFrameAttributes,
- mReferrer,
- mReferrerPolicy,
- mTriggeringPrincipal, mPrincipalToInherit,
- mFlags, EmptyString(), mTypeHint.get(),
- NullString(), mPostData, mHeadersData,
- mLoadType, mSHEntry, mFirstParty,
- mSrcdoc, mSourceDocShell, mBaseURI,
- nullptr, nullptr);
- }
- private:
- // Use IDL strings so .get() returns null by default
- nsXPIDLString mWindowTarget;
- nsXPIDLCString mTypeHint;
- nsString mSrcdoc;
- RefPtr<nsDocShell> mDocShell;
- nsCOMPtr<nsIURI> mURI;
- nsCOMPtr<nsIURI> mOriginalURI;
- bool mLoadReplace;
- bool mIsFromProcessingFrameAttributes;
- nsCOMPtr<nsIURI> mReferrer;
- uint32_t mReferrerPolicy;
- nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
- nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
- nsCOMPtr<nsIInputStream> mPostData;
- nsCOMPtr<nsIInputStream> mHeadersData;
- nsCOMPtr<nsISHEntry> mSHEntry;
- uint32_t mFlags;
- uint32_t mLoadType;
- bool mFirstParty;
- nsCOMPtr<nsIDocShell> mSourceDocShell;
- nsCOMPtr<nsIURI> mBaseURI;
- };
- /**
- * Returns true if we started an asynchronous load (i.e., from the network), but
- * the document we're loading there hasn't yet become this docshell's active
- * document.
- *
- * When JustStartedNetworkLoad is true, you should be careful about modifying
- * mLoadType and mLSHE. These are both set when the asynchronous load first
- * starts, and the load expects that, when it eventually runs InternalLoad,
- * mLoadType and mLSHE will have their original values.
- */
- bool
- nsDocShell::JustStartedNetworkLoad()
- {
- return mDocumentRequest && mDocumentRequest != GetCurrentDocChannel();
- }
- nsresult
- nsDocShell::CreatePrincipalFromReferrer(nsIURI* aReferrer,
- nsIPrincipal** aResult)
- {
- PrincipalOriginAttributes attrs;
- attrs.InheritFromDocShellToDoc(mOriginAttributes, aReferrer);
- nsCOMPtr<nsIPrincipal> prin =
- BasePrincipal::CreateCodebasePrincipal(aReferrer, attrs);
- prin.forget(aResult);
- return *aResult ? NS_OK : NS_ERROR_FAILURE;
- }
- bool
- nsDocShell::IsAboutNewtab(nsIURI* aURI)
- {
- if (!aURI) {
- return false;
- }
- bool isAbout;
- if (NS_WARN_IF(NS_FAILED(aURI->SchemeIs("about", &isAbout)))) {
- return false;
- }
- if (!isAbout) {
- return false;
- }
- nsAutoCString module;
- if (NS_WARN_IF(NS_FAILED(NS_GetAboutModuleName(aURI, module)))) {
- return false;
- }
- return module.Equals("newtab");
- }
- NS_IMETHODIMP
- nsDocShell::InternalLoad(nsIURI* aURI,
- nsIURI* aOriginalURI,
- bool aLoadReplace,
- bool aIsFromProcessingFrameAttributes,
- nsIURI* aReferrer,
- uint32_t aReferrerPolicy,
- nsIPrincipal* aTriggeringPrincipal,
- nsIPrincipal* aPrincipalToInherit,
- uint32_t aFlags,
- const nsAString& aWindowTarget,
- const char* aTypeHint,
- const nsAString& aFileName,
- nsIInputStream* aPostData,
- nsIInputStream* aHeadersData,
- uint32_t aLoadType,
- nsISHEntry* aSHEntry,
- bool aFirstParty,
- const nsAString& aSrcdoc,
- nsIDocShell* aSourceDocShell,
- nsIURI* aBaseURI,
- nsIDocShell** aDocShell,
- nsIRequest** aRequest)
- {
- MOZ_ASSERT(aTriggeringPrincipal, "need a valid TriggeringPrincipal");
- nsresult rv = NS_OK;
- mOriginalUriString.Truncate();
- if (gDocShellLeakLog && MOZ_LOG_TEST(gDocShellLeakLog, LogLevel::Debug)) {
- PR_LogPrint("DOCSHELL %p InternalLoad %s\n",
- this, aURI ? aURI->GetSpecOrDefault().get() : "");
- }
- // Initialize aDocShell/aRequest
- if (aDocShell) {
- *aDocShell = nullptr;
- }
- if (aRequest) {
- *aRequest = nullptr;
- }
- if (!aURI) {
- return NS_ERROR_NULL_POINTER;
- }
- NS_ENSURE_TRUE(IsValidLoadType(aLoadType), NS_ERROR_INVALID_ARG);
- NS_ENSURE_TRUE(!mIsBeingDestroyed, NS_ERROR_NOT_AVAILABLE);
- rv = EnsureScriptEnvironment();
- if (NS_FAILED(rv)) {
- return rv;
- }
- // wyciwyg urls can only be loaded through history. Any normal load of
- // wyciwyg through docshell is illegal. Disallow such loads.
- if (aLoadType & LOAD_CMD_NORMAL) {
- bool isWyciwyg = false;
- rv = aURI->SchemeIs("wyciwyg", &isWyciwyg);
- if ((isWyciwyg && NS_SUCCEEDED(rv)) || NS_FAILED(rv)) {
- return NS_ERROR_FAILURE;
- }
- }
- bool isJavaScript = false;
- if (NS_FAILED(aURI->SchemeIs("javascript", &isJavaScript))) {
- isJavaScript = false;
- }
- bool isTargetTopLevelDocShell = false;
- nsCOMPtr<nsIDocShell> targetDocShell;
- if (!aWindowTarget.IsEmpty()) {
- // Locate the target DocShell.
- nsCOMPtr<nsIDocShellTreeItem> targetItem;
- // Only _self, _parent, and _top are supported in noopener case. But we
- // have to be careful to not apply that to the noreferrer case. See bug
- // 1358469.
- bool allowNamedTarget = !(aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) ||
- (aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER);
- if (allowNamedTarget ||
- aWindowTarget.LowerCaseEqualsLiteral("_self") ||
- aWindowTarget.LowerCaseEqualsLiteral("_parent") ||
- aWindowTarget.LowerCaseEqualsLiteral("_top")) {
- rv = FindItemWithName(aWindowTarget, nullptr, this,
- getter_AddRefs(targetItem));
- NS_ENSURE_SUCCESS(rv, rv);
- }
- targetDocShell = do_QueryInterface(targetItem);
- if (targetDocShell) {
- // If the targetDocShell and the rootDocShell are the same, then the
- // targetDocShell is the top level document and hence we should
- // consider this TYPE_DOCUMENT
- //
- // For example:
- // 1. target="_top"
- // 2. target="_parent", where this docshell is in the 2nd level of
- // docshell tree.
- nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
- targetDocShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
- NS_ASSERTION(sameTypeRoot,
- "No document shell root tree item from targetDocShell!");
- nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(sameTypeRoot);
- NS_ASSERTION(rootShell,
- "No root docshell from document shell root tree item.");
- isTargetTopLevelDocShell = targetDocShell == rootShell;
- } else {
- // If the targetDocShell doesn't exist, then this is a new docShell
- // and we should consider this a TYPE_DOCUMENT load
- //
- // For example, when target="_blank"
- isTargetTopLevelDocShell = true;
- }
- }
- // The contentType will be INTERNAL_(I)FRAME if:
- // 1. This docshell is for iframe.
- // 2. AND aWindowTarget is not a new window, nor a top-level window.
- //
- // This variable will be used when we call NS_CheckContentLoadPolicy, and
- // later when we call DoURILoad.
- uint32_t contentType;
- if (IsFrame() && !isTargetTopLevelDocShell) {
- nsCOMPtr<Element> requestingElement =
- mScriptGlobal->AsOuter()->GetFrameElementInternal();
- if (requestingElement) {
- contentType = requestingElement->IsHTMLElement(nsGkAtoms::iframe) ?
- nsIContentPolicy::TYPE_INTERNAL_IFRAME : nsIContentPolicy::TYPE_INTERNAL_FRAME;
- } else {
- // If we have lost our frame element by now, just assume we're
- // an iframe since that's more common.
- contentType = nsIContentPolicy::TYPE_INTERNAL_IFRAME;
- }
- } else {
- contentType = nsIContentPolicy::TYPE_DOCUMENT;
- }
- // If there's no targetDocShell, that means we are about to create a new
- // window (or aWindowTarget is empty). Perform a content policy check before
- // creating the window. Please note for all other docshell loads
- // content policy checks are performed within the contentSecurityManager
- // when the channel is about to be openend.
- if (!targetDocShell && !aWindowTarget.IsEmpty()) {
- MOZ_ASSERT(contentType == nsIContentPolicy::TYPE_DOCUMENT,
- "opening a new window requires type to be TYPE_DOCUMENT");
- nsISupports* requestingContext = nullptr;
- if (XRE_IsContentProcess()) {
- // In e10s the child process doesn't have access to the element that
- // contains the browsing context (because that element is in the chrome
- // process). So we just pass mScriptGlobal.
- requestingContext = ToSupports(mScriptGlobal);
- } else {
- // This is for loading non-e10s tabs and toplevel windows of various
- // sorts.
- // For the toplevel window cases, requestingElement will be null.
- nsCOMPtr<Element> requestingElement =
- mScriptGlobal->AsOuter()->GetFrameElementInternal();
- requestingContext = requestingElement;
- }
- // Since Content Policy checks are performed within docShell as well as
- // the ContentSecurityManager we need a reliable way to let certain
- // nsIContentPolicy consumers ignore duplicate calls. Let's use the 'extra'
- // argument to pass a specific identifier.
- nsCOMPtr<nsISupportsString> extraStr =
- do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- NS_NAMED_LITERAL_STRING(msg, "conPolCheckFromDocShell");
- rv = extraStr->SetData(msg);
- NS_ENSURE_SUCCESS(rv, rv);
- int16_t shouldLoad = nsIContentPolicy::ACCEPT;
- rv = NS_CheckContentLoadPolicy(contentType,
- aURI,
- aTriggeringPrincipal,
- requestingContext,
- EmptyCString(), // mime guess
- extraStr, // extra
- &shouldLoad);
- if (NS_FAILED(rv) || NS_CP_REJECTED(shouldLoad)) {
- if (NS_SUCCEEDED(rv) && shouldLoad == nsIContentPolicy::REJECT_TYPE) {
- return NS_ERROR_CONTENT_BLOCKED_SHOW_ALT;
- }
- return NS_ERROR_CONTENT_BLOCKED;
- }
- }
- nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit;
- //
- // Get a principal from the current document if necessary. Note that we only
- // do this for URIs that inherit a security context and local file URIs;
- // in particular we do NOT do this for about:blank. This way, random
- // about:blank loads that have no principal (which basically means they were
- // done by someone from chrome manually messing with our nsIWebNavigation
- // or by C++ setting document.location) don't get a funky principal. If
- // callers want something interesting to happen with the about:blank
- // principal in this case, they should pass aPrincipalToInherit in.
- //
- {
- bool inherits;
- // One more twist: Don't inherit the principal for external loads.
- if (aLoadType != LOAD_NORMAL_EXTERNAL && !principalToInherit &&
- (aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL) &&
- NS_SUCCEEDED(nsContentUtils::URIInheritsSecurityContext(aURI,
- &inherits)) &&
- inherits) {
- principalToInherit = GetInheritedPrincipal(true);
- }
- }
- // Don't allow loads that would inherit our security context
- // if this document came from an unsafe channel.
- {
- bool willInherit;
- // This condition needs to match the one in
- // nsContentUtils::ChannelShouldInheritPrincipal.
- // Except we reverse the rv check to be safe in case
- // nsContentUtils::URIInheritsSecurityContext fails here and
- // succeeds there.
- rv = nsContentUtils::URIInheritsSecurityContext(aURI, &willInherit);
- if (NS_FAILED(rv) || willInherit || NS_IsAboutBlank(aURI)) {
- nsCOMPtr<nsIDocShellTreeItem> treeItem = this;
- do {
- nsCOMPtr<nsIDocShell> itemDocShell = do_QueryInterface(treeItem);
- bool isUnsafe;
- if (itemDocShell &&
- NS_SUCCEEDED(itemDocShell->GetChannelIsUnsafe(&isUnsafe)) &&
- isUnsafe) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- nsCOMPtr<nsIDocShellTreeItem> parent;
- treeItem->GetSameTypeParent(getter_AddRefs(parent));
- parent.swap(treeItem);
- } while (treeItem);
- }
- }
- //
- // Resolve the window target before going any further...
- // If the load has been targeted to another DocShell, then transfer the
- // load to it...
- //
- if (!aWindowTarget.IsEmpty()) {
- // We've already done our owner-inheriting. Mask out that bit, so we
- // don't try inheriting an owner from the target window if we came up
- // with a null owner above.
- aFlags = aFlags & ~INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL;
- bool isNewWindow = false;
- if (!targetDocShell) {
- // If the docshell's document is sandboxed, only open a new window
- // if the document's SANDBOXED_AUXILLARY_NAVIGATION flag is not set.
- // (i.e. if allow-popups is specified)
- NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
- nsIDocument* doc = mContentViewer->GetDocument();
- uint32_t sandboxFlags = 0;
- if (doc) {
- sandboxFlags = doc->GetSandboxFlags();
- if (sandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION) {
- return NS_ERROR_DOM_INVALID_ACCESS_ERR;
- }
- }
- nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
- NS_ENSURE_TRUE(win, NS_ERROR_NOT_AVAILABLE);
- nsCOMPtr<nsPIDOMWindowOuter> newWin;
- nsAutoCString spec;
- if (aURI) {
- aURI->GetSpec(spec);
- }
- // If we are a noopener load, we just hand the whole thing over to our
- // window.
- if (aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) {
- // Various asserts that we know to hold because NO_OPENER loads can only
- // happen for links.
- MOZ_ASSERT(!aLoadReplace);
- MOZ_ASSERT(aPrincipalToInherit == aTriggeringPrincipal);
- MOZ_ASSERT(aFlags == INTERNAL_LOAD_FLAGS_NO_OPENER ||
- aFlags == (INTERNAL_LOAD_FLAGS_NO_OPENER |
- INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
- MOZ_ASSERT(!aPostData);
- MOZ_ASSERT(!aHeadersData);
- MOZ_ASSERT(aLoadType == LOAD_LINK);
- MOZ_ASSERT(!aSHEntry);
- MOZ_ASSERT(aFirstParty); // Windowwatcher will assume this.
- nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
- rv = CreateLoadInfo(getter_AddRefs(loadInfo));
- if (NS_FAILED(rv)) {
- return rv;
- }
- // Set up our loadinfo so it will do the load as much like we would have
- // as possible.
- loadInfo->SetReferrer(aReferrer);
- loadInfo->SetReferrerPolicy(aReferrerPolicy);
- loadInfo->SetSendReferrer(!(aFlags &
- INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER));
- loadInfo->SetOriginalURI(aOriginalURI);
- loadInfo->SetLoadReplace(aLoadReplace);
- loadInfo->SetIsFromProcessingFrameAttributes(aIsFromProcessingFrameAttributes);
- loadInfo->SetTriggeringPrincipal(aTriggeringPrincipal);
- loadInfo->SetInheritPrincipal(
- aFlags & INTERNAL_LOAD_FLAGS_INHERIT_PRINCIPAL);
- // Explicit principal because we do not want any guesses as to what the
- // principal to inherit is: it should be aTriggeringPrincipal.
- loadInfo->SetPrincipalIsExplicit(true);
- loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(LOAD_LINK));
- loadInfo->SetForceAllowDataURI(aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI);
- rv = win->Open(NS_ConvertUTF8toUTF16(spec),
- aWindowTarget, // window name
- EmptyString(), // Features
- loadInfo,
- true, // aForceNoOpener
- getter_AddRefs(newWin));
- MOZ_ASSERT(!newWin);
- return rv;
- }
- rv = win->OpenNoNavigate(NS_ConvertUTF8toUTF16(spec),
- aWindowTarget, // window name
- EmptyString(), // Features
- getter_AddRefs(newWin));
- // In some cases the Open call doesn't actually result in a new
- // window being opened. We can detect these cases by examining the
- // document in |newWin|, if any.
- nsCOMPtr<nsPIDOMWindowOuter> piNewWin = do_QueryInterface(newWin);
- if (piNewWin) {
- nsCOMPtr<nsIDocument> newDoc = piNewWin->GetExtantDoc();
- if (!newDoc || newDoc->IsInitialDocument()) {
- isNewWindow = true;
- aFlags |= INTERNAL_LOAD_FLAGS_FIRST_LOAD;
- }
- }
- nsCOMPtr<nsIWebNavigation> webNav = do_GetInterface(newWin);
- targetDocShell = do_QueryInterface(webNav);
- }
- //
- // Transfer the load to the target DocShell... Pass nullptr as the
- // window target name from to prevent recursive retargeting!
- //
- if (NS_SUCCEEDED(rv) && targetDocShell) {
- rv = targetDocShell->InternalLoad(aURI,
- aOriginalURI,
- aLoadReplace,
- aIsFromProcessingFrameAttributes,
- aReferrer,
- aReferrerPolicy,
- aTriggeringPrincipal,
- principalToInherit,
- aFlags,
- EmptyString(), // No window target
- aTypeHint,
- NullString(), // No forced download
- aPostData,
- aHeadersData,
- aLoadType,
- aSHEntry,
- aFirstParty,
- aSrcdoc,
- aSourceDocShell,
- aBaseURI,
- aDocShell,
- aRequest);
- if (rv == NS_ERROR_NO_CONTENT) {
- // XXXbz except we never reach this code!
- if (isNewWindow) {
- //
- // At this point, a new window has been created, but the
- // URI did not have any data associated with it...
- //
- // So, the best we can do, is to tear down the new window
- // that was just created!
- //
- if (nsCOMPtr<nsPIDOMWindowOuter> domWin = targetDocShell->GetWindow()) {
- domWin->Close();
- }
- }
- //
- // NS_ERROR_NO_CONTENT should not be returned to the
- // caller... This is an internal error code indicating that
- // the URI had no data associated with it - probably a
- // helper-app style protocol (ie. mailto://)
- //
- rv = NS_OK;
- } else if (isNewWindow) {
- // XXX: Once new windows are created hidden, the new
- // window will need to be made visible... For now,
- // do nothing.
- }
- }
- // Else we ran out of memory, or were a popup and got blocked,
- // or something.
- return rv;
- }
- //
- // Load is being targetted at this docshell so return an error if the
- // docshell is in the process of being destroyed.
- //
- if (mIsBeingDestroyed) {
- return NS_ERROR_FAILURE;
- }
- NS_ENSURE_STATE(!HasUnloadedParent());
- rv = CheckLoadingPermissions();
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (mFiredUnloadEvent) {
- if (IsOKToLoadURI(aURI)) {
- NS_PRECONDITION(aWindowTarget.IsEmpty(),
- "Shouldn't have a window target here!");
- // If this is a replace load, make whatever load triggered
- // the unload event also a replace load, so we don't
- // create extra history entries.
- if (LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
- mLoadType = LOAD_NORMAL_REPLACE;
- }
- // Do this asynchronously
- nsCOMPtr<nsIRunnable> ev =
- new InternalLoadEvent(this, aURI, aOriginalURI, aLoadReplace,
- aIsFromProcessingFrameAttributes,
- aReferrer, aReferrerPolicy,
- aTriggeringPrincipal, principalToInherit,
- aFlags, aTypeHint, aPostData, aHeadersData,
- aLoadType, aSHEntry, aFirstParty, aSrcdoc,
- aSourceDocShell, aBaseURI);
- return NS_DispatchToCurrentThread(ev);
- }
- // Just ignore this load attempt
- return NS_OK;
- }
- // If a source docshell has been passed, check to see if we are sandboxed
- // from it as the result of an iframe or CSP sandbox.
- if (aSourceDocShell && aSourceDocShell->IsSandboxedFrom(this)) {
- return NS_ERROR_DOM_INVALID_ACCESS_ERR;
- }
- // If this docshell is owned by a frameloader, make sure to cancel
- // possible frameloader initialization before loading a new page.
- nsCOMPtr<nsIDocShellTreeItem> parent = GetParentDocshell();
- if (parent) {
- nsCOMPtr<nsIDocument> doc = parent->GetDocument();
- if (doc) {
- doc->TryCancelFrameLoaderInitialization(this);
- }
- }
- bool loadFromExternal = false;
- // Before going any further vet loads initiated by external programs.
- if (aLoadType == LOAD_NORMAL_EXTERNAL) {
- loadFromExternal = true;
- // Disallow external chrome: loads targetted at content windows
- bool isChrome = false;
- if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) {
- NS_WARNING("blocked external chrome: url -- use '--chrome' option");
- return NS_ERROR_FAILURE;
- }
- // clear the decks to prevent context bleed-through (bug 298255)
- rv = CreateAboutBlankContentViewer(nullptr, nullptr);
- if (NS_FAILED(rv)) {
- return NS_ERROR_FAILURE;
- }
- // reset loadType so we don't have to add lots of tests for
- // LOAD_NORMAL_EXTERNAL after this point
- aLoadType = LOAD_NORMAL;
- }
- mAllowKeywordFixup =
- (aFlags & INTERNAL_LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) != 0;
- mURIResultedInDocument = false; // reset the clock...
- if (aLoadType == LOAD_NORMAL ||
- aLoadType == LOAD_STOP_CONTENT ||
- LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
- aLoadType == LOAD_HISTORY ||
- aLoadType == LOAD_LINK) {
- nsCOMPtr<nsIURI> currentURI = mCurrentURI;
- nsAutoCString curHash, newHash;
- bool curURIHasRef = false, newURIHasRef = false;
- nsresult rvURINew = aURI->GetRef(newHash);
- if (NS_SUCCEEDED(rvURINew)) {
- rvURINew = aURI->GetHasRef(&newURIHasRef);
- }
- bool sameExceptHashes = false;
- if (currentURI && NS_SUCCEEDED(rvURINew)) {
- nsresult rvURIOld = currentURI->GetRef(curHash);
- if (NS_SUCCEEDED(rvURIOld)) {
- rvURIOld = currentURI->GetHasRef(&curURIHasRef);
- }
- if (NS_SUCCEEDED(rvURIOld)) {
- if (NS_FAILED(currentURI->EqualsExceptRef(aURI, &sameExceptHashes))) {
- sameExceptHashes = false;
- }
- }
- }
- if (!sameExceptHashes && sURIFixup && currentURI &&
- NS_SUCCEEDED(rvURINew)) {
- // Maybe aURI came from the exposable form of currentURI?
- nsCOMPtr<nsIURI> currentExposableURI;
- rv = sURIFixup->CreateExposableURI(currentURI,
- getter_AddRefs(currentExposableURI));
- NS_ENSURE_SUCCESS(rv, rv);
- nsresult rvURIOld = currentExposableURI->GetRef(curHash);
- if (NS_SUCCEEDED(rvURIOld)) {
- rvURIOld = currentExposableURI->GetHasRef(&curURIHasRef);
- }
- if (NS_SUCCEEDED(rvURIOld)) {
- if (NS_FAILED(currentExposableURI->EqualsExceptRef(aURI, &sameExceptHashes))) {
- sameExceptHashes = false;
- }
- }
- }
- bool historyNavBetweenSameDoc = false;
- if (mOSHE && aSHEntry) {
- // We're doing a history load.
- mOSHE->SharesDocumentWith(aSHEntry, &historyNavBetweenSameDoc);
- #ifdef DEBUG
- if (historyNavBetweenSameDoc) {
- nsCOMPtr<nsIInputStream> currentPostData;
- mOSHE->GetPostData(getter_AddRefs(currentPostData));
- NS_ASSERTION(currentPostData == aPostData,
- "Different POST data for entries for the same page?");
- }
- #endif
- }
- // A short-circuited load happens when we navigate between two SHEntries
- // for the same document. We do a short-circuited load under two
- // circumstances. Either
- //
- // a) we're navigating between two different SHEntries which share a
- // document, or
- //
- // b) we're navigating to a new shentry whose URI differs from the
- // current URI only in its hash, the new hash is non-empty, and
- // we're not doing a POST.
- //
- // The restriction tha the SHEntries in (a) must be different ensures
- // that history.go(0) and the like trigger full refreshes, rather than
- // short-circuited loads.
- bool doShortCircuitedLoad =
- (historyNavBetweenSameDoc && mOSHE != aSHEntry) ||
- (!aSHEntry && !aPostData &&
- sameExceptHashes && newURIHasRef);
- if (doShortCircuitedLoad) {
- // Save the position of the scrollers.
- nscoord cx = 0, cy = 0;
- GetCurScrollPos(ScrollOrientation_X, &cx);
- GetCurScrollPos(ScrollOrientation_Y, &cy);
- // Reset mLoadType to its original value once we exit this block,
- // because this short-circuited load might have started after a
- // normal, network load, and we don't want to clobber its load type.
- // See bug 737307.
- AutoRestore<uint32_t> loadTypeResetter(mLoadType);
- // If a non-short-circuit load (i.e., a network load) is pending,
- // make this a replacement load, so that we don't add a SHEntry here
- // and the network load goes into the SHEntry it expects to.
- if (JustStartedNetworkLoad() && (aLoadType & LOAD_CMD_NORMAL)) {
- mLoadType = LOAD_NORMAL_REPLACE;
- } else {
- mLoadType = aLoadType;
- }
- mURIResultedInDocument = true;
- nsCOMPtr<nsISHEntry> oldLSHE = mLSHE;
- /* we need to assign mLSHE to aSHEntry right here, so that on History
- * loads, SetCurrentURI() called from OnNewURI() will send proper
- * onLocationChange() notifications to the browser to update
- * back/forward buttons.
- */
- SetHistoryEntry(&mLSHE, aSHEntry);
- // Set the doc's URI according to the new history entry's URI.
- nsCOMPtr<nsIDocument> doc = GetDocument();
- NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
- doc->SetDocumentURI(aURI);
- /* This is a anchor traversal with in the same page.
- * call OnNewURI() so that, this traversal will be
- * recorded in session and global history.
- */
- nsCOMPtr<nsIPrincipal> newURITriggeringPrincipal, newURIPrincipalToInherit;
- if (mOSHE) {
- mOSHE->GetTriggeringPrincipal(getter_AddRefs(newURITriggeringPrincipal));
- mOSHE->GetPrincipalToInherit(getter_AddRefs(newURIPrincipalToInherit));
- } else {
- newURITriggeringPrincipal = aTriggeringPrincipal;
- newURIPrincipalToInherit = doc->NodePrincipal();
- }
- // Pass true for aCloneSHChildren, since we're not
- // changing documents here, so all of our subframes are
- // still relevant to the new session history entry.
- //
- // It also makes OnNewURI(...) set LOCATION_CHANGE_SAME_DOCUMENT
- // flag on firing onLocationChange(...).
- // Anyway, aCloneSHChildren param is simply reflecting
- // doShortCircuitedLoad in this scope.
- OnNewURI(aURI, nullptr, newURITriggeringPrincipal, newURIPrincipalToInherit,
- mLoadType, true, true, true);
- nsCOMPtr<nsIInputStream> postData;
- nsCOMPtr<nsISupports> cacheKey;
- bool scrollRestorationIsManual = false;
- if (mOSHE) {
- /* save current position of scroller(s) (bug 59774) */
- mOSHE->SetScrollPosition(cx, cy);
- mOSHE->GetScrollRestorationIsManual(&scrollRestorationIsManual);
- // Get the postdata and page ident from the current page, if
- // the new load is being done via normal means. Note that
- // "normal means" can be checked for just by checking for
- // LOAD_CMD_NORMAL, given the loadType and allowScroll check
- // above -- it filters out some LOAD_CMD_NORMAL cases that we
- // wouldn't want here.
- if (aLoadType & LOAD_CMD_NORMAL) {
- mOSHE->GetPostData(getter_AddRefs(postData));
- mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
- // Link our new SHEntry to the old SHEntry's back/forward
- // cache data, since the two SHEntries correspond to the
- // same document.
- if (mLSHE) {
- if (!aSHEntry) {
- // If we're not doing a history load, scroll restoration
- // should be inherited from the previous session history entry.
- mLSHE->SetScrollRestorationIsManual(scrollRestorationIsManual);
- }
- mLSHE->AdoptBFCacheEntry(mOSHE);
- }
- }
- }
- // If we're doing a history load, use its scroll restoration state.
- if (aSHEntry) {
- aSHEntry->GetScrollRestorationIsManual(&scrollRestorationIsManual);
- }
- /* Assign mOSHE to mLSHE. This will either be a new entry created
- * by OnNewURI() for normal loads or aSHEntry for history loads.
- */
- if (mLSHE) {
- SetHistoryEntry(&mOSHE, mLSHE);
- // Save the postData obtained from the previous page
- // in to the session history entry created for the
- // anchor page, so that any history load of the anchor
- // page will restore the appropriate postData.
- if (postData) {
- mOSHE->SetPostData(postData);
- }
- // Make sure we won't just repost without hitting the
- // cache first
- if (cacheKey) {
- mOSHE->SetCacheKey(cacheKey);
- }
- }
- /* Restore the original LSHE if we were loading something
- * while short-circuited load was initiated.
- */
- SetHistoryEntry(&mLSHE, oldLSHE);
- /* Set the title for the SH entry for this target url. so that
- * SH menus in go/back/forward buttons won't be empty for this.
- */
- if (mSessionHistory) {
- int32_t index = -1;
- mSessionHistory->GetIndex(&index);
- nsCOMPtr<nsISHEntry> shEntry;
- mSessionHistory->GetEntryAtIndex(index, false, getter_AddRefs(shEntry));
- NS_ENSURE_TRUE(shEntry, NS_ERROR_FAILURE);
- shEntry->SetTitle(mTitle);
- }
- /* Set the title for the Global History entry for this anchor url.
- */
- if (mUseGlobalHistory && !UsePrivateBrowsing()) {
- nsCOMPtr<IHistory> history = services::GetHistoryService();
- if (history) {
- history->SetURITitle(aURI, mTitle);
- } else if (mGlobalHistory) {
- mGlobalHistory->SetPageTitle(aURI, mTitle);
- }
- }
- SetDocCurrentStateObj(mOSHE);
- // Inform the favicon service that the favicon for oldURI also
- // applies to aURI.
- CopyFavicon(currentURI, aURI, doc->NodePrincipal(), UsePrivateBrowsing());
- RefPtr<nsGlobalWindow> scriptGlobal = mScriptGlobal;
- RefPtr<nsGlobalWindow> win = scriptGlobal ?
- scriptGlobal->GetCurrentInnerWindowInternal() : nullptr;
- // ScrollToAnchor doesn't necessarily cause us to scroll the window;
- // the function decides whether a scroll is appropriate based on the
- // arguments it receives. But even if we don't end up scrolling,
- // ScrollToAnchor performs other important tasks, such as informing
- // the presShell that we have a new hash. See bug 680257.
- rv = ScrollToAnchor(curURIHasRef, newURIHasRef, newHash, aLoadType);
- NS_ENSURE_SUCCESS(rv, rv);
- /* restore previous position of scroller(s), if we're moving
- * back in history (bug 59774)
- */
- nscoord bx = 0;
- nscoord by = 0;
- bool needsScrollPosUpdate = false;
- if (mOSHE && (aLoadType == LOAD_HISTORY ||
- aLoadType == LOAD_RELOAD_NORMAL) &&
- !scrollRestorationIsManual) {
- needsScrollPosUpdate = true;
- mOSHE->GetScrollPosition(&bx, &by);
- }
- // Dispatch the popstate and hashchange events, as appropriate.
- //
- // The event dispatch below can cause us to re-enter script and
- // destroy the docshell, nulling out mScriptGlobal. Hold a stack
- // reference to avoid null derefs. See bug 914521.
- if (win) {
- // Fire a hashchange event URIs differ, and only in their hashes.
- bool doHashchange = sameExceptHashes &&
- (curURIHasRef != newURIHasRef || !curHash.Equals(newHash));
- if (historyNavBetweenSameDoc || doHashchange) {
- win->DispatchSyncPopState();
- }
- if (needsScrollPosUpdate && win->AsInner()->HasActiveDocument()) {
- SetCurScrollPosEx(bx, by);
- }
- if (doHashchange) {
- // Note that currentURI hasn't changed because it's on the
- // stack, so we can just use it directly as the old URI.
- win->DispatchAsyncHashchange(currentURI, aURI);
- }
- }
- return NS_OK;
- }
- }
- // mContentViewer->PermitUnload can destroy |this| docShell, which
- // causes the next call of CanSavePresentation to crash.
- // Hold onto |this| until we return, to prevent a crash from happening.
- // (bug#331040)
- nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
- // Don't init timing for javascript:, since it generally doesn't
- // actually start a load or anything. If it does, we'll init
- // timing then, from OnStateChange.
- // XXXbz mTiming should know what channel it's for, so we don't
- // need this hackery. Note that this is still broken in cases
- // when we're loading something that's not javascript: and the
- // beforeunload handler denies the load. That will screw up
- // timing for the next load!
- if (!isJavaScript) {
- MaybeInitTiming();
- }
- bool timeBeforeUnload = aFileName.IsVoid();
- if (mTiming && timeBeforeUnload) {
- mTiming->NotifyBeforeUnload();
- }
- // Check if the page doesn't want to be unloaded. The javascript:
- // protocol handler deals with this for javascript: URLs.
- if (!isJavaScript && aFileName.IsVoid() && mContentViewer) {
- bool okToUnload;
- rv = mContentViewer->PermitUnload(&okToUnload);
- if (NS_SUCCEEDED(rv) && !okToUnload) {
- // The user chose not to unload the page, interrupt the
- // load.
- return NS_OK;
- }
- }
- if (mTiming && timeBeforeUnload) {
- mTiming->NotifyUnloadAccepted(mCurrentURI);
- }
- // Check if the webbrowser chrome wants the load to proceed; this can be
- // used to cancel attempts to load URIs in the wrong process.
- nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
- if (browserChrome3) {
- // In case this is a remote newtab load, set aURI to aOriginalURI (newtab).
- // This ensures that the verifySignedContent flag is set on loadInfo in
- // DoURILoad.
- nsIURI* uriForShouldLoadCheck = aURI;
- if (IsAboutNewtab(aOriginalURI)) {
- uriForShouldLoadCheck = aOriginalURI;
- }
- bool shouldLoad;
- rv = browserChrome3->ShouldLoadURI(this, uriForShouldLoadCheck, aReferrer,
- aTriggeringPrincipal, &shouldLoad);
- if (NS_SUCCEEDED(rv) && !shouldLoad) {
- return NS_OK;
- }
- }
- // Whenever a top-level browsing context is navigated, the user agent MUST
- // lock the orientation of the document to the document's default
- // orientation. We don't explicitly check for a top-level browsing context
- // here because orientation is only set on top-level browsing contexts.
- // We make an exception for apps because they currently rely on
- // orientation locks persisting across browsing contexts.
- if (OrientationLock() != eScreenOrientation_None && !GetIsApp()) {
- #ifdef DEBUG
- nsCOMPtr<nsIDocShellTreeItem> parent;
- GetSameTypeParent(getter_AddRefs(parent));
- MOZ_ASSERT(!parent);
- #endif
- SetOrientationLock(eScreenOrientation_None);
- if (mIsActive) {
- ScreenOrientation::UpdateActiveOrientationLock(eScreenOrientation_None);
- }
- }
- // Check for saving the presentation here, before calling Stop().
- // This is necessary so that we can catch any pending requests.
- // Since the new request has not been created yet, we pass null for the
- // new request parameter.
- // Also pass nullptr for the document, since it doesn't affect the return
- // value for our purposes here.
- bool savePresentation = CanSavePresentation(aLoadType, nullptr, nullptr);
- // Don't stop current network activity for javascript: URL's since
- // they might not result in any data, and thus nothing should be
- // stopped in those cases. In the case where they do result in
- // data, the javascript: URL channel takes care of stopping
- // current network activity.
- if (!isJavaScript && aFileName.IsVoid()) {
- // Stop any current network activity.
- // Also stop content if this is a zombie doc. otherwise
- // the onload will be delayed by other loads initiated in the
- // background by the first document that
- // didn't fully load before the next load was initiated.
- // If not a zombie, don't stop content until data
- // starts arriving from the new URI...
- nsCOMPtr<nsIContentViewer> zombieViewer;
- if (mContentViewer) {
- mContentViewer->GetPreviousViewer(getter_AddRefs(zombieViewer));
- }
- if (zombieViewer ||
- LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_STOP_CONTENT)) {
- rv = Stop(nsIWebNavigation::STOP_ALL);
- } else {
- rv = Stop(nsIWebNavigation::STOP_NETWORK);
- }
- if (NS_FAILED(rv)) {
- return rv;
- }
- }
- mLoadType = aLoadType;
- // mLSHE should be assigned to aSHEntry, only after Stop() has
- // been called. But when loading an error page, do not clear the
- // mLSHE for the real page.
- if (mLoadType != LOAD_ERROR_PAGE) {
- SetHistoryEntry(&mLSHE, aSHEntry);
- }
- mSavingOldViewer = savePresentation;
- // If we have a saved content viewer in history, restore and show it now.
- if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) {
- // Make sure our history ID points to the same ID as
- // SHEntry's docshell ID.
- aSHEntry->GetDocshellID(&mHistoryID);
- // It's possible that the previous viewer of mContentViewer is the
- // viewer that will end up in aSHEntry when it gets closed. If that's
- // the case, we need to go ahead and force it into its shentry so we
- // can restore it.
- if (mContentViewer) {
- nsCOMPtr<nsIContentViewer> prevViewer;
- mContentViewer->GetPreviousViewer(getter_AddRefs(prevViewer));
- if (prevViewer) {
- #ifdef DEBUG
- nsCOMPtr<nsIContentViewer> prevPrevViewer;
- prevViewer->GetPreviousViewer(getter_AddRefs(prevPrevViewer));
- NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here");
- #endif
- nsCOMPtr<nsISHEntry> viewerEntry;
- prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry));
- if (viewerEntry == aSHEntry) {
- // Make sure this viewer ends up in the right place
- mContentViewer->SetPreviousViewer(nullptr);
- prevViewer->Destroy();
- }
- }
- }
- nsCOMPtr<nsISHEntry> oldEntry = mOSHE;
- bool restoring;
- rv = RestorePresentation(aSHEntry, &restoring);
- if (restoring) {
- return rv;
- }
- // We failed to restore the presentation, so clean up.
- // Both the old and new history entries could potentially be in
- // an inconsistent state.
- if (NS_FAILED(rv)) {
- if (oldEntry) {
- oldEntry->SyncPresentationState();
- }
- aSHEntry->SyncPresentationState();
- }
- }
- nsAutoString srcdoc;
- if (aFlags & INTERNAL_LOAD_FLAGS_IS_SRCDOC) {
- srcdoc = aSrcdoc;
- } else {
- srcdoc = NullString();
- }
- net::PredictorLearn(aURI, nullptr,
- nsINetworkPredictor::LEARN_LOAD_TOPLEVEL, this);
- net::PredictorPredict(aURI, nullptr,
- nsINetworkPredictor::PREDICT_LOAD, this, nullptr);
- nsCOMPtr<nsIRequest> req;
- rv = DoURILoad(aURI, aOriginalURI, aLoadReplace,
- aIsFromProcessingFrameAttributes, loadFromExternal,
- (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_DATA_URI),
- aReferrer,
- !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER),
- aReferrerPolicy,
- aTriggeringPrincipal, principalToInherit, aTypeHint,
- aFileName, aPostData, aHeadersData,
- aFirstParty, aDocShell, getter_AddRefs(req),
- (aFlags & INTERNAL_LOAD_FLAGS_FIRST_LOAD) != 0,
- (aFlags & INTERNAL_LOAD_FLAGS_BYPASS_CLASSIFIER) != 0,
- (aFlags & INTERNAL_LOAD_FLAGS_FORCE_ALLOW_COOKIES) != 0,
- srcdoc, aBaseURI, contentType);
- if (req && aRequest) {
- NS_ADDREF(*aRequest = req);
- }
- if (NS_FAILED(rv)) {
- nsCOMPtr<nsIChannel> chan(do_QueryInterface(req));
- if (DisplayLoadError(rv, aURI, nullptr, chan) &&
- (aFlags & LOAD_FLAGS_ERROR_LOAD_CHANGES_RV) != 0) {
- return NS_ERROR_LOAD_SHOWED_ERRORPAGE;
- }
- }
- return rv;
- }
- nsIPrincipal*
- nsDocShell::GetInheritedPrincipal(bool aConsiderCurrentDocument)
- {
- nsCOMPtr<nsIDocument> document;
- bool inheritedFromCurrent = false;
- if (aConsiderCurrentDocument && mContentViewer) {
- document = mContentViewer->GetDocument();
- inheritedFromCurrent = true;
- }
- if (!document) {
- nsCOMPtr<nsIDocShellTreeItem> parentItem;
- GetSameTypeParent(getter_AddRefs(parentItem));
- if (parentItem) {
- document = parentItem->GetDocument();
- }
- }
- if (!document) {
- if (!aConsiderCurrentDocument) {
- return nullptr;
- }
- // Make sure we end up with _something_ as the principal no matter
- // what.If this fails, we'll just get a null docViewer and bail.
- EnsureContentViewer();
- if (!mContentViewer) {
- return nullptr;
- }
- document = mContentViewer->GetDocument();
- }
- //-- Get the document's principal
- if (document) {
- nsIPrincipal* docPrincipal = document->NodePrincipal();
- // Don't allow loads in typeContent docShells to inherit the system
- // principal from existing documents.
- if (inheritedFromCurrent &&
- mItemType == typeContent &&
- nsContentUtils::IsSystemPrincipal(docPrincipal)) {
- return nullptr;
- }
- return docPrincipal;
- }
- return nullptr;
- }
- nsresult
- nsDocShell::DoURILoad(nsIURI* aURI,
- nsIURI* aOriginalURI,
- bool aLoadReplace,
- bool aIsFromProcessingFrameAttributes,
- bool aLoadFromExternal,
- bool aForceAllowDataURI,
- nsIURI* aReferrerURI,
- bool aSendReferrer,
- uint32_t aReferrerPolicy,
- nsIPrincipal* aTriggeringPrincipal,
- nsIPrincipal* aPrincipalToInherit,
- const char* aTypeHint,
- const nsAString& aFileName,
- nsIInputStream* aPostData,
- nsIInputStream* aHeadersData,
- bool aFirstParty,
- nsIDocShell** aDocShell,
- nsIRequest** aRequest,
- bool aIsNewWindowTarget,
- bool aBypassClassifier,
- bool aForceAllowCookies,
- const nsAString& aSrcdoc,
- nsIURI* aBaseURI,
- nsContentPolicyType aContentPolicyType)
- {
- // Double-check that we're still around to load this URI.
- if (mIsBeingDestroyed) {
- // Return NS_OK despite not doing anything to avoid throwing exceptions from
- // nsLocation::SetHref if the unload handler of the existing page tears us
- // down.
- return NS_OK;
- }
- nsresult rv;
- nsCOMPtr<nsIURILoader> uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
- if (NS_FAILED(rv)) {
- return rv;
- }
- if (IsFrame()) {
- MOZ_ASSERT(aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_IFRAME ||
- aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FRAME,
- "DoURILoad thinks this is a frame and InternalLoad does not");
- // Only allow view-source scheme in top-level docshells. view-source is
- // the only scheme to which this applies at the moment due to potential
- // timing attacks to read data from cross-origin iframes. If this widens
- // we should add a protocol flag for whether the scheme is allowed in
- // frames and use something like nsNetUtil::NS_URIChainHasFlags.
- nsCOMPtr<nsIURI> tempURI = aURI;
- nsCOMPtr<nsINestedURI> nestedURI = do_QueryInterface(tempURI);
- while (nestedURI) {
- // view-source should always be an nsINestedURI, loop and check the
- // scheme on this and all inner URIs that are also nested URIs.
- bool isViewSource = false;
- rv = tempURI->SchemeIs("view-source", &isViewSource);
- if (NS_FAILED(rv) || isViewSource) {
- return NS_ERROR_UNKNOWN_PROTOCOL;
- }
- nestedURI->GetInnerURI(getter_AddRefs(tempURI));
- nestedURI = do_QueryInterface(tempURI);
- }
- } else {
- MOZ_ASSERT(aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT,
- "DoURILoad thinks this is a document and InternalLoad does not");
- }
- // open a channel for the url
- nsCOMPtr<nsIChannel> channel;
- bool isSrcdoc = !aSrcdoc.IsVoid();
- // There are two cases we care about:
- // * Top-level load: In this case, loadingNode is null, but loadingWindow
- // is our mScriptGlobal. We pass null for loadingPrincipal in this case.
- // * Subframe load: loadingWindow is null, but loadingNode is the frame
- // element for the load. loadingPrincipal is the NodePrincipal of the frame
- // element.
- nsCOMPtr<nsINode> loadingNode;
- nsCOMPtr<nsPIDOMWindowOuter> loadingWindow;
- nsCOMPtr<nsIPrincipal> loadingPrincipal;
- nsCOMPtr<nsISupports> topLevelLoadingContext;
- if (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) {
- loadingNode = nullptr;
- loadingPrincipal = nullptr;
- loadingWindow = mScriptGlobal->AsOuter();
- if (XRE_IsContentProcess()) {
- // In e10s the child process doesn't have access to the element that
- // contains the browsing context (because that element is in the chrome
- // process).
- nsCOMPtr<nsITabChild> tabChild = GetTabChild();
- topLevelLoadingContext = ToSupports(tabChild);
- } else {
- // This is for loading non-e10s tabs and toplevel windows of various
- // sorts.
- // For the toplevel window cases, requestingElement will be null.
- nsCOMPtr<Element> requestingElement =
- loadingWindow->GetFrameElementInternal();
- topLevelLoadingContext = requestingElement;
- }
- } else {
- loadingWindow = nullptr;
- loadingNode = mScriptGlobal->AsOuter()->GetFrameElementInternal();
- if (loadingNode) {
- // If we have a loading node, then use that as our loadingPrincipal.
- loadingPrincipal = loadingNode->NodePrincipal();
- #ifdef DEBUG
- // Get the docshell type for requestingElement.
- nsCOMPtr<nsIDocument> requestingDoc = loadingNode->OwnerDoc();
- nsCOMPtr<nsIDocShell> elementDocShell = requestingDoc->GetDocShell();
- // requestingElement docshell type = current docshell type.
- MOZ_ASSERT(mItemType == elementDocShell->ItemType(),
- "subframes should have the same docshell type as their parent");
- #endif
- } else {
- // If this isn't a top-level load and mScriptGlobal's frame element is
- // null, then the element got removed from the DOM while we were trying
- // to load this resource. This docshell is scheduled for destruction
- // already, so bail out here.
- return NS_OK;
- }
- }
- // Getting the right triggeringPrincipal needs to be updated and is only
- // ready for use once bug 1182569 landed. Until then, we cannot rely on
- // the triggeringPrincipal for TYPE_DOCUMENT loads.
- MOZ_ASSERT(aTriggeringPrincipal, "Need a valid triggeringPrincipal");
- bool isSandBoxed = mSandboxFlags & SANDBOXED_ORIGIN;
- // only inherit if we have a aPrincipalToInherit
- bool inherit = false;
- if (aPrincipalToInherit) {
- inherit = nsContentUtils::ChannelShouldInheritPrincipal(
- aPrincipalToInherit,
- aURI,
- true, // aInheritForAboutBlank
- isSrcdoc);
- }
- nsLoadFlags loadFlags = mDefaultLoadFlags;
- nsSecurityFlags securityFlags =
- nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
- if (aFirstParty) {
- // tag first party URL loads
- loadFlags |= nsIChannel::LOAD_INITIAL_DOCUMENT_URI;
- }
- if (mLoadType == LOAD_ERROR_PAGE) {
- // Error pages are LOAD_BACKGROUND
- loadFlags |= nsIChannel::LOAD_BACKGROUND;
- securityFlags |= nsILoadInfo::SEC_LOAD_ERROR_PAGE;
- }
- if (inherit) {
- securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
- }
- if (isSandBoxed) {
- securityFlags |= nsILoadInfo::SEC_SANDBOXED;
- }
- RefPtr<LoadInfo> loadInfo =
- (aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT) ?
- new LoadInfo(loadingWindow, aTriggeringPrincipal, topLevelLoadingContext,
- securityFlags) :
- new LoadInfo(loadingPrincipal, aTriggeringPrincipal, loadingNode,
- securityFlags, aContentPolicyType);
- if (aPrincipalToInherit) {
- loadInfo->SetPrincipalToInherit(aPrincipalToInherit);
- }
- loadInfo->SetLoadTriggeredFromExternal(aLoadFromExternal);
- loadInfo->SetForceAllowDataURI(aForceAllowDataURI);
- // We have to do this in case our OriginAttributes are different from the
- // OriginAttributes of the parent document. Or in case there isn't a
- // parent document.
- NeckoOriginAttributes neckoAttrs;
- bool isTopLevelDoc = aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT &&
- mItemType == typeContent &&
- !GetIsMozBrowserOrApp();
- neckoAttrs.InheritFromDocShellToNecko(GetOriginAttributes(), isTopLevelDoc, aURI);
- rv = loadInfo->SetOriginAttributes(neckoAttrs);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- if (aIsFromProcessingFrameAttributes) {
- loadInfo->SetIsFromProcessingFrameAttributes();
- }
- if (!isSrcdoc) {
- rv = NS_NewChannelInternal(getter_AddRefs(channel),
- aURI,
- loadInfo,
- nullptr, // loadGroup
- static_cast<nsIInterfaceRequestor*>(this),
- loadFlags);
- if (NS_FAILED(rv)) {
- if (rv == NS_ERROR_UNKNOWN_PROTOCOL) {
- // This is a uri with a protocol scheme we don't know how
- // to handle. Embedders might still be interested in
- // handling the load, though, so we fire a notification
- // before throwing the load away.
- bool abort = false;
- nsresult rv2 = mContentListener->OnStartURIOpen(aURI, &abort);
- if (NS_SUCCEEDED(rv2) && abort) {
- // Hey, they're handling the load for us! How convenient!
- return NS_OK;
- }
- }
- return rv;
- }
- if (aBaseURI) {
- nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(channel);
- if (vsc) {
- vsc->SetBaseURI(aBaseURI);
- }
- }
- } else {
- nsAutoCString scheme;
- rv = aURI->GetScheme(scheme);
- NS_ENSURE_SUCCESS(rv, rv);
- bool isViewSource;
- aURI->SchemeIs("view-source", &isViewSource);
- if (isViewSource) {
- nsViewSourceHandler* vsh = nsViewSourceHandler::GetInstance();
- NS_ENSURE_TRUE(vsh, NS_ERROR_FAILURE);
- rv = vsh->NewSrcdocChannel(aURI, aBaseURI, aSrcdoc,
- loadInfo, getter_AddRefs(channel));
- } else {
- rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
- aURI,
- aSrcdoc,
- NS_LITERAL_CSTRING("text/html"),
- loadInfo,
- true);
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIInputStreamChannel> isc = do_QueryInterface(channel);
- MOZ_ASSERT(isc);
- isc->SetBaseURI(aBaseURI);
- }
- }
- // Navigational requests that are same origin need to be upgraded in case
- // upgrade-insecure-requests is present. Please note that in that case
- // the triggeringPrincipal is holding the CSP that potentially
- // holds upgrade-insecure-requests.
- nsCOMPtr<nsIContentSecurityPolicy> csp;
- aTriggeringPrincipal->GetCsp(getter_AddRefs(csp));
- if (csp) {
- bool upgradeInsecureRequests = false;
- csp->GetUpgradeInsecureRequests(&upgradeInsecureRequests);
- if (upgradeInsecureRequests) {
- // only upgrade if the navigation is same origin
- nsCOMPtr<nsIPrincipal> resultPrincipal;
- rv = nsContentUtils::GetSecurityManager()->
- GetChannelResultPrincipal(channel,
- getter_AddRefs(resultPrincipal));
- NS_ENSURE_SUCCESS(rv, rv);
- if (resultPrincipal->Equals(aTriggeringPrincipal)) {
- static_cast<mozilla::LoadInfo*>(loadInfo.get())->SetUpgradeInsecureRequests();
- }
- }
- }
- nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
- do_QueryInterface(channel);
- if (appCacheChannel) {
- // Any document load should not inherit application cache.
- appCacheChannel->SetInheritApplicationCache(false);
- // Loads with the correct permissions should check for a matching
- // application cache.
- if (GeckoProcessType_Default != XRE_GetProcessType()) {
- // Permission will be checked in the parent process
- appCacheChannel->SetChooseApplicationCache(true);
- } else {
- nsCOMPtr<nsIScriptSecurityManager> secMan =
- do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
- if (secMan) {
- nsCOMPtr<nsIPrincipal> principal;
- secMan->GetDocShellCodebasePrincipal(aURI, this,
- getter_AddRefs(principal));
- appCacheChannel->SetChooseApplicationCache(
- NS_ShouldCheckAppCache(principal, UsePrivateBrowsing()));
- }
- }
- }
- // Make sure to give the caller a channel if we managed to create one
- // This is important for correct error page/session history interaction
- if (aRequest) {
- NS_ADDREF(*aRequest = channel);
- }
- if (aOriginalURI) {
- channel->SetOriginalURI(aOriginalURI);
- if (aLoadReplace) {
- uint32_t loadFlags;
- channel->GetLoadFlags(&loadFlags);
- NS_ENSURE_SUCCESS(rv, rv);
- channel->SetLoadFlags(loadFlags | nsIChannel::LOAD_REPLACE);
- }
- } else {
- channel->SetOriginalURI(aURI);
- }
- if (aTypeHint && *aTypeHint) {
- channel->SetContentType(nsDependentCString(aTypeHint));
- mContentTypeHint = aTypeHint;
- } else {
- mContentTypeHint.Truncate();
- }
- if (!aFileName.IsVoid()) {
- rv = channel->SetContentDisposition(nsIChannel::DISPOSITION_ATTACHMENT);
- NS_ENSURE_SUCCESS(rv, rv);
- if (!aFileName.IsEmpty()) {
- rv = channel->SetContentDispositionFilename(aFileName);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- }
- if (mLoadType == LOAD_NORMAL_ALLOW_MIXED_CONTENT ||
- mLoadType == LOAD_RELOAD_ALLOW_MIXED_CONTENT) {
- rv = SetMixedContentChannel(channel);
- NS_ENSURE_SUCCESS(rv, rv);
- } else if (mMixedContentChannel) {
- /*
- * If the user "Disables Protection on This Page", we call
- * SetMixedContentChannel for the first time, otherwise
- * mMixedContentChannel is still null.
- * Later, if the new channel passes a same orign check, we remember the
- * users decision by calling SetMixedContentChannel using the new channel.
- * This way, the user does not have to click the disable protection button
- * over and over for browsing the same site.
- */
- rv = nsContentUtils::CheckSameOrigin(mMixedContentChannel, channel);
- if (NS_FAILED(rv) || NS_FAILED(SetMixedContentChannel(channel))) {
- SetMixedContentChannel(nullptr);
- }
- }
- // hack
- nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel));
- nsCOMPtr<nsIHttpChannelInternal> httpChannelInternal(
- do_QueryInterface(channel));
- if (httpChannelInternal) {
- if (aForceAllowCookies) {
- httpChannelInternal->SetThirdPartyFlags(
- nsIHttpChannelInternal::THIRD_PARTY_FORCE_ALLOW);
- }
- if (aFirstParty) {
- httpChannelInternal->SetDocumentURI(aURI);
- } else {
- httpChannelInternal->SetDocumentURI(aReferrerURI);
- }
- httpChannelInternal->SetRedirectMode(
- nsIHttpChannelInternal::REDIRECT_MODE_MANUAL);
- }
- nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(channel));
- if (props) {
- // save true referrer for those who need it (e.g. xpinstall whitelisting)
- // Currently only http and ftp channels support this.
- props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"),
- aReferrerURI);
- }
- nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(channel));
- /* Get the cache Key from SH */
- nsCOMPtr<nsISupports> cacheKey;
- if (cacheChannel) {
- if (mLSHE) {
- mLSHE->GetCacheKey(getter_AddRefs(cacheKey));
- } else if (mOSHE) { // for reload cases
- mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
- }
- }
- // figure out if we need to set the post data stream on the channel...
- if (aPostData) {
- nsCOMPtr<nsIFormPOSTActionChannel> postChannel(do_QueryInterface(channel));
- if (postChannel) {
- // XXX it's a bit of a hack to rewind the postdata stream here but
- // it has to be done in case the post data is being reused multiple
- // times.
- nsCOMPtr<nsISeekableStream> postDataSeekable =
- do_QueryInterface(aPostData);
- if (postDataSeekable) {
- rv = postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- // we really need to have a content type associated with this stream!!
- postChannel->SetUploadStream(aPostData, EmptyCString(), -1);
- }
- /* If there is a valid postdata *and* it is a History Load,
- * set up the cache key on the channel, to retrieve the
- * data *only* from the cache. If it is a normal reload, the
- * cache is free to go to the server for updated postdata.
- */
- if (cacheChannel && cacheKey) {
- if (mLoadType == LOAD_HISTORY ||
- mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
- cacheChannel->SetCacheKey(cacheKey);
- uint32_t loadFlags;
- if (NS_SUCCEEDED(channel->GetLoadFlags(&loadFlags))) {
- channel->SetLoadFlags(
- loadFlags | nsICachingChannel::LOAD_ONLY_FROM_CACHE);
- }
- } else if (mLoadType == LOAD_RELOAD_NORMAL) {
- cacheChannel->SetCacheKey(cacheKey);
- }
- }
- } else {
- /* If there is no postdata, set the cache key on the channel, and
- * do not set the LOAD_ONLY_FROM_CACHE flag, so that the channel
- * will be free to get it from net if it is not found in cache.
- * New cache may use it creatively on CGI pages with GET
- * method and even on those that say "no-cache"
- */
- if (mLoadType == LOAD_HISTORY ||
- mLoadType == LOAD_RELOAD_NORMAL ||
- mLoadType == LOAD_RELOAD_CHARSET_CHANGE) {
- if (cacheChannel && cacheKey) {
- cacheChannel->SetCacheKey(cacheKey);
- }
- }
- }
- if (httpChannel) {
- if (aHeadersData) {
- rv = AddHeadersToChannel(aHeadersData, httpChannel);
- }
- // Set the referrer explicitly
- if (aReferrerURI && aSendReferrer) {
- // Referrer is currenly only set for link clicks here.
- httpChannel->SetReferrerWithPolicy(aReferrerURI, aReferrerPolicy);
- }
- // set Content-Signature enforcing bit if aOriginalURI == about:newtab
- if (aOriginalURI && httpChannel) {
- if (IsAboutNewtab(aOriginalURI)) {
- nsCOMPtr<nsILoadInfo> loadInfo = httpChannel->GetLoadInfo();
- if (loadInfo) {
- loadInfo->SetVerifySignedContent(true);
- }
- }
- }
- }
- nsCOMPtr<nsIScriptChannel> scriptChannel = do_QueryInterface(channel);
- if (scriptChannel) {
- // Allow execution against our context if the principals match
- scriptChannel->SetExecutionPolicy(nsIScriptChannel::EXECUTE_NORMAL);
- }
- if (aIsNewWindowTarget) {
- nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
- if (props) {
- props->SetPropertyAsBool(NS_LITERAL_STRING("docshell.newWindowTarget"),
- true);
- }
- }
- nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(channel));
- if (timedChannel) {
- timedChannel->SetTimingEnabled(true);
- nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
- if (IsFrame() && win) {
- nsCOMPtr<Element> frameElement = win->GetFrameElementInternal();
- if (frameElement) {
- timedChannel->SetInitiatorType(frameElement->LocalName());
- }
- }
- }
- rv = DoChannelLoad(channel, uriLoader, aBypassClassifier);
- //
- // If the channel load failed, we failed and nsIWebProgress just ain't
- // gonna happen.
- //
- if (NS_SUCCEEDED(rv)) {
- if (aDocShell) {
- *aDocShell = this;
- NS_ADDREF(*aDocShell);
- }
- }
- return rv;
- }
- static nsresult
- AppendSegmentToString(nsIInputStream* aIn,
- void* aClosure,
- const char* aFromRawSegment,
- uint32_t aToOffset,
- uint32_t aCount,
- uint32_t* aWriteCount)
- {
- // aFromSegment now contains aCount bytes of data.
- nsAutoCString* buf = static_cast<nsAutoCString*>(aClosure);
- buf->Append(aFromRawSegment, aCount);
- // Indicate that we have consumed all of aFromSegment
- *aWriteCount = aCount;
- return NS_OK;
- }
- nsresult
- nsDocShell::AddHeadersToChannel(nsIInputStream* aHeadersData,
- nsIChannel* aGenericChannel)
- {
- nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aGenericChannel);
- NS_ENSURE_STATE(httpChannel);
- uint32_t numRead;
- nsAutoCString headersString;
- nsresult rv = aHeadersData->ReadSegments(AppendSegmentToString,
- &headersString,
- UINT32_MAX,
- &numRead);
- NS_ENSURE_SUCCESS(rv, rv);
- // used during the manipulation of the String from the InputStream
- nsAutoCString headerName;
- nsAutoCString headerValue;
- int32_t crlf;
- int32_t colon;
- //
- // Iterate over the headersString: for each "\r\n" delimited chunk,
- // add the value as a header to the nsIHttpChannel
- //
- static const char kWhitespace[] = "\b\t\r\n ";
- while (true) {
- crlf = headersString.Find("\r\n");
- if (crlf == kNotFound) {
- return NS_OK;
- }
- const nsCSubstring& oneHeader = StringHead(headersString, crlf);
- colon = oneHeader.FindChar(':');
- if (colon == kNotFound) {
- return NS_ERROR_UNEXPECTED;
- }
- headerName = StringHead(oneHeader, colon);
- headerValue = Substring(oneHeader, colon + 1);
- headerName.Trim(kWhitespace);
- headerValue.Trim(kWhitespace);
- headersString.Cut(0, crlf + 2);
- //
- // FINALLY: we can set the header!
- //
- rv = httpChannel->SetRequestHeader(headerName, headerValue, true);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- NS_NOTREACHED("oops");
- return NS_ERROR_UNEXPECTED;
- }
- nsresult
- nsDocShell::DoChannelLoad(nsIChannel* aChannel,
- nsIURILoader* aURILoader,
- bool aBypassClassifier)
- {
- nsresult rv;
- // Mark the channel as being a document URI and allow content sniffing...
- nsLoadFlags loadFlags = 0;
- (void)aChannel->GetLoadFlags(&loadFlags);
- loadFlags |= nsIChannel::LOAD_DOCUMENT_URI |
- nsIChannel::LOAD_CALL_CONTENT_SNIFFERS;
- // Load attributes depend on load type...
- switch (mLoadType) {
- case LOAD_HISTORY: {
- // Only send VALIDATE_NEVER if mLSHE's URI was never changed via
- // push/replaceState (bug 669671).
- bool uriModified = false;
- if (mLSHE) {
- mLSHE->GetURIWasModified(&uriModified);
- }
- if (!uriModified) {
- loadFlags |= nsIRequest::VALIDATE_NEVER;
- }
- break;
- }
- case LOAD_RELOAD_CHARSET_CHANGE: {
- // Use SetAllowStaleCacheContent (not LOAD_FROM_CACHE flag) since we only want
- // to force cache load for this channel, not the whole loadGroup.
- nsCOMPtr<nsICacheInfoChannel> cachingChannel = do_QueryInterface(aChannel);
- if (cachingChannel) {
- cachingChannel->SetAllowStaleCacheContent(true);
- }
- break;
- }
- case LOAD_RELOAD_NORMAL:
- case LOAD_REFRESH:
- loadFlags |= nsIRequest::VALIDATE_ALWAYS;
- break;
- case LOAD_NORMAL_BYPASS_CACHE:
- case LOAD_NORMAL_BYPASS_PROXY:
- case LOAD_NORMAL_BYPASS_PROXY_AND_CACHE:
- case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
- case LOAD_RELOAD_BYPASS_CACHE:
- case LOAD_RELOAD_BYPASS_PROXY:
- case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
- case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
- case LOAD_REPLACE_BYPASS_CACHE:
- loadFlags |= nsIRequest::LOAD_BYPASS_CACHE |
- nsIRequest::LOAD_FRESH_CONNECTION;
- break;
- case LOAD_NORMAL:
- case LOAD_LINK:
- // Set cache checking flags
- switch (Preferences::GetInt("browser.cache.check_doc_frequency", -1)) {
- case 0:
- loadFlags |= nsIRequest::VALIDATE_ONCE_PER_SESSION;
- break;
- case 1:
- loadFlags |= nsIRequest::VALIDATE_ALWAYS;
- break;
- case 2:
- loadFlags |= nsIRequest::VALIDATE_NEVER;
- break;
- }
- break;
- }
- if (!aBypassClassifier) {
- loadFlags |= nsIChannel::LOAD_CLASSIFY_URI;
- }
- // If the user pressed shift-reload, then do not allow ServiceWorker
- // interception to occur. See step 12.1 of the SW HandleFetch algorithm.
- if (IsForceReloadType(mLoadType)) {
- loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
- }
- (void)aChannel->SetLoadFlags(loadFlags);
- uint32_t openFlags = 0;
- if (mLoadType == LOAD_LINK) {
- openFlags |= nsIURILoader::IS_CONTENT_PREFERRED;
- }
- if (!mAllowContentRetargeting) {
- openFlags |= nsIURILoader::DONT_RETARGET;
- }
- rv = aURILoader->OpenURI(aChannel, openFlags, this);
- NS_ENSURE_SUCCESS(rv, rv);
- return NS_OK;
- }
- nsresult
- nsDocShell::ScrollToAnchor(bool aCurHasRef, bool aNewHasRef,
- nsACString& aNewHash, uint32_t aLoadType)
- {
- if (!mCurrentURI) {
- return NS_OK;
- }
- nsCOMPtr<nsIPresShell> shell = GetPresShell();
- if (!shell) {
- // If we failed to get the shell, or if there is no shell,
- // nothing left to do here.
- return NS_OK;
- }
- nsIScrollableFrame* rootScroll = shell->GetRootScrollFrameAsScrollable();
- if (rootScroll) {
- rootScroll->ClearDidHistoryRestore();
- }
- // If we have no new anchor, we do not want to scroll, unless there is a
- // current anchor and we are doing a history load. So return if we have no
- // new anchor, and there is no current anchor or the load is not a history
- // load.
- if ((!aCurHasRef || aLoadType != LOAD_HISTORY) && !aNewHasRef) {
- return NS_OK;
- }
- // Both the new and current URIs refer to the same page. We can now
- // browse to the hash stored in the new URI.
- if (!aNewHash.IsEmpty()) {
- // anchor is there, but if it's a load from history,
- // we don't have any anchor jumping to do
- bool scroll = aLoadType != LOAD_HISTORY &&
- aLoadType != LOAD_RELOAD_NORMAL;
- char* str = ToNewCString(aNewHash);
- if (!str) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- // nsUnescape modifies the string that is passed into it.
- nsUnescape(str);
- // We assume that the bytes are in UTF-8, as it says in the
- // spec:
- // http://www.w3.org/TR/html4/appendix/notes.html#h-B.2.1
- // We try the UTF-8 string first, and then try the document's
- // charset (see below). If the string is not UTF-8,
- // conversion will fail and give us an empty Unicode string.
- // In that case, we should just fall through to using the
- // page's charset.
- nsresult rv = NS_ERROR_FAILURE;
- NS_ConvertUTF8toUTF16 uStr(str);
- if (!uStr.IsEmpty()) {
- rv = shell->GoToAnchor(NS_ConvertUTF8toUTF16(str), scroll,
- nsIPresShell::SCROLL_SMOOTH_AUTO);
- }
- free(str);
- // Above will fail if the anchor name is not UTF-8. Need to
- // convert from document charset to unicode.
- if (NS_FAILED(rv)) {
- // Get a document charset
- NS_ENSURE_TRUE(mContentViewer, NS_ERROR_FAILURE);
- nsIDocument* doc = mContentViewer->GetDocument();
- NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
- const nsACString& aCharset = doc->GetDocumentCharacterSet();
- nsCOMPtr<nsITextToSubURI> textToSubURI =
- do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- // Unescape and convert to unicode
- nsXPIDLString uStr;
- rv = textToSubURI->UnEscapeAndConvert(PromiseFlatCString(aCharset).get(),
- PromiseFlatCString(aNewHash).get(),
- getter_Copies(uStr));
- NS_ENSURE_SUCCESS(rv, rv);
- // Ignore return value of GoToAnchor, since it will return an error
- // if there is no such anchor in the document, which is actually a
- // success condition for us (we want to update the session history
- // with the new URI no matter whether we actually scrolled
- // somewhere).
- //
- // When aNewHash contains "%00", unescaped string may be empty.
- // And GoToAnchor asserts if we ask it to scroll to an empty ref.
- shell->GoToAnchor(uStr, scroll && !uStr.IsEmpty(),
- nsIPresShell::SCROLL_SMOOTH_AUTO);
- }
- } else {
- // Tell the shell it's at an anchor, without scrolling.
- shell->GoToAnchor(EmptyString(), false);
- // An empty anchor was found, but if it's a load from history,
- // we don't have to jump to the top of the page. Scrollbar
- // position will be restored by the caller, based on positions
- // stored in session history.
- if (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL) {
- return NS_OK;
- }
- // An empty anchor. Scroll to the top of the page. Ignore the
- // return value; failure to scroll here (e.g. if there is no
- // root scrollframe) is not grounds for canceling the load!
- SetCurScrollPosEx(0, 0);
- }
- return NS_OK;
- }
- void
- nsDocShell::SetupReferrerFromChannel(nsIChannel* aChannel)
- {
- nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
- if (httpChannel) {
- nsCOMPtr<nsIURI> referrer;
- nsresult rv = httpChannel->GetReferrer(getter_AddRefs(referrer));
- if (NS_SUCCEEDED(rv)) {
- SetReferrerURI(referrer);
- }
- uint32_t referrerPolicy;
- rv = httpChannel->GetReferrerPolicy(&referrerPolicy);
- if (NS_SUCCEEDED(rv)) {
- SetReferrerPolicy(referrerPolicy);
- }
- }
- }
- bool
- nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
- nsIPrincipal* aTriggeringPrincipal,
- nsIPrincipal* aPrincipalToInherit,
- uint32_t aLoadType, bool aFireOnLocationChange,
- bool aAddToGlobalHistory, bool aCloneSHChildren)
- {
- NS_PRECONDITION(aURI, "uri is null");
- NS_PRECONDITION(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set");
- MOZ_ASSERT(!aPrincipalToInherit || (aPrincipalToInherit && aTriggeringPrincipal));
- #if defined(DEBUG)
- if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
- nsAutoCString chanName;
- if (aChannel) {
- aChannel->GetName(chanName);
- } else {
- chanName.AssignLiteral("<no channel>");
- }
- MOZ_LOG(gDocShellLog, LogLevel::Debug,
- ("nsDocShell[%p]::OnNewURI(\"%s\", [%s], 0x%x)\n",
- this, aURI->GetSpecOrDefault().get(), chanName.get(), aLoadType));
- }
- #endif
- bool equalUri = false;
- // Get the post data and the HTTP response code from the channel.
- uint32_t responseStatus = 0;
- nsCOMPtr<nsIInputStream> inputStream;
- if (aChannel) {
- nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
- // Check if the HTTPChannel is hiding under a multiPartChannel
- if (!httpChannel) {
- GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
- }
- if (httpChannel) {
- nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
- if (uploadChannel) {
- uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
- }
- // If the response status indicates an error, unlink this session
- // history entry from any entries sharing its document.
- nsresult rv = httpChannel->GetResponseStatus(&responseStatus);
- if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) {
- mLSHE->AbandonBFCacheEntry();
- }
- }
- }
- // Determine if this type of load should update history.
- bool updateGHistory = !(aLoadType == LOAD_BYPASS_HISTORY ||
- aLoadType == LOAD_ERROR_PAGE ||
- aLoadType & LOAD_CMD_HISTORY);
- // We don't update session history on reload unless we're loading
- // an iframe in shift-reload case.
- bool updateSHistory = updateGHistory &&
- (!(aLoadType & LOAD_CMD_RELOAD) ||
- (IsForceReloadType(aLoadType) && IsFrame()));
- // Create SH Entry (mLSHE) only if there is a SessionHistory object in the
- // current frame or in the root docshell.
- nsCOMPtr<nsISHistory> rootSH = mSessionHistory;
- if (!rootSH) {
- // Get the handle to SH from the root docshell
- GetRootSessionHistory(getter_AddRefs(rootSH));
- if (!rootSH) {
- updateSHistory = false;
- updateGHistory = false; // XXX Why global history too?
- }
- }
- // Check if the url to be loaded is the same as the one already loaded.
- if (mCurrentURI) {
- aURI->Equals(mCurrentURI, &equalUri);
- }
- #ifdef DEBUG
- bool shAvailable = (rootSH != nullptr);
- // XXX This log message is almost useless because |updateSHistory|
- // and |updateGHistory| are not correct at this point.
- MOZ_LOG(gDocShellLog, LogLevel::Debug,
- (" shAvailable=%i updateSHistory=%i updateGHistory=%i"
- " equalURI=%i\n",
- shAvailable, updateSHistory, updateGHistory, equalUri));
- if (shAvailable && mCurrentURI && !mOSHE && aLoadType != LOAD_ERROR_PAGE) {
- NS_ASSERTION(NS_IsAboutBlank(mCurrentURI),
- "no SHEntry for a non-transient viewer?");
- }
- #endif
- /* If the url to be loaded is the same as the one already there,
- * and the original loadType is LOAD_NORMAL, LOAD_LINK, or
- * LOAD_STOP_CONTENT, set loadType to LOAD_NORMAL_REPLACE so that
- * AddToSessionHistory() won't mess with the current SHEntry and
- * if this page has any frame children, it also will be handled
- * properly. see bug 83684
- *
- * NB: If mOSHE is null but we have a current URI, then it means
- * that we must be at the transient about:blank content viewer
- * (asserted above) and we should let the normal load continue,
- * since there's nothing to replace.
- *
- * XXX Hopefully changing the loadType at this time will not hurt
- * anywhere. The other way to take care of sequentially repeating
- * frameset pages is to add new methods to nsIDocShellTreeItem.
- * Hopefully I don't have to do that.
- */
- if (equalUri &&
- mOSHE &&
- (mLoadType == LOAD_NORMAL ||
- mLoadType == LOAD_LINK ||
- mLoadType == LOAD_STOP_CONTENT) &&
- !inputStream) {
- mLoadType = LOAD_NORMAL_REPLACE;
- }
- // If this is a refresh to the currently loaded url, we don't
- // have to update session or global history.
- if (mLoadType == LOAD_REFRESH && !inputStream && equalUri) {
- SetHistoryEntry(&mLSHE, mOSHE);
- }
- /* If the user pressed shift-reload, cache will create a new cache key
- * for the page. Save the new cacheKey in Session History.
- * see bug 90098
- */
- if (aChannel && IsForceReloadType(aLoadType)) {
- MOZ_ASSERT(!updateSHistory || IsFrame(),
- "We shouldn't be updating session history for forced"
- " reloads unless we're in a newly created iframe!");
- nsCOMPtr<nsICacheInfoChannel> cacheChannel(do_QueryInterface(aChannel));
- nsCOMPtr<nsISupports> cacheKey;
- // Get the Cache Key and store it in SH.
- if (cacheChannel) {
- cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
- }
- // If we already have a loading history entry, store the new cache key
- // in it. Otherwise, since we're doing a reload and won't be updating
- // our history entry, store the cache key in our current history entry.
- if (mLSHE) {
- mLSHE->SetCacheKey(cacheKey);
- } else if (mOSHE) {
- mOSHE->SetCacheKey(cacheKey);
- }
- // Since we're force-reloading, clear all the sub frame history.
- ClearFrameHistory(mLSHE);
- ClearFrameHistory(mOSHE);
- }
- if (aLoadType == LOAD_RELOAD_NORMAL) {
- nsCOMPtr<nsISHEntry> currentSH;
- bool oshe = false;
- GetCurrentSHEntry(getter_AddRefs(currentSH), &oshe);
- bool dynamicallyAddedChild = false;
- if (currentSH) {
- currentSH->HasDynamicallyAddedChild(&dynamicallyAddedChild);
- }
- if (dynamicallyAddedChild) {
- ClearFrameHistory(currentSH);
- }
- }
- if (aLoadType == LOAD_REFRESH) {
- ClearFrameHistory(mLSHE);
- ClearFrameHistory(mOSHE);
- }
- if (updateSHistory) {
- // Update session history if necessary...
- if (!mLSHE && (mItemType == typeContent) && mURIResultedInDocument) {
- /* This is a fresh page getting loaded for the first time
- *.Create a Entry for it and add it to SH, if this is the
- * rootDocShell
- */
- (void)AddToSessionHistory(aURI, aChannel, aTriggeringPrincipal,
- aPrincipalToInherit, aCloneSHChildren,
- getter_AddRefs(mLSHE));
- }
- } else if (mSessionHistory && mLSHE && mURIResultedInDocument) {
- // Even if we don't add anything to SHistory, ensure the current index
- // points to the same SHEntry as our mLSHE.
- int32_t index = 0;
- mSessionHistory->GetRequestedIndex(&index);
- if (index == -1) {
- mSessionHistory->GetIndex(&index);
- }
- nsCOMPtr<nsISHEntry> currentSH;
- mSessionHistory->GetEntryAtIndex(index, false, getter_AddRefs(currentSH));
- if (currentSH != mLSHE) {
- nsCOMPtr<nsISHistoryInternal> shPrivate =
- do_QueryInterface(mSessionHistory);
- shPrivate->ReplaceEntry(index, mLSHE);
- }
- }
- // If this is a POST request, we do not want to include this in global
- // history.
- if (updateGHistory && aAddToGlobalHistory && !ChannelIsPost(aChannel)) {
- nsCOMPtr<nsIURI> previousURI;
- uint32_t previousFlags = 0;
- if (aLoadType & LOAD_CMD_RELOAD) {
- // On a reload request, we don't set redirecting flags.
- previousURI = aURI;
- } else {
- ExtractLastVisit(aChannel, getter_AddRefs(previousURI), &previousFlags);
- }
- // Note: We don't use |referrer| when our global history is
- // based on IHistory.
- nsCOMPtr<nsIURI> referrer;
- // Treat referrer as null if there is an error getting it.
- (void)NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
- AddURIVisit(aURI, referrer, previousURI, previousFlags, responseStatus);
- }
- // If this was a history load or a refresh, or it was a history load but
- // later changed to LOAD_NORMAL_REPLACE due to redirection, update the index
- // in session history.
- if (rootSH &&
- ((mLoadType & (LOAD_CMD_HISTORY | LOAD_CMD_RELOAD)) ||
- mLoadType == LOAD_NORMAL_REPLACE)) {
- nsCOMPtr<nsISHistoryInternal> shInternal(do_QueryInterface(rootSH));
- if (shInternal) {
- rootSH->GetIndex(&mPreviousTransIndex);
- shInternal->UpdateIndex();
- rootSH->GetIndex(&mLoadedTransIndex);
- #ifdef DEBUG_PAGE_CACHE
- printf("Previous index: %d, Loaded index: %d\n\n",
- mPreviousTransIndex, mLoadedTransIndex);
- #endif
- }
- }
- // aCloneSHChildren exactly means "we are not loading a new document".
- uint32_t locationFlags =
- aCloneSHChildren ? uint32_t(LOCATION_CHANGE_SAME_DOCUMENT) : 0;
- bool onLocationChangeNeeded = SetCurrentURI(aURI, aChannel,
- aFireOnLocationChange,
- locationFlags);
- // Make sure to store the referrer from the channel, if any
- SetupReferrerFromChannel(aChannel);
- return onLocationChangeNeeded;
- }
- bool
- nsDocShell::OnLoadingSite(nsIChannel* aChannel, bool aFireOnLocationChange,
- bool aAddToGlobalHistory)
- {
- nsCOMPtr<nsIURI> uri;
- // If this a redirect, use the final url (uri)
- // else use the original url
- //
- // Note that this should match what documents do (see nsDocument::Reset).
- NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
- NS_ENSURE_TRUE(uri, false);
- // Pass false for aCloneSHChildren, since we're loading a new page here.
- return OnNewURI(uri, aChannel, nullptr, nullptr, mLoadType, aFireOnLocationChange,
- aAddToGlobalHistory, false);
- }
- void
- nsDocShell::SetReferrerURI(nsIURI* aURI)
- {
- mReferrerURI = aURI; // This assigment addrefs
- }
- void
- nsDocShell::SetReferrerPolicy(uint32_t aReferrerPolicy)
- {
- mReferrerPolicy = aReferrerPolicy;
- }
- //*****************************************************************************
- // nsDocShell: Session History
- //*****************************************************************************
- bool
- nsDocShell::IsStateChangeFlooding()
- {
- // Issue #1688: Let's copy Firefox's strategy for state flooding here, so
- // that our implementations are interoperable.
- if (mStateFloodGuardCount > kStateUpdateLimit) {
- TimeStamp now = TimeStamp::Now();
- if (now - mStateFloodGuardUpdated > TimeDuration::FromSeconds(kRefreshTimeSecs)) {
- mStateFloodGuardCount = 0;
- mStateFloodGuardUpdated = now;
- mStateFloodGuardReported = false;
- return false;
- }
- return true;
- }
- mStateFloodGuardCount++;
- return false;
- }
- NS_IMETHODIMP
- nsDocShell::AddState(JS::Handle<JS::Value> aData, const nsAString& aTitle,
- const nsAString& aURL, bool aReplace, JSContext* aCx)
- {
- // Implements History.pushState and History.replaceState
- // Here's what we do, roughly in the order specified by HTML5. The specific
- // steps we are executing are at
- // <https://html.spec.whatwg.org/multipage/history.html#dom-history-pushstate>
- // and
- // <https://html.spec.whatwg.org/multipage/history.html#url-and-history-update-steps>.
- // This function basically implements #dom-history-pushstate and
- // UpdateURLAndHistory implements #url-and-history-update-steps.
- //
- // A. Serialize aData using structured clone. This is #dom-history-pushstate
- // step 5.
- // B. If the third argument is present, #dom-history-pushstate step 7.
- // 7.1. Resolve the url, relative to our document.
- // 7.2. If (a) fails, raise a SECURITY_ERR
- // 7.4. Compare the resulting absolute URL to the document's address. If
- // any part of the URLs difer other than the <path>, <query>, and
- // <fragment> components, raise a SECURITY_ERR and abort.
- // C. If !aReplace, #url-and-history-update-steps steps 2.1-2.3:
- // Remove from the session history all entries after the current entry,
- // as we would after a regular navigation, and save the current
- // entry's scroll position (bug 590573).
- // D. #url-and-history-update-steps step 2.4 or step 3. As apropriate,
- // either add a state object entry to the session history after the
- // current entry with the following properties, or modify the current
- // session history entry to set
- // a. cloned data as the state object,
- // b. if the third argument was present, the absolute URL found in
- // step 2
- // Also clear the new history entry's POST data (see bug 580069).
- // E. If aReplace is false (i.e. we're doing a pushState instead of a
- // replaceState), notify bfcache that we've navigated to a new page.
- // F. If the third argument is present, set the document's current address
- // to the absolute URL found in step B. This is
- // #url-and-history-update-steps step 4.
- //
- // It's important that this function not run arbitrary scripts after step 1
- // and before completing step 5. For example, if a script called
- // history.back() before we completed step 5, bfcache might destroy an
- // active content viewer. Since EvictOutOfRangeContentViewers at the end of
- // step E might run script, we can't just put a script blocker around the
- // critical section.
- //
- // Note that we completely ignore the aTitle parameter.
- nsresult rv;
- // Don't clobber the load type of an existing network load.
- AutoRestore<uint32_t> loadTypeResetter(mLoadType);
- // pushState effectively becomes replaceState when we've started a network
- // load but haven't adopted its document yet. This mirrors what we do with
- // changes to the hash at this stage of the game.
- if (JustStartedNetworkLoad()) {
- aReplace = true;
- }
- nsCOMPtr<nsIDocument> document = GetDocument();
- NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
- // If we're being flooded with state change requests, we should abort early
- // from the state change logic.
- if (IsStateChangeFlooding()) {
- // Report a warning to the console to tell developers why their navigations
- // failed.
- // Do this only if not yet marked reported so we only report it once per
- // flood interval.
- if (!mStateFloodGuardReported) {
- nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
- NS_LITERAL_CSTRING("PushState"),
- document,
- nsContentUtils::eDOM_PROPERTIES,
- "PushStateFloodingPrevented");
- mStateFloodGuardReported = true;
- }
- return NS_OK;
- }
- // Step A: Serialize aData using structured clone.
- // https://html.spec.whatwg.org/multipage/history.html#dom-history-pushstate
- // step 5.
- nsCOMPtr<nsIStructuredCloneContainer> scContainer;
- // scContainer->Init might cause arbitrary JS to run, and this code might
- // navigate the page we're on, potentially to a different origin! (bug
- // 634834) To protect against this, we abort if our principal changes due
- // to the InitFromJSVal() call.
- {
- nsCOMPtr<nsIDocument> origDocument = GetDocument();
- if (!origDocument) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- nsCOMPtr<nsIPrincipal> origPrincipal = origDocument->NodePrincipal();
- scContainer = new nsStructuredCloneContainer();
- rv = scContainer->InitFromJSVal(aData, aCx);
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIDocument> newDocument = GetDocument();
- if (!newDocument) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- nsCOMPtr<nsIPrincipal> newPrincipal = newDocument->NodePrincipal();
- bool principalsEqual = false;
- origPrincipal->Equals(newPrincipal, &principalsEqual);
- NS_ENSURE_TRUE(principalsEqual, NS_ERROR_DOM_SECURITY_ERR);
- }
- // Check that the state object isn't too long.
- // Default max length: 640k bytes.
- int32_t maxStateObjSize =
- Preferences::GetInt("browser.history.maxStateObjectSize", 0xA0000);
- if (maxStateObjSize < 0) {
- maxStateObjSize = 0;
- }
- uint64_t scSize;
- rv = scContainer->GetSerializedNBytes(&scSize);
- NS_ENSURE_SUCCESS(rv, rv);
- NS_ENSURE_TRUE(scSize <= (uint32_t)maxStateObjSize, NS_ERROR_ILLEGAL_VALUE);
- // Step B: Resolve aURL.
- // https://html.spec.whatwg.org/multipage/history.html#dom-history-pushstate
- // step 7.
- bool equalURIs = true;
- nsCOMPtr<nsIURI> currentURI;
- if (sURIFixup && mCurrentURI) {
- rv = sURIFixup->CreateExposableURI(mCurrentURI, getter_AddRefs(currentURI));
- NS_ENSURE_SUCCESS(rv, rv);
- } else {
- currentURI = mCurrentURI;
- }
- nsCOMPtr<nsIURI> newURI;
- if (aURL.Length() == 0) {
- newURI = currentURI;
- } else {
- // 7.1: Resolve aURL relative to mURI
- nsIURI* docBaseURI = document->GetDocBaseURI();
- if (!docBaseURI) {
- return NS_ERROR_FAILURE;
- }
- nsAutoCString spec;
- docBaseURI->GetSpec(spec);
- nsAutoCString charset;
- rv = docBaseURI->GetOriginCharset(charset);
- NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
- rv = NS_NewURI(getter_AddRefs(newURI), aURL, charset.get(), docBaseURI);
- // 7.2: If 7.1 fails, raise a SECURITY_ERR
- if (NS_FAILED(rv)) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- // 7.4 and 7.5: Same-origin check.
- if (!nsContentUtils::URIIsLocalFile(newURI)) {
- // In addition to checking that the security manager says that
- // the new URI has the same origin as our current URI, we also
- // check that the two URIs have the same userpass. (The
- // security manager says that |http://foo.com| and
- // |http://me@foo.com| have the same origin.) currentURI
- // won't contain the password part of the userpass, so this
- // means that it's never valid to specify a password in a
- // pushState or replaceState URI.
- nsCOMPtr<nsIScriptSecurityManager> secMan =
- do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
- NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
- // It's very important that we check that newURI is of the same
- // origin as currentURI, not docBaseURI, because a page can
- // set docBaseURI arbitrarily to any domain.
- nsAutoCString currentUserPass, newUserPass;
- NS_ENSURE_SUCCESS(currentURI->GetUserPass(currentUserPass),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(newURI->GetUserPass(newUserPass), NS_ERROR_FAILURE);
- if (NS_FAILED(secMan->CheckSameOriginURI(currentURI, newURI, true)) ||
- !currentUserPass.Equals(newUserPass)) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- } else {
- // It's a file:// URI
- nsCOMPtr<nsIScriptObjectPrincipal> docScriptObj =
- do_QueryInterface(document);
- if (!docScriptObj) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- nsCOMPtr<nsIPrincipal> principal = docScriptObj->GetPrincipal();
- if (!principal ||
- NS_FAILED(principal->CheckMayLoad(newURI, true, false))) {
- return NS_ERROR_DOM_SECURITY_ERR;
- }
- }
- if (currentURI) {
- currentURI->Equals(newURI, &equalURIs);
- } else {
- equalURIs = false;
- }
- } // end of same-origin check
- // Step 8: call "URL and history update steps"
- rv = UpdateURLAndHistory(document, newURI, scContainer, aTitle, aReplace,
- currentURI, equalURIs);
- NS_ENSURE_SUCCESS(rv, rv);
- return NS_OK;
- }
- nsresult
- nsDocShell::UpdateURLAndHistory(nsIDocument* aDocument, nsIURI* aNewURI,
- nsIStructuredCloneContainer* aData,
- const nsAString& aTitle, bool aReplace,
- nsIURI* aCurrentURI, bool aEqualURIs)
- {
- // Implements
- // https://html.spec.whatwg.org/multipage/history.html#url-and-history-update-steps
- // Step 2, if aReplace is false: Create a new entry in the session
- // history. This will erase all SHEntries after the new entry and make this
- // entry the current one. This operation may modify mOSHE, which we need
- // later, so we keep a reference here.
- NS_ENSURE_TRUE(mOSHE || aReplace, NS_ERROR_FAILURE);
- nsCOMPtr<nsISHEntry> oldOSHE = mOSHE;
- mLoadType = LOAD_PUSHSTATE;
- nsCOMPtr<nsISHEntry> newSHEntry;
- if (!aReplace) {
- // Step 2.
- // Save the current scroll position (bug 590573). Step 2.3.
- nscoord cx = 0, cy = 0;
- GetCurScrollPos(ScrollOrientation_X, &cx);
- GetCurScrollPos(ScrollOrientation_Y, &cy);
- mOSHE->SetScrollPosition(cx, cy);
- bool scrollRestorationIsManual = false;
- mOSHE->GetScrollRestorationIsManual(&scrollRestorationIsManual);
- // Since we're not changing which page we have loaded, pass
- // true for aCloneChildren.
- nsresult rv = AddToSessionHistory(aNewURI, nullptr,
- aDocument->NodePrincipal(), // triggeringPrincipal
- nullptr, true,
- getter_AddRefs(newSHEntry));
- NS_ENSURE_SUCCESS(rv, rv);
- NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
- // Session history entries created by pushState inherit scroll restoration
- // mode from the current entry.
- newSHEntry->SetScrollRestorationIsManual(scrollRestorationIsManual);
- // Link the new SHEntry to the old SHEntry's BFCache entry, since the
- // two entries correspond to the same document.
- NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE), NS_ERROR_FAILURE);
- // Set the new SHEntry's title (bug 655273).
- nsString title;
- mOSHE->GetTitle(getter_Copies(title));
- newSHEntry->SetTitle(title);
- // AddToSessionHistory may not modify mOSHE. In case it doesn't,
- // we'll just set mOSHE here.
- mOSHE = newSHEntry;
- } else {
- // Step 3.
- newSHEntry = mOSHE;
- // Since we're not changing which page we have loaded, pass
- if (!newSHEntry) {
- nsresult rv = AddToSessionHistory(
- aNewURI, nullptr,
- aDocument->NodePrincipal(), // triggeringPrincipal
- nullptr, true, getter_AddRefs(newSHEntry));
- NS_ENSURE_SUCCESS(rv, rv);
- mOSHE = newSHEntry;
- }
- newSHEntry->SetURI(aNewURI);
- newSHEntry->SetOriginalURI(aNewURI);
- newSHEntry->SetLoadReplace(false);
- }
- // Step 2.4 and 3: Modify new/original session history entry and clear its
- // POST data, if there is any.
- newSHEntry->SetStateData(aData);
- newSHEntry->SetPostData(nullptr);
- // If this push/replaceState changed the document's current URI and the new
- // URI differs from the old URI in more than the hash, or if the old
- // SHEntry's URI was modified in this way by a push/replaceState call
- // set URIWasModified to true for the current SHEntry (bug 669671).
- bool sameExceptHashes = true, oldURIWasModified = false;
- aNewURI->EqualsExceptRef(aCurrentURI, &sameExceptHashes);
- // mOSHE might be null on replace. Only check if we're not replacing.
- if (oldOSHE) {
- oldOSHE->GetURIWasModified(&oldURIWasModified);
- }
- newSHEntry->SetURIWasModified(!sameExceptHashes || oldURIWasModified);
- // Step E as described at the top of AddState: If aReplace is false,
- // indicating that we're doing a pushState rather than a replaceState, notify
- // bfcache that we've added a page to the history so it can evict content
- // viewers if appropriate. Otherwise call ReplaceEntry so that we notify
- // nsIHistoryListeners that an entry was replaced. We may not have a root
- // session history if this call is coming from a document.open() in a docshell
- // subtree that disables session history.
- nsCOMPtr<nsISHistory> rootSH;
- GetRootSessionHistory(getter_AddRefs(rootSH));
- NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED);
- nsCOMPtr<nsISHistoryInternal> internalSH = do_QueryInterface(rootSH);
- NS_ENSURE_TRUE(internalSH, NS_ERROR_UNEXPECTED);
-
- nsresult rv;
-
- if (rootSH) {
- if (!aReplace) {
- int32_t curIndex = -1;
- rv = rootSH->GetIndex(&curIndex);
- if (NS_SUCCEEDED(rv) && curIndex > -1) {
- internalSH->EvictOutOfRangeContentViewers(curIndex);
- }
- } else {
- nsCOMPtr<nsISHEntry> rootSHEntry = GetRootSHEntry(newSHEntry);
- int32_t index = -1;
- rv = rootSH->GetIndexOfEntry(rootSHEntry, &index);
- if (NS_SUCCEEDED(rv) && index > -1) {
- internalSH->ReplaceEntry(index, rootSHEntry);
- }
- }
- }
- // Step 4: If the document's URI changed, update document's URI and update
- // global history.
- //
- // We need to call FireOnLocationChange so that the browser's address bar
- // gets updated and the back button is enabled, but we only need to
- // explicitly call FireOnLocationChange if we're not calling SetCurrentURI,
- // since SetCurrentURI will call FireOnLocationChange for us.
- //
- // Both SetCurrentURI(...) and FireDummyOnLocationChange() pass
- // nullptr for aRequest param to FireOnLocationChange(...). Such an update
- // notification is allowed only when we know docshell is not loading a new
- // document and it requires LOCATION_CHANGE_SAME_DOCUMENT flag. Otherwise,
- // FireOnLocationChange(...) breaks security UI.
- if (!aEqualURIs) {
- aDocument->SetDocumentURI(aNewURI);
- // We can't trust SetCurrentURI to do always fire locationchange events
- // when we expect it to, so we hack around that by doing it ourselves...
- SetCurrentURI(aNewURI, nullptr, false, LOCATION_CHANGE_SAME_DOCUMENT);
- if (mLoadType != LOAD_ERROR_PAGE) {
- FireDummyOnLocationChange();
- }
- AddURIVisit(aNewURI, aCurrentURI, aCurrentURI, 0);
- // AddURIVisit doesn't set the title for the new URI in global history,
- // so do that here.
- if (mUseGlobalHistory && !UsePrivateBrowsing()) {
- nsCOMPtr<IHistory> history = services::GetHistoryService();
- if (history) {
- history->SetURITitle(aNewURI, mTitle);
- } else if (mGlobalHistory) {
- mGlobalHistory->SetPageTitle(aNewURI, mTitle);
- }
- }
- // Inform the favicon service that our old favicon applies to this new
- // URI.
- CopyFavicon(aCurrentURI, aNewURI, aDocument->NodePrincipal(), UsePrivateBrowsing());
- } else {
- FireDummyOnLocationChange();
- }
- aDocument->SetStateObject(aData);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetCurrentScrollRestorationIsManual(bool* aIsManual)
- {
- *aIsManual = false;
- if (mOSHE) {
- mOSHE->GetScrollRestorationIsManual(aIsManual);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetCurrentScrollRestorationIsManual(bool aIsManual)
- {
- if (mOSHE) {
- mOSHE->SetScrollRestorationIsManual(aIsManual);
- }
- return NS_OK;
- }
- bool
- nsDocShell::ShouldAddToSessionHistory(nsIURI* aURI)
- {
- // I believe none of the about: urls should go in the history. But then
- // that could just be me... If the intent is only deny about:blank then we
- // should just do a spec compare, rather than two gets of the scheme and
- // then the path. -Gagan
- nsresult rv;
- nsAutoCString buf;
- rv = aURI->GetScheme(buf);
- if (NS_FAILED(rv)) {
- return false;
- }
- if (buf.EqualsLiteral("about")) {
- rv = aURI->GetPath(buf);
- if (NS_FAILED(rv)) {
- return false;
- }
- if (buf.EqualsLiteral("blank") || buf.EqualsLiteral("logopage") ||
- (buf.EqualsLiteral("newtab") &&
- !Preferences::GetBool("browser.newtabpage.add_to_session_history", false))) {
- return false;
- }
- }
- return true;
- }
- nsresult
- nsDocShell::AddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel,
- nsIPrincipal* aTriggeringPrincipal,
- nsIPrincipal* aPrincipalToInherit,
- bool aCloneChildren,
- nsISHEntry** aNewEntry)
- {
- NS_PRECONDITION(aURI, "uri is null");
- NS_PRECONDITION(!aChannel || !aTriggeringPrincipal, "Shouldn't have both set");
- #if defined(DEBUG)
- if (MOZ_LOG_TEST(gDocShellLog, LogLevel::Debug)) {
- nsAutoCString chanName;
- if (aChannel) {
- aChannel->GetName(chanName);
- } else {
- chanName.AssignLiteral("<no channel>");
- }
- MOZ_LOG(gDocShellLog, LogLevel::Debug,
- ("nsDocShell[%p]::AddToSessionHistory(\"%s\", [%s])\n",
- this, aURI->GetSpecOrDefault().get(), chanName.get()));
- }
- #endif
- nsresult rv = NS_OK;
- nsCOMPtr<nsISHEntry> entry;
- bool shouldPersist;
- shouldPersist = ShouldAddToSessionHistory(aURI);
- // Get a handle to the root docshell
- nsCOMPtr<nsIDocShellTreeItem> root;
- GetSameTypeRootTreeItem(getter_AddRefs(root));
- /*
- * If this is a LOAD_FLAGS_REPLACE_HISTORY in a subframe, we use
- * the existing SH entry in the page and replace the url and
- * other vitalities.
- */
- if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY) &&
- root != static_cast<nsIDocShellTreeItem*>(this)) {
- // This is a subframe
- entry = mOSHE;
- nsCOMPtr<nsISHContainer> shContainer(do_QueryInterface(entry));
- if (shContainer) {
- int32_t childCount = 0;
- shContainer->GetChildCount(&childCount);
- // Remove all children of this entry
- for (int32_t i = childCount - 1; i >= 0; i--) {
- nsCOMPtr<nsISHEntry> child;
- shContainer->GetChildAt(i, getter_AddRefs(child));
- shContainer->RemoveChild(child);
- }
- entry->AbandonBFCacheEntry();
- }
- }
- // Create a new entry if necessary.
- if (!entry) {
- entry = do_CreateInstance(NS_SHENTRY_CONTRACTID);
- if (!entry) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- }
- // Get the post data & referrer
- nsCOMPtr<nsIInputStream> inputStream;
- nsCOMPtr<nsIURI> originalURI;
- bool loadReplace = false;
- nsCOMPtr<nsIURI> referrerURI;
- uint32_t referrerPolicy = mozilla::net::RP_Default;
- nsCOMPtr<nsISupports> cacheKey;
- nsCOMPtr<nsIPrincipal> triggeringPrincipal = aTriggeringPrincipal;
- nsCOMPtr<nsIPrincipal> principalToInherit = aPrincipalToInherit;
- bool expired = false;
- bool discardLayoutState = false;
- nsCOMPtr<nsICacheInfoChannel> cacheChannel;
- if (aChannel) {
- cacheChannel = do_QueryInterface(aChannel);
- /* If there is a caching channel, get the Cache Key and store it
- * in SH.
- */
- if (cacheChannel) {
- cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
- }
- nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
- // Check if the httpChannel is hiding under a multipartChannel
- if (!httpChannel) {
- GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
- }
- if (httpChannel) {
- nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(httpChannel));
- if (uploadChannel) {
- uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
- }
- httpChannel->GetOriginalURI(getter_AddRefs(originalURI));
- uint32_t loadFlags;
- aChannel->GetLoadFlags(&loadFlags);
- loadReplace = loadFlags & nsIChannel::LOAD_REPLACE;
- httpChannel->GetReferrer(getter_AddRefs(referrerURI));
- httpChannel->GetReferrerPolicy(&referrerPolicy);
- discardLayoutState = ShouldDiscardLayoutState(httpChannel);
- }
- nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
- if (loadInfo) {
- if (!triggeringPrincipal) {
- triggeringPrincipal = loadInfo->TriggeringPrincipal();
- }
- // For now keep storing just the principal in the SHEntry.
- if (!principalToInherit) {
- if (loadInfo->GetLoadingSandboxed()) {
- if (loadInfo->LoadingPrincipal()) {
- principalToInherit = nsNullPrincipal::CreateWithInheritedAttributes(
- loadInfo->LoadingPrincipal());
- } else {
- // get the OriginAttributes
- NeckoOriginAttributes nAttrs;
- loadInfo->GetOriginAttributes(&nAttrs);
- PrincipalOriginAttributes pAttrs;
- pAttrs.InheritFromNecko(nAttrs);
- principalToInherit = nsNullPrincipal::Create(pAttrs);
- }
- } else {
- principalToInherit = loadInfo->PrincipalToInherit();
- }
- }
- }
- }
- // Title is set in nsDocShell::SetTitle()
- entry->Create(aURI, // uri
- EmptyString(), // Title
- inputStream, // Post data stream
- nullptr, // LayoutHistory state
- cacheKey, // CacheKey
- mContentTypeHint, // Content-type
- triggeringPrincipal, // Channel or provided principal
- principalToInherit,
- mHistoryID,
- mDynamicallyCreated);
- entry->SetOriginalURI(originalURI);
- entry->SetLoadReplace(loadReplace);
- entry->SetReferrerURI(referrerURI);
- entry->SetReferrerPolicy(referrerPolicy);
- nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(aChannel);
- if (inStrmChan) {
- bool isSrcdocChannel;
- inStrmChan->GetIsSrcdocChannel(&isSrcdocChannel);
- if (isSrcdocChannel) {
- nsAutoString srcdoc;
- inStrmChan->GetSrcdocData(srcdoc);
- entry->SetSrcdocData(srcdoc);
- nsCOMPtr<nsIURI> baseURI;
- inStrmChan->GetBaseURI(getter_AddRefs(baseURI));
- entry->SetBaseURI(baseURI);
- }
- }
- /* If cache got a 'no-store', ask SH not to store
- * HistoryLayoutState. By default, SH will set this
- * flag to true and save HistoryLayoutState.
- */
- if (discardLayoutState) {
- entry->SetSaveLayoutStateFlag(false);
- }
- if (cacheChannel) {
- // Check if the page has expired from cache
- uint32_t expTime = 0;
- cacheChannel->GetCacheTokenExpirationTime(&expTime);
- uint32_t now = PRTimeToSeconds(PR_Now());
- if (expTime <= now) {
- expired = true;
- }
- }
- if (expired) {
- entry->SetExpirationStatus(true);
- }
- if (root == static_cast<nsIDocShellTreeItem*>(this) && mSessionHistory) {
- // If we need to clone our children onto the new session
- // history entry, do so now.
- if (aCloneChildren && mOSHE) {
- uint32_t cloneID;
- mOSHE->GetID(&cloneID);
- nsCOMPtr<nsISHEntry> newEntry;
- CloneAndReplace(mOSHE, this, cloneID, entry, true,
- getter_AddRefs(newEntry));
- NS_ASSERTION(entry == newEntry,
- "The new session history should be in the new entry");
- }
- // This is the root docshell
- bool addToSHistory = !LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY);
- if (!addToSHistory) {
- // Replace current entry in session history; If the requested index is
- // valid, it indicates the loading was triggered by a history load, and
- // we should replace the entry at requested index instead.
- int32_t index = 0;
- mSessionHistory->GetRequestedIndex(&index);
- if (index == -1) {
- mSessionHistory->GetIndex(&index);
- }
- nsCOMPtr<nsISHistoryInternal> shPrivate =
- do_QueryInterface(mSessionHistory);
- // Replace the current entry with the new entry
- if (index >= 0) {
- if (shPrivate) {
- rv = shPrivate->ReplaceEntry(index, entry);
- }
- } else {
- // If we're trying to replace an inexistant shistory entry, append.
- addToSHistory = true;
- }
- }
- if (addToSHistory) {
- // Add to session history
- nsCOMPtr<nsISHistoryInternal> shPrivate =
- do_QueryInterface(mSessionHistory);
- NS_ENSURE_TRUE(shPrivate, NS_ERROR_FAILURE);
- mSessionHistory->GetIndex(&mPreviousTransIndex);
- rv = shPrivate->AddEntry(entry, shouldPersist);
- mSessionHistory->GetIndex(&mLoadedTransIndex);
- #ifdef DEBUG_PAGE_CACHE
- printf("Previous index: %d, Loaded index: %d\n\n",
- mPreviousTransIndex, mLoadedTransIndex);
- #endif
- }
- } else {
- // This is a subframe.
- if (!mOSHE || !LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) {
- rv = AddChildSHEntryToParent(entry, mChildOffset, aCloneChildren);
- }
- }
- // Return the new SH entry...
- if (aNewEntry) {
- *aNewEntry = nullptr;
- if (NS_SUCCEEDED(rv)) {
- entry.forget(aNewEntry);
- }
- }
- return rv;
- }
- nsresult
- nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType)
- {
- if (!IsNavigationAllowed()) {
- return NS_OK;
- }
- nsCOMPtr<nsIURI> uri;
- nsCOMPtr<nsIURI> originalURI;
- bool loadReplace = false;
- nsCOMPtr<nsIInputStream> postData;
- nsCOMPtr<nsIURI> referrerURI;
- uint32_t referrerPolicy;
- nsAutoCString contentType;
- nsCOMPtr<nsIPrincipal> triggeringPrincipal;
- nsCOMPtr<nsIPrincipal> principalToInherit;
- NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(aEntry->GetOriginalURI(getter_AddRefs(originalURI)),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(aEntry->GetLoadReplace(&loadReplace),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(aEntry->GetReferrerPolicy(&referrerPolicy),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(aEntry->GetContentType(contentType), NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(aEntry->GetTriggeringPrincipal(getter_AddRefs(triggeringPrincipal)),
- NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(aEntry->GetPrincipalToInherit(getter_AddRefs(principalToInherit)),
- NS_ERROR_FAILURE);
- // Calling CreateAboutBlankContentViewer can set mOSHE to null, and if
- // that's the only thing holding a ref to aEntry that will cause aEntry to
- // die while we're loading it. So hold a strong ref to aEntry here, just
- // in case.
- nsCOMPtr<nsISHEntry> kungFuDeathGrip(aEntry);
- bool isJS;
- nsresult rv = uri->SchemeIs("javascript", &isJS);
- if (NS_FAILED(rv) || isJS) {
- // We're loading a URL that will execute script from inside asyncOpen.
- // Replace the current document with about:blank now to prevent
- // anything from the current document from leaking into any JavaScript
- // code in the URL.
- // Don't cache the presentation if we're going to just reload the
- // current entry. Caching would lead to trying to save the different
- // content viewers in the same nsISHEntry object.
- rv = CreateAboutBlankContentViewer(principalToInherit, nullptr,
- aEntry != mOSHE);
- if (NS_FAILED(rv)) {
- // The creation of the intermittent about:blank content
- // viewer failed for some reason (potentially because the
- // user prevented it). Interrupt the history load.
- return NS_OK;
- }
- if (!triggeringPrincipal) {
- // Ensure that we have a triggeringPrincipal. Otherwise javascript:
- // URIs will pick it up from the about:blank page we just loaded,
- // and we don't really want even that in this case.
- triggeringPrincipal = nsNullPrincipal::CreateWithInheritedAttributes(this);
- }
- }
- /* If there is a valid postdata *and* the user pressed
- * reload or shift-reload, take user's permission before we
- * repost the data to the server.
- */
- if ((aLoadType & LOAD_CMD_RELOAD) && postData) {
- bool repost;
- rv = ConfirmRepost(&repost);
- if (NS_FAILED(rv)) {
- return rv;
- }
- // If the user pressed cancel in the dialog, return. We're done here.
- if (!repost) {
- return NS_BINDING_ABORTED;
- }
- }
- // Do not inherit principal from document (security-critical!);
- uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
- nsAutoString srcdoc;
- bool isSrcdoc;
- nsCOMPtr<nsIURI> baseURI;
- aEntry->GetIsSrcdocEntry(&isSrcdoc);
- if (isSrcdoc) {
- aEntry->GetSrcdocData(srcdoc);
- aEntry->GetBaseURI(getter_AddRefs(baseURI));
- flags |= INTERNAL_LOAD_FLAGS_IS_SRCDOC;
- } else {
- srcdoc = NullString();
- }
- if (!triggeringPrincipal) {
- triggeringPrincipal = nsContentUtils::GetSystemPrincipal();
- }
- // Passing nullptr as aSourceDocShell gives the same behaviour as before
- // aSourceDocShell was introduced. According to spec we should be passing
- // the source browsing context that was used when the history entry was
- // first created. bug 947716 has been created to address this issue.
- rv = InternalLoad(uri,
- originalURI,
- loadReplace,
- false, // Is from processing frame attributes
- referrerURI,
- referrerPolicy,
- triggeringPrincipal,
- principalToInherit,
- flags,
- EmptyString(), // No window target
- contentType.get(), // Type hint
- NullString(), // No forced file download
- postData, // Post data stream
- nullptr, // No headers stream
- aLoadType, // Load type
- aEntry, // SHEntry
- true,
- srcdoc,
- nullptr, // Source docshell, see comment above
- baseURI,
- nullptr, // No nsIDocShell
- nullptr); // No nsIRequest
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::GetShouldSaveLayoutState(bool* aShould)
- {
- *aShould = false;
- if (mOSHE) {
- // Don't capture historystate and save it in history
- // if the page asked not to do so.
- mOSHE->GetSaveLayoutStateFlag(aShould);
- }
- return NS_OK;
- }
- nsresult
- nsDocShell::PersistLayoutHistoryState()
- {
- nsresult rv = NS_OK;
- if (mOSHE) {
- bool scrollRestorationIsManual = false;
- mOSHE->GetScrollRestorationIsManual(&scrollRestorationIsManual);
- nsCOMPtr<nsIPresShell> shell = GetPresShell();
- nsCOMPtr<nsILayoutHistoryState> layoutState;
- if (shell) {
- rv = shell->CaptureHistoryState(getter_AddRefs(layoutState));
- } else if (scrollRestorationIsManual) {
- // Even if we don't have layout anymore, we may want to reset the current
- // scroll state in layout history.
- GetLayoutHistoryState(getter_AddRefs(layoutState));
- }
- if (scrollRestorationIsManual && layoutState) {
- layoutState->ResetScrollState();
- }
- }
- return rv;
- }
- /* static */ nsresult
- nsDocShell::WalkHistoryEntries(nsISHEntry* aRootEntry,
- nsDocShell* aRootShell,
- WalkHistoryEntriesFunc aCallback,
- void* aData)
- {
- NS_ENSURE_TRUE(aRootEntry, NS_ERROR_FAILURE);
- nsCOMPtr<nsISHContainer> container(do_QueryInterface(aRootEntry));
- if (!container) {
- return NS_ERROR_FAILURE;
- }
- int32_t childCount;
- container->GetChildCount(&childCount);
- for (int32_t i = 0; i < childCount; i++) {
- nsCOMPtr<nsISHEntry> childEntry;
- container->GetChildAt(i, getter_AddRefs(childEntry));
- if (!childEntry) {
- // childEntry can be null for valid reasons, for example if the
- // docshell at index i never loaded anything useful.
- // Remember to clone also nulls in the child array (bug 464064).
- aCallback(nullptr, nullptr, i, aData);
- continue;
- }
- nsDocShell* childShell = nullptr;
- if (aRootShell) {
- // Walk the children of aRootShell and see if one of them
- // has srcChild as a SHEntry.
- nsTObserverArray<nsDocLoader*>::ForwardIterator iter(
- aRootShell->mChildList);
- while (iter.HasMore()) {
- nsDocShell* child = static_cast<nsDocShell*>(iter.GetNext());
- if (child->HasHistoryEntry(childEntry)) {
- childShell = child;
- break;
- }
- }
- }
- nsresult rv = aCallback(childEntry, childShell, i, aData);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- return NS_OK;
- }
- // callback data for WalkHistoryEntries
- struct MOZ_STACK_CLASS CloneAndReplaceData
- {
- CloneAndReplaceData(uint32_t aCloneID, nsISHEntry* aReplaceEntry,
- bool aCloneChildren, nsISHEntry* aDestTreeParent)
- : cloneID(aCloneID)
- , cloneChildren(aCloneChildren)
- , replaceEntry(aReplaceEntry)
- , destTreeParent(aDestTreeParent)
- {
- }
- uint32_t cloneID;
- bool cloneChildren;
- nsISHEntry* replaceEntry;
- nsISHEntry* destTreeParent;
- nsCOMPtr<nsISHEntry> resultEntry;
- };
- /* static */ nsresult
- nsDocShell::CloneAndReplaceChild(nsISHEntry* aEntry, nsDocShell* aShell,
- int32_t aEntryIndex, void* aData)
- {
- nsCOMPtr<nsISHEntry> dest;
- CloneAndReplaceData* data = static_cast<CloneAndReplaceData*>(aData);
- uint32_t cloneID = data->cloneID;
- nsISHEntry* replaceEntry = data->replaceEntry;
- nsCOMPtr<nsISHContainer> container = do_QueryInterface(data->destTreeParent);
- if (!aEntry) {
- if (container) {
- container->AddChild(nullptr, aEntryIndex);
- }
- return NS_OK;
- }
- uint32_t srcID;
- aEntry->GetID(&srcID);
- nsresult rv = NS_OK;
- if (srcID == cloneID) {
- // Replace the entry
- dest = replaceEntry;
- } else {
- // Clone the SHEntry...
- rv = aEntry->Clone(getter_AddRefs(dest));
- NS_ENSURE_SUCCESS(rv, rv);
- }
- dest->SetIsSubFrame(true);
- if (srcID != cloneID || data->cloneChildren) {
- // Walk the children
- CloneAndReplaceData childData(cloneID, replaceEntry,
- data->cloneChildren, dest);
- rv = WalkHistoryEntries(aEntry, aShell,
- CloneAndReplaceChild, &childData);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- if (srcID != cloneID && aShell) {
- aShell->SwapHistoryEntries(aEntry, dest);
- }
- if (container) {
- container->AddChild(dest, aEntryIndex);
- }
- data->resultEntry = dest;
- return rv;
- }
- /* static */ nsresult
- nsDocShell::CloneAndReplace(nsISHEntry* aSrcEntry,
- nsDocShell* aSrcShell,
- uint32_t aCloneID,
- nsISHEntry* aReplaceEntry,
- bool aCloneChildren,
- nsISHEntry** aResultEntry)
- {
- NS_ENSURE_ARG_POINTER(aResultEntry);
- NS_ENSURE_TRUE(aReplaceEntry, NS_ERROR_FAILURE);
- CloneAndReplaceData data(aCloneID, aReplaceEntry, aCloneChildren, nullptr);
- nsresult rv = CloneAndReplaceChild(aSrcEntry, aSrcShell, 0, &data);
- data.resultEntry.swap(*aResultEntry);
- return rv;
- }
- void
- nsDocShell::SwapHistoryEntries(nsISHEntry* aOldEntry, nsISHEntry* aNewEntry)
- {
- if (aOldEntry == mOSHE) {
- mOSHE = aNewEntry;
- }
- if (aOldEntry == mLSHE) {
- mLSHE = aNewEntry;
- }
- }
- struct SwapEntriesData
- {
- nsDocShell* ignoreShell; // constant; the shell to ignore
- nsISHEntry* destTreeRoot; // constant; the root of the dest tree
- nsISHEntry* destTreeParent; // constant; the node under destTreeRoot
- // whose children will correspond to aEntry
- };
- nsresult
- nsDocShell::SetChildHistoryEntry(nsISHEntry* aEntry, nsDocShell* aShell,
- int32_t aEntryIndex, void* aData)
- {
- SwapEntriesData* data = static_cast<SwapEntriesData*>(aData);
- nsDocShell* ignoreShell = data->ignoreShell;
- if (!aShell || aShell == ignoreShell) {
- return NS_OK;
- }
- nsISHEntry* destTreeRoot = data->destTreeRoot;
- nsCOMPtr<nsISHEntry> destEntry;
- nsCOMPtr<nsISHContainer> container = do_QueryInterface(data->destTreeParent);
- if (container) {
- // aEntry is a clone of some child of destTreeParent, but since the
- // trees aren't necessarily in sync, we'll have to locate it.
- // Note that we could set aShell's entry to null if we don't find a
- // corresponding entry under destTreeParent.
- uint32_t targetID, id;
- aEntry->GetID(&targetID);
- // First look at the given index, since this is the common case.
- nsCOMPtr<nsISHEntry> entry;
- container->GetChildAt(aEntryIndex, getter_AddRefs(entry));
- if (entry && NS_SUCCEEDED(entry->GetID(&id)) && id == targetID) {
- destEntry.swap(entry);
- } else {
- int32_t childCount;
- container->GetChildCount(&childCount);
- for (int32_t i = 0; i < childCount; ++i) {
- container->GetChildAt(i, getter_AddRefs(entry));
- if (!entry) {
- continue;
- }
- entry->GetID(&id);
- if (id == targetID) {
- destEntry.swap(entry);
- break;
- }
- }
- }
- } else {
- destEntry = destTreeRoot;
- }
- aShell->SwapHistoryEntries(aEntry, destEntry);
- // Now handle the children of aEntry.
- SwapEntriesData childData = { ignoreShell, destTreeRoot, destEntry };
- return WalkHistoryEntries(aEntry, aShell, SetChildHistoryEntry, &childData);
- }
- static nsISHEntry*
- GetRootSHEntry(nsISHEntry* aEntry)
- {
- nsCOMPtr<nsISHEntry> rootEntry = aEntry;
- nsISHEntry* result = nullptr;
- while (rootEntry) {
- result = rootEntry;
- result->GetParent(getter_AddRefs(rootEntry));
- }
- return result;
- }
- void
- nsDocShell::SetHistoryEntry(nsCOMPtr<nsISHEntry>* aPtr, nsISHEntry* aEntry)
- {
- // We need to sync up the docshell and session history trees for
- // subframe navigation. If the load was in a subframe, we forward up to
- // the root docshell, which will then recursively sync up all docshells
- // to their corresponding entries in the new session history tree.
- // If we don't do this, then we can cache a content viewer on the wrong
- // cloned entry, and subsequently restore it at the wrong time.
- nsISHEntry* newRootEntry = GetRootSHEntry(aEntry);
- if (newRootEntry) {
- // newRootEntry is now the new root entry.
- // Find the old root entry as well.
- // Need a strong ref. on |oldRootEntry| so it isn't destroyed when
- // SetChildHistoryEntry() does SwapHistoryEntries() (bug 304639).
- nsCOMPtr<nsISHEntry> oldRootEntry = GetRootSHEntry(*aPtr);
- if (oldRootEntry) {
- nsCOMPtr<nsIDocShellTreeItem> rootAsItem;
- GetSameTypeRootTreeItem(getter_AddRefs(rootAsItem));
- nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(rootAsItem);
- if (rootShell) { // if we're the root just set it, nothing to swap
- SwapEntriesData data = { this, newRootEntry };
- nsIDocShell* rootIDocShell = static_cast<nsIDocShell*>(rootShell);
- nsDocShell* rootDocShell = static_cast<nsDocShell*>(rootIDocShell);
- #ifdef DEBUG
- nsresult rv =
- #endif
- SetChildHistoryEntry(oldRootEntry, rootDocShell, 0, &data);
- NS_ASSERTION(NS_SUCCEEDED(rv), "SetChildHistoryEntry failed");
- }
- }
- }
- *aPtr = aEntry;
- }
- nsresult
- nsDocShell::GetRootSessionHistory(nsISHistory** aReturn)
- {
- nsresult rv;
- nsCOMPtr<nsIDocShellTreeItem> root;
- // Get the root docshell
- rv = GetSameTypeRootTreeItem(getter_AddRefs(root));
- // QI to nsIWebNavigation
- nsCOMPtr<nsIWebNavigation> rootAsWebnav(do_QueryInterface(root));
- if (rootAsWebnav) {
- // Get the handle to SH from the root docshell
- rv = rootAsWebnav->GetSessionHistory(aReturn);
- }
- return rv;
- }
- nsresult
- nsDocShell::GetHttpChannel(nsIChannel* aChannel, nsIHttpChannel** aReturn)
- {
- NS_ENSURE_ARG_POINTER(aReturn);
- if (!aChannel) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsIMultiPartChannel> multiPartChannel(do_QueryInterface(aChannel));
- if (multiPartChannel) {
- nsCOMPtr<nsIChannel> baseChannel;
- multiPartChannel->GetBaseChannel(getter_AddRefs(baseChannel));
- nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(baseChannel));
- *aReturn = httpChannel;
- NS_IF_ADDREF(*aReturn);
- }
- return NS_OK;
- }
- bool
- nsDocShell::ShouldDiscardLayoutState(nsIHttpChannel* aChannel)
- {
- // By default layout State will be saved.
- if (!aChannel) {
- return false;
- }
- // figure out if SH should be saving layout state
- bool noStore = false;
- aChannel->IsNoStoreResponse(&noStore);
- return noStore;
- }
- NS_IMETHODIMP
- nsDocShell::GetEditor(nsIEditor** aEditor)
- {
- NS_ENSURE_ARG_POINTER(aEditor);
- if (!mEditorData) {
- *aEditor = nullptr;
- return NS_OK;
- }
- return mEditorData->GetEditor(aEditor);
- }
- NS_IMETHODIMP
- nsDocShell::SetEditor(nsIEditor* aEditor)
- {
- nsresult rv = EnsureEditorData();
- if (NS_FAILED(rv)) {
- return rv;
- }
- return mEditorData->SetEditor(aEditor);
- }
- NS_IMETHODIMP
- nsDocShell::GetEditable(bool* aEditable)
- {
- NS_ENSURE_ARG_POINTER(aEditable);
- *aEditable = mEditorData && mEditorData->GetEditable();
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetHasEditingSession(bool* aHasEditingSession)
- {
- NS_ENSURE_ARG_POINTER(aHasEditingSession);
- if (mEditorData) {
- nsCOMPtr<nsIEditingSession> editingSession;
- mEditorData->GetEditingSession(getter_AddRefs(editingSession));
- *aHasEditingSession = (editingSession.get() != nullptr);
- } else {
- *aHasEditingSession = false;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::MakeEditable(bool aInWaitForUriLoad)
- {
- nsresult rv = EnsureEditorData();
- if (NS_FAILED(rv)) {
- return rv;
- }
- return mEditorData->MakeEditable(aInWaitForUriLoad);
- }
- bool
- nsDocShell::ChannelIsPost(nsIChannel* aChannel)
- {
- nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
- if (!httpChannel) {
- return false;
- }
- nsAutoCString method;
- httpChannel->GetRequestMethod(method);
- return method.EqualsLiteral("POST");
- }
- void
- nsDocShell::ExtractLastVisit(nsIChannel* aChannel,
- nsIURI** aURI,
- uint32_t* aChannelRedirectFlags)
- {
- nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel));
- if (!props) {
- return;
- }
- nsresult rv = props->GetPropertyAsInterface(
- NS_LITERAL_STRING("docshell.previousURI"),
- NS_GET_IID(nsIURI),
- reinterpret_cast<void**>(aURI));
- if (NS_FAILED(rv)) {
- // There is no last visit for this channel, so this must be the first
- // link. Link the visit to the referrer of this request, if any.
- // Treat referrer as null if there is an error getting it.
- (void)NS_GetReferrerFromChannel(aChannel, aURI);
- } else {
- rv = props->GetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
- aChannelRedirectFlags);
- NS_WARNING_ASSERTION(
- NS_SUCCEEDED(rv),
- "Could not fetch previous flags, URI will be treated like referrer");
- }
- }
- void
- nsDocShell::SaveLastVisit(nsIChannel* aChannel,
- nsIURI* aURI,
- uint32_t aChannelRedirectFlags)
- {
- nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel));
- if (!props || !aURI) {
- return;
- }
- props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"),
- aURI);
- props->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
- aChannelRedirectFlags);
- }
- void
- nsDocShell::AddURIVisit(nsIURI* aURI,
- nsIURI* aReferrerURI,
- nsIURI* aPreviousURI,
- uint32_t aChannelRedirectFlags,
- uint32_t aResponseStatus)
- {
- MOZ_ASSERT(aURI, "Visited URI is null!");
- MOZ_ASSERT(mLoadType != LOAD_ERROR_PAGE &&
- mLoadType != LOAD_BYPASS_HISTORY,
- "Do not add error or bypass pages to global history");
- // Only content-type docshells save URI visits. Also don't do
- // anything here if we're not supposed to use global history.
- if (mItemType != typeContent || !mUseGlobalHistory || UsePrivateBrowsing()) {
- return;
- }
- nsCOMPtr<IHistory> history = services::GetHistoryService();
- if (history) {
- uint32_t visitURIFlags = 0;
- if (!IsFrame()) {
- visitURIFlags |= IHistory::TOP_LEVEL;
- }
- if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) {
- visitURIFlags |= IHistory::REDIRECT_TEMPORARY;
- } else if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_PERMANENT) {
- visitURIFlags |= IHistory::REDIRECT_PERMANENT;
- }
- if (aResponseStatus >= 300 && aResponseStatus < 400) {
- visitURIFlags |= IHistory::REDIRECT_SOURCE;
- }
- // Errors 400-501 and 505 are considered unrecoverable, in the sense a
- // simple retry attempt by the user is unlikely to solve them.
- // 408 is special cased, since may actually indicate a temporary
- // connection problem.
- else if (aResponseStatus != 408 &&
- ((aResponseStatus >= 400 && aResponseStatus <= 501) ||
- aResponseStatus == 505)) {
- visitURIFlags |= IHistory::UNRECOVERABLE_ERROR;
- }
- (void)history->VisitURI(aURI, aPreviousURI, visitURIFlags);
- } else if (mGlobalHistory) {
- // Falls back to sync global history interface.
- (void)mGlobalHistory->AddURI(aURI,
- !!aChannelRedirectFlags,
- !IsFrame(),
- aReferrerURI);
- }
- }
- //*****************************************************************************
- // nsDocShell: Helper Routines
- //*****************************************************************************
- NS_IMETHODIMP
- nsDocShell::SetLoadType(uint32_t aLoadType)
- {
- mLoadType = aLoadType;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetLoadType(uint32_t* aLoadType)
- {
- *aLoadType = mLoadType;
- return NS_OK;
- }
- nsresult
- nsDocShell::ConfirmRepost(bool* aRepost)
- {
- nsCOMPtr<nsIPrompt> prompter;
- CallGetInterface(this, static_cast<nsIPrompt**>(getter_AddRefs(prompter)));
- if (!prompter) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- nsCOMPtr<nsIStringBundleService> stringBundleService =
- mozilla::services::GetStringBundleService();
- if (!stringBundleService) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsIStringBundle> appBundle;
- nsresult rv = stringBundleService->CreateBundle(kAppstringsBundleURL,
- getter_AddRefs(appBundle));
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIStringBundle> brandBundle;
- rv = stringBundleService->CreateBundle(kBrandBundleURL,
- getter_AddRefs(brandBundle));
- NS_ENSURE_SUCCESS(rv, rv);
- NS_ASSERTION(prompter && brandBundle && appBundle,
- "Unable to set up repost prompter.");
- nsXPIDLString brandName;
- rv = brandBundle->GetStringFromName(u"brandShortName",
- getter_Copies(brandName));
- nsXPIDLString msgString, button0Title;
- if (NS_FAILED(rv)) { // No brand, use the generic version.
- rv = appBundle->GetStringFromName(u"confirmRepostPrompt",
- getter_Copies(msgString));
- } else {
- // Brand available - if the app has an override file with formatting, the
- // app name will be included. Without an override, the prompt will look
- // like the generic version.
- const char16_t* formatStrings[] = { brandName.get() };
- rv = appBundle->FormatStringFromName(u"confirmRepostPrompt",
- formatStrings,
- ArrayLength(formatStrings),
- getter_Copies(msgString));
- }
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = appBundle->GetStringFromName(u"resendButton.label",
- getter_Copies(button0Title));
- if (NS_FAILED(rv)) {
- return rv;
- }
- int32_t buttonPressed;
- // The actual value here is irrelevant, but we can't pass an invalid
- // bool through XPConnect.
- bool checkState = false;
- rv = prompter->ConfirmEx(
- nullptr, msgString.get(),
- (nsIPrompt::BUTTON_POS_0 * nsIPrompt::BUTTON_TITLE_IS_STRING) +
- (nsIPrompt::BUTTON_POS_1 * nsIPrompt::BUTTON_TITLE_CANCEL),
- button0Title.get(), nullptr, nullptr, nullptr, &checkState, &buttonPressed);
- if (NS_FAILED(rv)) {
- return rv;
- }
- *aRepost = (buttonPressed == 0);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetPromptAndStringBundle(nsIPrompt** aPrompt,
- nsIStringBundle** aStringBundle)
- {
- NS_ENSURE_SUCCESS(GetInterface(NS_GET_IID(nsIPrompt), (void**)aPrompt),
- NS_ERROR_FAILURE);
- nsCOMPtr<nsIStringBundleService> stringBundleService =
- mozilla::services::GetStringBundleService();
- NS_ENSURE_TRUE(stringBundleService, NS_ERROR_FAILURE);
- NS_ENSURE_SUCCESS(
- stringBundleService->CreateBundle(kAppstringsBundleURL, aStringBundle),
- NS_ERROR_FAILURE);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetChildOffset(nsIDOMNode* aChild, nsIDOMNode* aParent,
- int32_t* aOffset)
- {
- NS_ENSURE_ARG_POINTER(aChild || aParent);
- nsCOMPtr<nsIDOMNodeList> childNodes;
- NS_ENSURE_SUCCESS(aParent->GetChildNodes(getter_AddRefs(childNodes)),
- NS_ERROR_FAILURE);
- NS_ENSURE_TRUE(childNodes, NS_ERROR_FAILURE);
- int32_t i = 0;
- for (; true; i++) {
- nsCOMPtr<nsIDOMNode> childNode;
- NS_ENSURE_SUCCESS(childNodes->Item(i, getter_AddRefs(childNode)),
- NS_ERROR_FAILURE);
- NS_ENSURE_TRUE(childNode, NS_ERROR_FAILURE);
- if (childNode.get() == aChild) {
- *aOffset = i;
- return NS_OK;
- }
- }
- return NS_ERROR_FAILURE;
- }
- nsIScrollableFrame*
- nsDocShell::GetRootScrollFrame()
- {
- nsCOMPtr<nsIPresShell> shell = GetPresShell();
- NS_ENSURE_TRUE(shell, nullptr);
- return shell->GetRootScrollFrameAsScrollableExternal();
- }
- NS_IMETHODIMP
- nsDocShell::EnsureScriptEnvironment()
- {
- if (mScriptGlobal) {
- return NS_OK;
- }
- if (mIsBeingDestroyed) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- #ifdef DEBUG
- NS_ASSERTION(!mInEnsureScriptEnv,
- "Infinite loop! Calling EnsureScriptEnvironment() from "
- "within EnsureScriptEnvironment()!");
- // Yeah, this isn't re-entrant safe, but that's ok since if we
- // re-enter this method, we'll infinitely loop...
- AutoRestore<bool> boolSetter(mInEnsureScriptEnv);
- mInEnsureScriptEnv = true;
- #endif
- nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
- NS_ENSURE_TRUE(browserChrome, NS_ERROR_NOT_AVAILABLE);
- uint32_t chromeFlags;
- browserChrome->GetChromeFlags(&chromeFlags);
- // If our window is modal and we're not opened as chrome, make
- // this window a modal content window.
- mScriptGlobal = NS_NewScriptGlobalObject(mItemType == typeChrome);
- MOZ_ASSERT(mScriptGlobal);
- mScriptGlobal->SetDocShell(this);
- // Ensure the script object is set up to run script.
- return mScriptGlobal->EnsureScriptEnvironment();
- }
- NS_IMETHODIMP
- nsDocShell::EnsureEditorData()
- {
- bool openDocHasDetachedEditor = mOSHE && mOSHE->HasDetachedEditor();
- if (!mEditorData && !mIsBeingDestroyed && !openDocHasDetachedEditor) {
- // We shouldn't recreate the editor data if it already exists, or
- // we're shutting down, or we already have a detached editor data
- // stored in the session history. We should only have one editordata
- // per docshell.
- mEditorData = new nsDocShellEditorData(this);
- }
- return mEditorData ? NS_OK : NS_ERROR_NOT_AVAILABLE;
- }
- nsresult
- nsDocShell::EnsureTransferableHookData()
- {
- if (!mTransferableHookData) {
- mTransferableHookData = new nsTransferableHookData();
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::EnsureFind()
- {
- nsresult rv;
- if (!mFind) {
- mFind = do_CreateInstance("@mozilla.org/embedcomp/find;1", &rv);
- if (NS_FAILED(rv)) {
- return rv;
- }
- }
- // we promise that the nsIWebBrowserFind that we return has been set
- // up to point to the focused, or content window, so we have to
- // set that up each time.
- nsIScriptGlobalObject* scriptGO = GetScriptGlobalObject();
- NS_ENSURE_TRUE(scriptGO, NS_ERROR_UNEXPECTED);
- // default to our window
- nsCOMPtr<nsPIDOMWindowOuter> ourWindow = do_QueryInterface(scriptGO);
- nsCOMPtr<nsPIDOMWindowOuter> windowToSearch;
- nsFocusManager::GetFocusedDescendant(ourWindow, true,
- getter_AddRefs(windowToSearch));
- nsCOMPtr<nsIWebBrowserFindInFrames> findInFrames = do_QueryInterface(mFind);
- if (!findInFrames) {
- return NS_ERROR_NO_INTERFACE;
- }
- rv = findInFrames->SetRootSearchFrame(ourWindow);
- if (NS_FAILED(rv)) {
- return rv;
- }
- rv = findInFrames->SetCurrentSearchFrame(windowToSearch);
- if (NS_FAILED(rv)) {
- return rv;
- }
- return NS_OK;
- }
- bool
- nsDocShell::IsFrame()
- {
- nsCOMPtr<nsIDocShellTreeItem> parent;
- GetSameTypeParent(getter_AddRefs(parent));
- return !!parent;
- }
- NS_IMETHODIMP
- nsDocShell::IsBeingDestroyed(bool* aDoomed)
- {
- NS_ENSURE_ARG(aDoomed);
- *aDoomed = mIsBeingDestroyed;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetIsExecutingOnLoadHandler(bool* aResult)
- {
- NS_ENSURE_ARG(aResult);
- *aResult = mIsExecutingOnLoadHandler;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetLayoutHistoryState(nsILayoutHistoryState** aLayoutHistoryState)
- {
- if (mOSHE) {
- mOSHE->GetLayoutHistoryState(aLayoutHistoryState);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetLayoutHistoryState(nsILayoutHistoryState* aLayoutHistoryState)
- {
- if (mOSHE) {
- mOSHE->SetLayoutHistoryState(aLayoutHistoryState);
- }
- return NS_OK;
- }
- nsRefreshTimer::nsRefreshTimer()
- : mDelay(0), mRepeat(false), mMetaRefresh(false)
- {
- }
- nsRefreshTimer::~nsRefreshTimer()
- {
- }
- NS_IMPL_ADDREF(nsRefreshTimer)
- NS_IMPL_RELEASE(nsRefreshTimer)
- NS_INTERFACE_MAP_BEGIN(nsRefreshTimer)
- NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITimerCallback)
- NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
- NS_INTERFACE_MAP_END_THREADSAFE
- NS_IMETHODIMP
- nsRefreshTimer::Notify(nsITimer* aTimer)
- {
- NS_ASSERTION(mDocShell, "DocShell is somehow null");
- if (mDocShell && aTimer) {
- // Get the delay count to determine load type
- uint32_t delay = 0;
- aTimer->GetDelay(&delay);
- mDocShell->ForceRefreshURIFromTimer(mURI, delay, mMetaRefresh, aTimer, mPrincipal);
- }
- return NS_OK;
- }
- nsDocShell::InterfaceRequestorProxy::InterfaceRequestorProxy(
- nsIInterfaceRequestor* aRequestor)
- {
- if (aRequestor) {
- mWeakPtr = do_GetWeakReference(aRequestor);
- }
- }
- nsDocShell::InterfaceRequestorProxy::~InterfaceRequestorProxy()
- {
- mWeakPtr = nullptr;
- }
- NS_IMPL_ISUPPORTS(nsDocShell::InterfaceRequestorProxy, nsIInterfaceRequestor)
- NS_IMETHODIMP
- nsDocShell::InterfaceRequestorProxy::GetInterface(const nsIID& aIID,
- void** aSink)
- {
- NS_ENSURE_ARG_POINTER(aSink);
- nsCOMPtr<nsIInterfaceRequestor> ifReq = do_QueryReferent(mWeakPtr);
- if (ifReq) {
- return ifReq->GetInterface(aIID, aSink);
- }
- *aSink = nullptr;
- return NS_NOINTERFACE;
- }
- nsresult
- nsDocShell::SetBaseUrlForWyciwyg(nsIContentViewer* aContentViewer)
- {
- if (!aContentViewer) {
- return NS_ERROR_FAILURE;
- }
- nsCOMPtr<nsIURI> baseURI;
- nsresult rv = NS_ERROR_NOT_AVAILABLE;
- if (sURIFixup) {
- rv = sURIFixup->CreateExposableURI(mCurrentURI, getter_AddRefs(baseURI));
- }
- // Get the current document and set the base uri
- if (baseURI) {
- nsIDocument* document = aContentViewer->GetDocument();
- if (document) {
- document->SetBaseURI(baseURI);
- }
- }
- return rv;
- }
- //*****************************************************************************
- // nsDocShell::nsIAuthPromptProvider
- //*****************************************************************************
- NS_IMETHODIMP
- nsDocShell::GetAuthPrompt(uint32_t aPromptReason, const nsIID& aIID,
- void** aResult)
- {
- // a priority prompt request will override a false mAllowAuth setting
- bool priorityPrompt = (aPromptReason == PROMPT_PROXY);
- if (!mAllowAuth && !priorityPrompt) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- // we're either allowing auth, or it's a proxy request
- nsresult rv;
- nsCOMPtr<nsIPromptFactory> wwatch =
- do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
- NS_ENSURE_SUCCESS(rv, rv);
- rv = EnsureScriptEnvironment();
- NS_ENSURE_SUCCESS(rv, rv);
- // Get the an auth prompter for our window so that the parenting
- // of the dialogs works as it should when using tabs.
- return wwatch->GetPrompt(mScriptGlobal->AsOuter(), aIID,
- reinterpret_cast<void**>(aResult));
- }
- //*****************************************************************************
- // nsDocShell::nsILoadContext
- //*****************************************************************************
- NS_IMETHODIMP
- nsDocShell::GetAssociatedWindow(mozIDOMWindowProxy** aWindow)
- {
- CallGetInterface(this, aWindow);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetTopWindow(mozIDOMWindowProxy** aWindow)
- {
- nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
- if (win) {
- win = win->GetTop();
- }
- win.forget(aWindow);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetTopFrameElement(nsIDOMElement** aElement)
- {
- *aElement = nullptr;
- nsCOMPtr<nsPIDOMWindowOuter> win = GetWindow();
- if (!win) {
- return NS_OK;
- }
- nsCOMPtr<nsPIDOMWindowOuter> top = win->GetScriptableTop();
- NS_ENSURE_TRUE(top, NS_ERROR_FAILURE);
- // GetFrameElementInternal, /not/ GetScriptableFrameElement -- if |top| is
- // inside <iframe mozbrowser>, we want to return the iframe, not null.
- // And we want to cross the content/chrome boundary.
- nsCOMPtr<nsIDOMElement> elt =
- do_QueryInterface(top->GetFrameElementInternal());
- elt.forget(aElement);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetNestedFrameId(uint64_t* aId)
- {
- *aId = 0;
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::IsTrackingProtectionOn(bool* aIsTrackingProtectionOn)
- {
- if (Preferences::GetBool("privacy.trackingprotection.enabled", false)) {
- *aIsTrackingProtectionOn = true;
- } else if (UsePrivateBrowsing() &&
- Preferences::GetBool("privacy.trackingprotection.pbmode.enabled", false)) {
- *aIsTrackingProtectionOn = true;
- } else {
- *aIsTrackingProtectionOn = false;
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetIsContent(bool* aIsContent)
- {
- *aIsContent = (mItemType == typeContent);
- return NS_OK;
- }
- bool
- nsDocShell::IsOKToLoadURI(nsIURI* aURI)
- {
- NS_PRECONDITION(aURI, "Must have a URI!");
- if (!mFiredUnloadEvent) {
- return true;
- }
- if (!mLoadingURI) {
- return false;
- }
- nsCOMPtr<nsIScriptSecurityManager> secMan =
- do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
- return secMan &&
- NS_SUCCEEDED(secMan->CheckSameOriginURI(aURI, mLoadingURI, false));
- }
- //
- // Routines for selection and clipboard
- //
- nsresult
- nsDocShell::GetControllerForCommand(const char* aCommand,
- nsIController** aResult)
- {
- NS_ENSURE_ARG_POINTER(aResult);
- *aResult = nullptr;
- NS_ENSURE_TRUE(mScriptGlobal, NS_ERROR_FAILURE);
- nsCOMPtr<nsPIWindowRoot> root = mScriptGlobal->GetTopWindowRoot();
- NS_ENSURE_TRUE(root, NS_ERROR_FAILURE);
- return root->GetControllerForCommand(aCommand, aResult);
- }
- NS_IMETHODIMP
- nsDocShell::IsCommandEnabled(const char* aCommand, bool* aResult)
- {
- NS_ENSURE_ARG_POINTER(aResult);
- *aResult = false;
- nsresult rv = NS_ERROR_FAILURE;
- nsCOMPtr<nsIController> controller;
- rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
- if (controller) {
- rv = controller->IsCommandEnabled(aCommand, aResult);
- }
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::DoCommand(const char* aCommand)
- {
- nsresult rv = NS_ERROR_FAILURE;
- nsCOMPtr<nsIController> controller;
- rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
- if (controller) {
- rv = controller->DoCommand(aCommand);
- }
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::DoCommandWithParams(const char* aCommand, nsICommandParams* aParams)
- {
- nsCOMPtr<nsIController> controller;
- nsresult rv = GetControllerForCommand(aCommand, getter_AddRefs(controller));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- nsCOMPtr<nsICommandController> commandController =
- do_QueryInterface(controller, &rv);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
- return commandController->DoCommandWithParams(aCommand, aParams);
- }
- nsresult
- nsDocShell::EnsureCommandHandler()
- {
- if (!mCommandManager) {
- nsCOMPtr<nsPICommandUpdater> commandUpdater =
- do_CreateInstance("@mozilla.org/embedcomp/command-manager;1");
- if (!commandUpdater) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- nsCOMPtr<nsPIDOMWindowOuter> domWindow = GetWindow();
- nsresult rv = commandUpdater->Init(domWindow);
- if (NS_SUCCEEDED(rv)) {
- mCommandManager = do_QueryInterface(commandUpdater);
- }
- }
- return mCommandManager ? NS_OK : NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsDocShell::CanCutSelection(bool* aResult)
- {
- return IsCommandEnabled("cmd_cut", aResult);
- }
- NS_IMETHODIMP
- nsDocShell::CanCopySelection(bool* aResult)
- {
- return IsCommandEnabled("cmd_copy", aResult);
- }
- NS_IMETHODIMP
- nsDocShell::CanCopyLinkLocation(bool* aResult)
- {
- return IsCommandEnabled("cmd_copyLink", aResult);
- }
- NS_IMETHODIMP
- nsDocShell::CanCopyImageLocation(bool* aResult)
- {
- return IsCommandEnabled("cmd_copyImageLocation", aResult);
- }
- NS_IMETHODIMP
- nsDocShell::CanCopyImageContents(bool* aResult)
- {
- return IsCommandEnabled("cmd_copyImageContents", aResult);
- }
- NS_IMETHODIMP
- nsDocShell::CanPaste(bool* aResult)
- {
- return IsCommandEnabled("cmd_paste", aResult);
- }
- NS_IMETHODIMP
- nsDocShell::CutSelection(void)
- {
- return DoCommand("cmd_cut");
- }
- NS_IMETHODIMP
- nsDocShell::CopySelection(void)
- {
- return DoCommand("cmd_copy");
- }
- NS_IMETHODIMP
- nsDocShell::CopyLinkLocation(void)
- {
- return DoCommand("cmd_copyLink");
- }
- NS_IMETHODIMP
- nsDocShell::CopyImageLocation(void)
- {
- return DoCommand("cmd_copyImageLocation");
- }
- NS_IMETHODIMP
- nsDocShell::CopyImageContents(void)
- {
- return DoCommand("cmd_copyImageContents");
- }
- NS_IMETHODIMP
- nsDocShell::Paste(void)
- {
- return DoCommand("cmd_paste");
- }
- NS_IMETHODIMP
- nsDocShell::SelectAll(void)
- {
- return DoCommand("cmd_selectAll");
- }
- //
- // SelectNone
- //
- // Collapses the current selection, insertion point ends up at beginning
- // of previous selection.
- //
- NS_IMETHODIMP
- nsDocShell::SelectNone(void)
- {
- return DoCommand("cmd_selectNone");
- }
- // link handling
- class OnLinkClickEvent : public Runnable
- {
- public:
- OnLinkClickEvent(nsDocShell* aHandler, nsIContent* aContent,
- nsIURI* aURI,
- const char16_t* aTargetSpec,
- const nsAString& aFileName,
- nsIInputStream* aPostDataStream,
- nsIInputStream* aHeadersDataStream,
- bool aIsTrusted,
- nsIPrincipal* aTriggeringPrincipal);
- NS_IMETHOD Run() override
- {
- nsAutoPopupStatePusher popupStatePusher(mPopupState);
- // We need to set up an AutoJSAPI here for the following reason: When we do
- // OnLinkClickSync we'll eventually end up in nsGlobalWindow::OpenInternal
- // which only does popup blocking if !LegacyIsCallerChromeOrNativeCode().
- // So we need to fake things so that we don't look like native code as far
- // as LegacyIsCallerNativeCode() is concerned.
- AutoJSAPI jsapi;
- if (mIsTrusted || jsapi.Init(mContent->OwnerDoc()->GetScopeObject())) {
- mHandler->OnLinkClickSync(mContent, mURI,
- mTargetSpec.get(), mFileName,
- mPostDataStream, mHeadersDataStream,
- nullptr, nullptr, mTriggeringPrincipal);
- }
- return NS_OK;
- }
- private:
- RefPtr<nsDocShell> mHandler;
- nsCOMPtr<nsIURI> mURI;
- nsString mTargetSpec;
- nsString mFileName;
- nsCOMPtr<nsIInputStream> mPostDataStream;
- nsCOMPtr<nsIInputStream> mHeadersDataStream;
- nsCOMPtr<nsIContent> mContent;
- PopupControlState mPopupState;
- bool mIsTrusted;
- nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
- };
- OnLinkClickEvent::OnLinkClickEvent(nsDocShell* aHandler,
- nsIContent* aContent,
- nsIURI* aURI,
- const char16_t* aTargetSpec,
- const nsAString& aFileName,
- nsIInputStream* aPostDataStream,
- nsIInputStream* aHeadersDataStream,
- bool aIsTrusted,
- nsIPrincipal* aTriggeringPrincipal)
- : mHandler(aHandler)
- , mURI(aURI)
- , mTargetSpec(aTargetSpec)
- , mFileName(aFileName)
- , mPostDataStream(aPostDataStream)
- , mHeadersDataStream(aHeadersDataStream)
- , mContent(aContent)
- , mPopupState(mHandler->mScriptGlobal->GetPopupControlState())
- , mIsTrusted(aIsTrusted)
- , mTriggeringPrincipal(aTriggeringPrincipal)
- {
- }
- NS_IMETHODIMP
- nsDocShell::OnLinkClick(nsIContent* aContent,
- nsIURI* aURI,
- const char16_t* aTargetSpec,
- const nsAString& aFileName,
- nsIInputStream* aPostDataStream,
- nsIInputStream* aHeadersDataStream,
- bool aIsTrusted,
- nsIPrincipal* aTriggeringPrincipal)
- {
- NS_ASSERTION(NS_IsMainThread(), "wrong thread");
- if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI)) {
- return NS_OK;
- }
- // On history navigation through Back/Forward buttons, don't execute
- // automatic JavaScript redirection such as |anchorElement.click()| or
- // |formElement.submit()|.
- //
- // XXX |formElement.submit()| bypasses this checkpoint because it calls
- // nsDocShell::OnLinkClickSync(...) instead.
- if (ShouldBlockLoadingForBackButton()) {
- return NS_OK;
- }
- if (aContent->IsEditable()) {
- return NS_OK;
- }
- nsresult rv = NS_ERROR_FAILURE;
- nsAutoString target;
- nsCOMPtr<nsIWebBrowserChrome3> browserChrome3 = do_GetInterface(mTreeOwner);
- if (browserChrome3) {
- nsCOMPtr<nsIDOMNode> linkNode = do_QueryInterface(aContent);
- nsAutoString oldTarget(aTargetSpec);
- rv = browserChrome3->OnBeforeLinkTraversal(oldTarget, aURI,
- linkNode, mIsAppTab, target);
- }
- if (NS_FAILED(rv)) {
- target = aTargetSpec;
- }
- nsCOMPtr<nsIRunnable> ev =
- new OnLinkClickEvent(this, aContent, aURI, target.get(), aFileName,
- aPostDataStream, aHeadersDataStream,
- aIsTrusted, aTriggeringPrincipal);
- return NS_DispatchToCurrentThread(ev);
- }
- NS_IMETHODIMP
- nsDocShell::OnLinkClickSync(nsIContent* aContent,
- nsIURI* aURI,
- const char16_t* aTargetSpec,
- const nsAString& aFileName,
- nsIInputStream* aPostDataStream,
- nsIInputStream* aHeadersDataStream,
- nsIDocShell** aDocShell,
- nsIRequest** aRequest,
- nsIPrincipal* aTriggeringPrincipal)
- {
- // Initialize the DocShell / Request
- if (aDocShell) {
- *aDocShell = nullptr;
- }
- if (aRequest) {
- *aRequest = nullptr;
- }
- if (!IsNavigationAllowed() || !IsOKToLoadURI(aURI)) {
- return NS_OK;
- }
- // XXX When the linking node was HTMLFormElement, it is synchronous event.
- // That is, the caller of this method is not |OnLinkClickEvent::Run()|
- // but |HTMLFormElement::SubmitSubmission(...)|.
- if (aContent->IsHTMLElement(nsGkAtoms::form) &&
- ShouldBlockLoadingForBackButton()) {
- return NS_OK;
- }
- if (aContent->IsEditable()) {
- return NS_OK;
- }
- {
- // defer to an external protocol handler if necessary...
- nsCOMPtr<nsIExternalProtocolService> extProtService =
- do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
- if (extProtService) {
- nsAutoCString scheme;
- aURI->GetScheme(scheme);
- if (!scheme.IsEmpty()) {
- // if the URL scheme does not correspond to an exposed protocol, then we
- // need to hand this link click over to the external protocol handler.
- bool isExposed;
- nsresult rv =
- extProtService->IsExposedProtocol(scheme.get(), &isExposed);
- if (NS_SUCCEEDED(rv) && !isExposed) {
- return extProtService->LoadURI(aURI, this);
- }
- }
- }
- }
- uint32_t flags = INTERNAL_LOAD_FLAGS_NONE;
- if (IsElementAnchor(aContent)) {
- MOZ_ASSERT(aContent->IsHTMLElement());
- nsAutoString referrer;
- aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, referrer);
- nsWhitespaceTokenizerTemplate<nsContentUtils::IsHTMLWhitespace> tok(referrer);
- while (tok.hasMoreTokens()) {
- const nsAString& token = tok.nextToken();
- if (token.LowerCaseEqualsLiteral("noreferrer")) {
- flags |= INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER |
- INTERNAL_LOAD_FLAGS_NO_OPENER;
- // We now have all the flags we could possibly have, so just stop.
- break;
- }
- if (token.LowerCaseEqualsLiteral("noopener")) {
- flags |= INTERNAL_LOAD_FLAGS_NO_OPENER;
- }
- }
- }
- // Get the owner document of the link that was clicked, this will be
- // the document that the link is in, or the last document that the
- // link was in. From that document, we'll get the URI to use as the
- // referer, since the current URI in this docshell may be a
- // new document that we're in the process of loading.
- nsCOMPtr<nsIDocument> refererDoc = aContent->OwnerDoc();
- NS_ENSURE_TRUE(refererDoc, NS_ERROR_UNEXPECTED);
- // Now check that the refererDoc's inner window is the current inner
- // window for mScriptGlobal. If it's not, then we don't want to
- // follow this link.
- nsPIDOMWindowInner* refererInner = refererDoc->GetInnerWindow();
- NS_ENSURE_TRUE(refererInner, NS_ERROR_UNEXPECTED);
- if (!mScriptGlobal ||
- mScriptGlobal->AsOuter()->GetCurrentInnerWindow() != refererInner) {
- // We're no longer the current inner window
- return NS_OK;
- }
- nsCOMPtr<nsIURI> referer = refererDoc->GetDocumentURI();
- uint32_t refererPolicy = refererDoc->GetReferrerPolicy();
- // get referrer attribute from clicked link and parse it
- // if per element referrer is enabled, the element referrer overrules
- // the document wide referrer
- if (IsElementAnchor(aContent)) {
- net::ReferrerPolicy refPolEnum = aContent->AsElement()->GetReferrerPolicyAsEnum();
- if (refPolEnum != net::RP_Unset) {
- refererPolicy = refPolEnum;
- }
- }
- // referer could be null here in some odd cases, but that's ok,
- // we'll just load the link w/o sending a referer in those cases.
- nsAutoString target(aTargetSpec);
- // If this is an anchor element, grab its type property to use as a hint
- nsAutoString typeHint;
- nsCOMPtr<nsIDOMHTMLAnchorElement> anchor(do_QueryInterface(aContent));
- if (anchor) {
- anchor->GetType(typeHint);
- NS_ConvertUTF16toUTF8 utf8Hint(typeHint);
- nsAutoCString type, dummy;
- NS_ParseRequestContentType(utf8Hint, type, dummy);
- CopyUTF8toUTF16(type, typeHint);
- }
- // Clone the URI now, in case a content policy or something messes
- // with it under InternalLoad; we do _not_ want to change the URI
- // our caller passed in.
- nsCOMPtr<nsIURI> clonedURI;
- aURI->Clone(getter_AddRefs(clonedURI));
- if (!clonedURI) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
- // if the triggeringPrincipal is not passed explicitly, then we
- // fall back to using doc->NodePrincipal() as the triggeringPrincipal.
- nsCOMPtr<nsIPrincipal> triggeringPrincipal =
- aTriggeringPrincipal ? aTriggeringPrincipal
- : aContent->NodePrincipal();
- nsresult rv = InternalLoad(clonedURI, // New URI
- nullptr, // Original URI
- false, // LoadReplace
- false, // From frame attributes
- referer, // Referer URI
- refererPolicy, // Referer policy
- triggeringPrincipal,
- aContent->NodePrincipal(),
- flags,
- target, // Window target
- NS_LossyConvertUTF16toASCII(typeHint).get(),
- aFileName, // Download as file
- aPostDataStream, // Post data stream
- aHeadersDataStream, // Headers stream
- LOAD_LINK, // Load type
- nullptr, // No SHEntry
- true, // first party site
- NullString(), // No srcdoc
- this, // We are the source
- nullptr, // baseURI not needed
- aDocShell, // DocShell out-param
- aRequest); // Request out-param
- if (NS_SUCCEEDED(rv)) {
- DispatchPings(this, aContent, aURI, referer, refererPolicy);
- }
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::OnOverLink(nsIContent* aContent,
- nsIURI* aURI,
- const char16_t* aTargetSpec)
- {
- if (aContent->IsEditable()) {
- return NS_OK;
- }
- nsCOMPtr<nsIWebBrowserChrome2> browserChrome2 = do_GetInterface(mTreeOwner);
- nsresult rv = NS_ERROR_FAILURE;
- nsCOMPtr<nsIWebBrowserChrome> browserChrome;
- if (!browserChrome2) {
- browserChrome = do_GetInterface(mTreeOwner);
- if (!browserChrome) {
- return rv;
- }
- }
- nsCOMPtr<nsITextToSubURI> textToSubURI =
- do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv);
- if (NS_FAILED(rv)) {
- return rv;
- }
- // use url origin charset to unescape the URL
- nsAutoCString charset;
- rv = aURI->GetOriginCharset(charset);
- NS_ENSURE_SUCCESS(rv, rv);
- nsAutoCString spec;
- rv = aURI->GetSpec(spec);
- NS_ENSURE_SUCCESS(rv, rv);
- nsAutoString uStr;
- rv = textToSubURI->UnEscapeURIForUI(charset, spec, uStr);
- NS_ENSURE_SUCCESS(rv, rv);
- mozilla::net::PredictorPredict(aURI, mCurrentURI,
- nsINetworkPredictor::PREDICT_LINK,
- this, nullptr);
- if (browserChrome2) {
- nsCOMPtr<nsIDOMElement> element = do_QueryInterface(aContent);
- rv = browserChrome2->SetStatusWithContext(nsIWebBrowserChrome::STATUS_LINK,
- uStr, element);
- } else {
- rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK, uStr.get());
- }
- return rv;
- }
- NS_IMETHODIMP
- nsDocShell::OnLeaveLink()
- {
- nsCOMPtr<nsIWebBrowserChrome> browserChrome(do_GetInterface(mTreeOwner));
- nsresult rv = NS_ERROR_FAILURE;
- if (browserChrome) {
- rv = browserChrome->SetStatus(nsIWebBrowserChrome::STATUS_LINK,
- EmptyString().get());
- }
- return rv;
- }
- bool
- nsDocShell::ShouldBlockLoadingForBackButton()
- {
- if (!(mLoadType & LOAD_CMD_HISTORY) ||
- EventStateManager::IsHandlingUserInput() ||
- !Preferences::GetBool("accessibility.blockjsredirection")) {
- return false;
- }
- bool canGoForward = false;
- GetCanGoForward(&canGoForward);
- return canGoForward;
- }
- bool
- nsDocShell::PluginsAllowedInCurrentDoc()
- {
- bool pluginsAllowed = false;
- if (!mContentViewer) {
- return false;
- }
- nsIDocument* doc = mContentViewer->GetDocument();
- if (!doc) {
- return false;
- }
- doc->GetAllowPlugins(&pluginsAllowed);
- return pluginsAllowed;
- }
- //----------------------------------------------------------------------
- // Web Shell Services API
- // This functions is only called when a new charset is detected in loading a
- // document. Its name should be changed to "CharsetReloadDocument"
- NS_IMETHODIMP
- nsDocShell::ReloadDocument(const char* aCharset, int32_t aSource)
- {
- // XXX hack. keep the aCharset and aSource wait to pick it up
- nsCOMPtr<nsIContentViewer> cv;
- NS_ENSURE_SUCCESS(GetContentViewer(getter_AddRefs(cv)), NS_ERROR_FAILURE);
- if (cv) {
- int32_t hint;
- cv->GetHintCharacterSetSource(&hint);
- if (aSource > hint) {
- nsCString charset(aCharset);
- cv->SetHintCharacterSet(charset);
- cv->SetHintCharacterSetSource(aSource);
- if (eCharsetReloadRequested != mCharsetReloadState) {
- mCharsetReloadState = eCharsetReloadRequested;
- return Reload(LOAD_FLAGS_CHARSET_CHANGE);
- }
- }
- }
- // return failure if this request is not accepted due to mCharsetReloadState
- return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
- }
- NS_IMETHODIMP
- nsDocShell::StopDocumentLoad(void)
- {
- if (eCharsetReloadRequested != mCharsetReloadState) {
- Stop(nsIWebNavigation::STOP_ALL);
- return NS_OK;
- }
- // return failer if this request is not accepted due to mCharsetReloadState
- return NS_ERROR_DOCSHELL_REQUEST_REJECTED;
- }
- NS_IMETHODIMP
- nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview)
- {
- *aPrintPreview = nullptr;
- #if NS_PRINT_PREVIEW
- nsCOMPtr<nsIDocumentViewerPrint> print = do_QueryInterface(mContentViewer);
- if (!print || !print->IsInitializedForPrintPreview()) {
- Stop(nsIWebNavigation::STOP_ALL);
- nsCOMPtr<nsIPrincipal> principal = nsNullPrincipal::CreateWithInheritedAttributes(this);
- nsresult rv = CreateAboutBlankContentViewer(principal, nullptr);
- NS_ENSURE_SUCCESS(rv, rv);
- print = do_QueryInterface(mContentViewer);
- NS_ENSURE_STATE(print);
- print->InitializeForPrintPreview();
- }
- nsCOMPtr<nsIWebBrowserPrint> result = do_QueryInterface(print);
- result.forget(aPrintPreview);
- return NS_OK;
- #else
- return NS_ERROR_NOT_IMPLEMENTED;
- #endif
- }
- #ifdef DEBUG
- unsigned long nsDocShell::gNumberOfDocShells = 0;
- #endif
- NS_IMETHODIMP
- nsDocShell::GetCanExecuteScripts(bool* aResult)
- {
- *aResult = mCanExecuteScripts;
- return NS_OK;
- }
- /* [infallible] */ NS_IMETHODIMP
- nsDocShell::SetFrameType(uint32_t aFrameType)
- {
- mFrameType = aFrameType;
- return NS_OK;
- }
- /* [infallible] */ NS_IMETHODIMP
- nsDocShell::GetFrameType(uint32_t* aFrameType)
- {
- *aFrameType = mFrameType;
- return NS_OK;
- }
- /* [infallible] */ NS_IMETHODIMP
- nsDocShell::GetIsApp(bool* aIsApp)
- {
- *aIsApp = (mFrameType == FRAME_TYPE_APP);
- return NS_OK;
- }
- /* [infallible] */ NS_IMETHODIMP
- nsDocShell::GetIsMozBrowserOrApp(bool* aIsMozBrowserOrApp)
- {
- *aIsMozBrowserOrApp = (mFrameType != FRAME_TYPE_REGULAR);
- return NS_OK;
- }
- uint32_t
- nsDocShell::GetInheritedFrameType()
- {
- if (mFrameType != FRAME_TYPE_REGULAR) {
- return mFrameType;
- }
- nsCOMPtr<nsIDocShellTreeItem> parentAsItem;
- GetSameTypeParent(getter_AddRefs(parentAsItem));
- nsCOMPtr<nsIDocShell> parent = do_QueryInterface(parentAsItem);
- if (!parent) {
- return FRAME_TYPE_REGULAR;
- }
- return static_cast<nsDocShell*>(parent.get())->GetInheritedFrameType();
- }
- /* [infallible] */ NS_IMETHODIMP
- nsDocShell::GetIsIsolatedMozBrowserElement(bool* aIsIsolatedMozBrowserElement)
- {
- bool result = mFrameType == FRAME_TYPE_BROWSER &&
- mOriginAttributes.mInIsolatedMozBrowser;
- *aIsIsolatedMozBrowserElement = result;
- return NS_OK;
- }
- /* [infallible] */ NS_IMETHODIMP
- nsDocShell::GetIsInIsolatedMozBrowserElement(bool* aIsInIsolatedMozBrowserElement)
- {
- MOZ_ASSERT(!mOriginAttributes.mInIsolatedMozBrowser ||
- (GetInheritedFrameType() == FRAME_TYPE_BROWSER),
- "Isolated mozbrowser should only be true inside browser frames");
- bool result = (GetInheritedFrameType() == FRAME_TYPE_BROWSER) &&
- mOriginAttributes.mInIsolatedMozBrowser;
- *aIsInIsolatedMozBrowserElement = result;
- return NS_OK;
- }
- /* [infallible] */ NS_IMETHODIMP
- nsDocShell::GetIsInMozBrowserOrApp(bool* aIsInMozBrowserOrApp)
- {
- *aIsInMozBrowserOrApp = (GetInheritedFrameType() != FRAME_TYPE_REGULAR);
- return NS_OK;
- }
- /* [infallible] */ NS_IMETHODIMP
- nsDocShell::GetIsTopLevelContentDocShell(bool* aIsTopLevelContentDocShell)
- {
- *aIsTopLevelContentDocShell = false;
- if (mItemType == typeContent) {
- nsCOMPtr<nsIDocShellTreeItem> root;
- GetSameTypeRootTreeItem(getter_AddRefs(root));
- *aIsTopLevelContentDocShell = root.get() == static_cast<nsIDocShellTreeItem*>(this);
- }
- return NS_OK;
- }
- /* [infallible] */ NS_IMETHODIMP
- nsDocShell::GetAppId(uint32_t* aAppId)
- {
- if (mOriginAttributes.mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
- *aAppId = mOriginAttributes.mAppId;
- return NS_OK;
- }
- nsCOMPtr<nsIDocShell> parent;
- GetSameTypeParentIgnoreBrowserAndAppBoundaries(getter_AddRefs(parent));
- if (!parent) {
- *aAppId = nsIScriptSecurityManager::NO_APP_ID;
- return NS_OK;
- }
- return parent->GetAppId(aAppId);
- }
- // Implements nsILoadContext.originAttributes
- NS_IMETHODIMP
- nsDocShell::GetOriginAttributes(JS::MutableHandle<JS::Value> aVal)
- {
- JSContext* cx = nsContentUtils::GetCurrentJSContext();
- MOZ_ASSERT(cx);
- return GetOriginAttributes(cx, aVal);
- }
- // Implements nsIDocShell.GetOriginAttributes()
- NS_IMETHODIMP
- nsDocShell::GetOriginAttributes(JSContext* aCx,
- JS::MutableHandle<JS::Value> aVal)
- {
- bool ok = ToJSValue(aCx, mOriginAttributes, aVal);
- NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
- return NS_OK;
- }
- bool
- nsDocShell::CanSetOriginAttributes()
- {
- MOZ_ASSERT(mChildList.IsEmpty());
- if (!mChildList.IsEmpty()) {
- return false;
- }
- // TODO: Bug 1273058 - mContentViewer should be null when setting origin
- // attributes.
- if (mContentViewer) {
- nsIDocument* doc = mContentViewer->GetDocument();
- if (doc) {
- nsIURI* uri = doc->GetDocumentURI();
- if (!uri) {
- return false;
- }
- nsCString uriSpec = uri->GetSpecOrDefault();
- MOZ_ASSERT(uriSpec.EqualsLiteral("about:blank"));
- if (!uriSpec.EqualsLiteral("about:blank")) {
- return false;
- }
- }
- }
- return true;
- }
- nsresult
- nsDocShell::SetOriginAttributes(const DocShellOriginAttributes& aAttrs)
- {
- if (!CanSetOriginAttributes()) {
- return NS_ERROR_FAILURE;
- }
- AssertOriginAttributesMatchPrivateBrowsing();
- mOriginAttributes = aAttrs;
- bool isPrivate = mOriginAttributes.mPrivateBrowsingId > 0;
- // Chrome docshell can not contain OriginAttributes.mPrivateBrowsingId
- if (mItemType == typeChrome && isPrivate) {
- mOriginAttributes.mPrivateBrowsingId = 0;
- }
- SetPrivateBrowsing(isPrivate);
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::SetOriginAttributesBeforeLoading(JS::Handle<JS::Value> aOriginAttributes)
- {
- if (!aOriginAttributes.isObject()) {
- return NS_ERROR_INVALID_ARG;
- }
- AutoJSAPI jsapi;
- if (!jsapi.Init(&aOriginAttributes.toObject())) {
- return NS_ERROR_UNEXPECTED;
- }
- JSContext* cx = jsapi.cx();
- if (NS_WARN_IF(!cx)) {
- return NS_ERROR_FAILURE;
- }
- DocShellOriginAttributes attrs;
- if (!aOriginAttributes.isObject() || !attrs.Init(cx, aOriginAttributes)) {
- return NS_ERROR_INVALID_ARG;
- }
- return SetOriginAttributes(attrs);
- }
- NS_IMETHODIMP
- nsDocShell::SetOriginAttributes(JS::Handle<JS::Value> aOriginAttributes,
- JSContext* aCx)
- {
- DocShellOriginAttributes attrs;
- if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
- return NS_ERROR_INVALID_ARG;
- }
- return SetOriginAttributes(attrs);
- }
- NS_IMETHODIMP
- nsDocShell::GetAppManifestURL(nsAString& aAppManifestURL)
- {
- uint32_t appId = nsIDocShell::GetAppId();
- if (appId != nsIScriptSecurityManager::NO_APP_ID &&
- appId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
- nsCOMPtr<nsIAppsService> appsService =
- do_GetService(APPS_SERVICE_CONTRACTID);
- NS_ASSERTION(appsService, "No AppsService available");
- appsService->GetManifestURLByLocalId(appId, aAppManifestURL);
- } else {
- aAppManifestURL.SetLength(0);
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetAsyncPanZoomEnabled(bool* aOut)
- {
- if (nsIPresShell* presShell = GetPresShell()) {
- *aOut = presShell->AsyncPanZoomEnabled();
- return NS_OK;
- }
- // If we don't have a presShell, fall back to the default platform value of
- // whether or not APZ is enabled.
- *aOut = gfxPlatform::AsyncPanZoomEnabled();
- return NS_OK;
- }
- bool
- nsDocShell::HasUnloadedParent()
- {
- RefPtr<nsDocShell> parent = GetParentDocshell();
- while (parent) {
- bool inUnload = false;
- parent->GetIsInUnload(&inUnload);
- if (inUnload) {
- return true;
- }
- parent = parent->GetParentDocshell();
- }
- return false;
- }
- bool
- nsDocShell::IsInvisible()
- {
- return mInvisible;
- }
- void
- nsDocShell::SetInvisible(bool aInvisible)
- {
- mInvisible = aInvisible;
- }
- void
- nsDocShell::SetOpener(nsITabParent* aOpener)
- {
- mOpener = do_GetWeakReference(aOpener);
- }
- nsITabParent*
- nsDocShell::GetOpener()
- {
- nsCOMPtr<nsITabParent> opener(do_QueryReferent(mOpener));
- return opener;
- }
- // The caller owns |aAsyncCause| here.
- void
- nsDocShell::NotifyJSRunToCompletionStart(const char* aReason,
- const char16_t* aFunctionName,
- const char16_t* aFilename,
- const uint32_t aLineNumber,
- JS::Handle<JS::Value> aAsyncStack,
- const char* aAsyncCause)
- {
- // If first start, mark interval start.
- if (mJSRunToCompletionDepth == 0) {
- RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
- if (timelines && timelines->HasConsumer(this)) {
- timelines->AddMarkerForDocShell(this, Move(
- mozilla::MakeUnique<JavascriptTimelineMarker>(
- aReason, aFunctionName, aFilename, aLineNumber, MarkerTracingType::START,
- aAsyncStack, aAsyncCause)));
- }
- }
- mJSRunToCompletionDepth++;
- }
- void
- nsDocShell::NotifyJSRunToCompletionStop()
- {
- mJSRunToCompletionDepth--;
- // If last stop, mark interval end.
- if (mJSRunToCompletionDepth == 0) {
- RefPtr<TimelineConsumers> timelines = TimelineConsumers::Get();
- if (timelines && timelines->HasConsumer(this)) {
- timelines->AddMarkerForDocShell(this, "Javascript", MarkerTracingType::END);
- }
- }
- }
- void
- nsDocShell::MaybeNotifyKeywordSearchLoading(const nsString& aProvider,
- const nsString& aKeyword)
- {
- if (aProvider.IsEmpty()) {
- return;
- }
- if (XRE_IsContentProcess()) {
- dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
- if (contentChild) {
- contentChild->SendNotifyKeywordSearchLoading(aProvider, aKeyword);
- }
- return;
- }
- #ifdef MOZ_TOOLKIT_SEARCH
- nsCOMPtr<nsIBrowserSearchService> searchSvc =
- do_GetService("@mozilla.org/browser/search-service;1");
- if (searchSvc) {
- nsCOMPtr<nsISearchEngine> searchEngine;
- searchSvc->GetEngineByName(aProvider, getter_AddRefs(searchEngine));
- if (searchEngine) {
- nsCOMPtr<nsIObserverService> obsSvc = services::GetObserverService();
- if (obsSvc) {
- // Note that "keyword-search" refers to a search via the url
- // bar, not a bookmarks keyword search.
- obsSvc->NotifyObservers(searchEngine, "keyword-search", aKeyword.get());
- }
- }
- }
- #endif
- }
- NS_IMETHODIMP
- nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNonSubresourceRequest,
- bool* aShouldIntercept)
- {
- *aShouldIntercept = false;
- // No in private browsing
- if (UsePrivateBrowsing()) {
- return NS_OK;
- }
- if (mSandboxFlags) {
- // If we're sandboxed, don't intercept.
- return NS_OK;
- }
- RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
- if (!swm) {
- return NS_OK;
- }
- nsresult result;
- nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil =
- do_GetService(THIRDPARTYUTIL_CONTRACTID, &result);
- NS_ENSURE_SUCCESS(result, result);
- if (mCurrentURI &&
- nsContentUtils::CookiesBehavior() == nsICookieService::BEHAVIOR_REJECT_FOREIGN) {
- nsAutoCString uriSpec;
- if (!(mCurrentURI->GetSpecOrDefault().EqualsLiteral("about:blank"))) {
- // Reject the interception of third-party iframes if the cookie behaviour
- // is set to reject all third-party cookies (1). In case that this pref
- // is not set or can't be read, we default to allow all cookies (0) as
- // this is the default value in all.js.
- bool isThirdPartyURI = true;
- result = thirdPartyUtil->IsThirdPartyURI(mCurrentURI, aURI,
- &isThirdPartyURI);
- if (NS_FAILED(result)) {
- return result;
- }
- if (isThirdPartyURI) {
- return NS_OK;
- }
- }
- }
- if (aIsNonSubresourceRequest) {
- PrincipalOriginAttributes attrs;
- attrs.InheritFromDocShellToDoc(mOriginAttributes, aURI);
- nsCOMPtr<nsIPrincipal> principal =
- BasePrincipal::CreateCodebasePrincipal(aURI, attrs);
- *aShouldIntercept = swm->IsAvailable(principal, aURI);
- return NS_OK;
- }
- nsCOMPtr<nsIDocument> doc = GetDocument();
- if (!doc) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- ErrorResult rv;
- *aShouldIntercept = swm->IsControlled(doc, rv);
- if (NS_WARN_IF(rv.Failed())) {
- return rv.StealNSResult();
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel)
- {
- RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
- if (!swm) {
- aChannel->Cancel(NS_ERROR_INTERCEPTION_FAILED);
- return NS_OK;
- }
- nsCOMPtr<nsIChannel> channel;
- nsresult rv = aChannel->GetChannel(getter_AddRefs(channel));
- NS_ENSURE_SUCCESS(rv, rv);
- nsCOMPtr<nsIDocument> doc;
- bool isSubresourceLoad = !nsContentUtils::IsNonSubresourceRequest(channel);
- if (isSubresourceLoad) {
- doc = GetDocument();
- if (!doc) {
- return NS_ERROR_NOT_AVAILABLE;
- }
- } else {
- // For top-level navigations, save a document ID which will be passed to
- // the FetchEvent as the clientId later on.
- rv = nsIDocument::GenerateDocumentId(mInterceptedDocumentId);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- bool isReload = mLoadType & LOAD_CMD_RELOAD;
- nsCOMPtr<nsIURI> uri;
- rv = channel->GetURI(getter_AddRefs(uri));
- NS_ENSURE_SUCCESS(rv, rv);
- PrincipalOriginAttributes attrs;
- attrs.InheritFromDocShellToDoc(mOriginAttributes, uri);
- ErrorResult error;
- swm->DispatchFetchEvent(attrs, doc, mInterceptedDocumentId, aChannel,
- isReload, isSubresourceLoad, error);
- if (NS_WARN_IF(error.Failed())) {
- return error.StealNSResult();
- }
- return NS_OK;
- }
- bool
- nsDocShell::InFrameSwap()
- {
- RefPtr<nsDocShell> shell = this;
- do {
- if (shell->mInFrameSwap) {
- return true;
- }
- shell = shell->GetParentDocshell();
- } while (shell);
- return false;
- }
- NS_IMETHODIMP
- nsDocShell::IssueWarning(uint32_t aWarning, bool aAsError)
- {
- if (mContentViewer) {
- nsCOMPtr<nsIDocument> doc = mContentViewer->GetDocument();
- if (doc) {
- doc->WarnOnceAbout(nsIDocument::DeprecatedOperations(aWarning), aAsError);
- }
- }
- return NS_OK;
- }
- NS_IMETHODIMP
- nsDocShell::GetEditingSession(nsIEditingSession** aEditSession)
- {
- if (!NS_SUCCEEDED(EnsureEditorData())) {
- return NS_ERROR_FAILURE;
- }
- mEditorData->GetEditingSession(aEditSession);
- return *aEditSession ? NS_OK : NS_ERROR_FAILURE;
- }
- NS_IMETHODIMP
- nsDocShell::GetScriptableTabChild(nsITabChild** aTabChild)
- {
- *aTabChild = GetTabChild().take();
- return *aTabChild ? NS_OK : NS_ERROR_FAILURE;
- }
- already_AddRefed<nsITabChild>
- nsDocShell::GetTabChild()
- {
- nsCOMPtr<nsIDocShellTreeOwner> owner(mTreeOwner);
- nsCOMPtr<nsITabChild> tc = do_GetInterface(owner);
- return tc.forget();
- }
- nsICommandManager*
- nsDocShell::GetCommandManager()
- {
- NS_ENSURE_SUCCESS(EnsureCommandHandler(), nullptr);
- return mCommandManager;
- }
- NS_IMETHODIMP
- nsDocShell::GetProcessLockReason(uint32_t* aReason)
- {
- MOZ_ASSERT(aReason);
- nsPIDOMWindowOuter* outer = GetWindow();
- MOZ_ASSERT(outer);
- // Check if we are a toplevel window
- if (outer->GetScriptableParentOrNull()) {
- *aReason = PROCESS_LOCK_IFRAME;
- return NS_OK;
- }
- // If we have any other toplevel windows in our tab group, then we cannot
- // perform the navigation.
- nsTArray<nsPIDOMWindowOuter*> toplevelWindows =
- outer->TabGroup()->GetTopLevelWindows();
- if (toplevelWindows.Length() > 1) {
- *aReason = PROCESS_LOCK_RELATED_CONTEXTS;
- return NS_OK;
- }
- MOZ_ASSERT(toplevelWindows.Length() == 1);
- MOZ_ASSERT(toplevelWindows[0] == outer);
- // If we aren't in a content process, we cannot perform a cross-process load.
- if (!XRE_IsContentProcess()) {
- *aReason = PROCESS_LOCK_NON_CONTENT;
- return NS_OK;
- }
- *aReason = PROCESS_LOCK_NONE;
- return NS_OK;
- }
|