XMLHttpRequestMainThread.cpp 124 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #include "XMLHttpRequestMainThread.h"
  6. #include <algorithm>
  7. #ifndef XP_WIN
  8. #include <unistd.h>
  9. #endif
  10. #include "mozilla/ArrayUtils.h"
  11. #include "mozilla/CheckedInt.h"
  12. #include "mozilla/dom/BlobSet.h"
  13. #include "mozilla/dom/DOMString.h"
  14. #include "mozilla/dom/File.h"
  15. #include "mozilla/dom/FetchUtil.h"
  16. #include "mozilla/dom/FormData.h"
  17. #include "mozilla/dom/MutableBlobStorage.h"
  18. #include "mozilla/dom/XMLDocument.h"
  19. #include "mozilla/dom/URLSearchParams.h"
  20. #include "mozilla/EventDispatcher.h"
  21. #include "mozilla/EventListenerManager.h"
  22. #include "mozilla/LoadInfo.h"
  23. #include "mozilla/LoadContext.h"
  24. #include "mozilla/MemoryReporting.h"
  25. #include "nsIDOMDocument.h"
  26. #include "mozilla/dom/ProgressEvent.h"
  27. #include "nsIJARChannel.h"
  28. #include "nsIJARURI.h"
  29. #include "nsLayoutCID.h"
  30. #include "nsReadableUtils.h"
  31. #include "nsIURI.h"
  32. #include "nsILoadGroup.h"
  33. #include "nsNetUtil.h"
  34. #include "nsStringStream.h"
  35. #include "nsIAuthPrompt.h"
  36. #include "nsIAuthPrompt2.h"
  37. #include "nsIOutputStream.h"
  38. #include "nsISupportsPrimitives.h"
  39. #include "nsIInterfaceRequestorUtils.h"
  40. #include "nsStreamUtils.h"
  41. #include "nsThreadUtils.h"
  42. #include "nsIUploadChannel.h"
  43. #include "nsIUploadChannel2.h"
  44. #include "nsIDOMSerializer.h"
  45. #include "nsXPCOM.h"
  46. #include "nsIDOMEventListener.h"
  47. #include "nsIScriptSecurityManager.h"
  48. #include "nsIVariant.h"
  49. #include "nsVariant.h"
  50. #include "nsIScriptError.h"
  51. #include "nsIStreamConverterService.h"
  52. #include "nsICachingChannel.h"
  53. #include "nsContentUtils.h"
  54. #include "nsCycleCollectionParticipant.h"
  55. #include "nsError.h"
  56. #include "nsIHTMLDocument.h"
  57. #include "nsIStorageStream.h"
  58. #include "nsIPromptFactory.h"
  59. #include "nsIWindowWatcher.h"
  60. #include "nsIConsoleService.h"
  61. #include "nsIContentSecurityPolicy.h"
  62. #include "nsAsyncRedirectVerifyHelper.h"
  63. #include "nsStringBuffer.h"
  64. #include "nsIFileChannel.h"
  65. #include "mozilla/Telemetry.h"
  66. #include "jsfriendapi.h"
  67. #include "GeckoProfiler.h"
  68. #include "mozilla/dom/EncodingUtils.h"
  69. #include "nsIUnicodeDecoder.h"
  70. #include "mozilla/dom/XMLHttpRequestBinding.h"
  71. #include "mozilla/Attributes.h"
  72. #include "MultipartBlobImpl.h"
  73. #include "nsIPermissionManager.h"
  74. #include "nsMimeTypes.h"
  75. #include "nsIHttpChannelInternal.h"
  76. #include "nsIClassOfService.h"
  77. #include "nsCharSeparatedTokenizer.h"
  78. #include "nsStreamListenerWrapper.h"
  79. #include "xpcjsid.h"
  80. #include "nsITimedChannel.h"
  81. #include "nsWrapperCacheInlines.h"
  82. #include "nsZipArchive.h"
  83. #include "mozilla/Preferences.h"
  84. #include "private/pprio.h"
  85. #include "XMLHttpRequestUpload.h"
  86. #include "nsHostObjectProtocolHandler.h"
  87. using namespace mozilla::net;
  88. namespace mozilla {
  89. namespace dom {
  90. // Maximum size that we'll grow an ArrayBuffer instead of doubling,
  91. // once doubling reaches this threshold
  92. const uint32_t XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH = 32*1024*1024;
  93. // start at 32k to avoid lots of doubling right at the start
  94. const uint32_t XML_HTTP_REQUEST_ARRAYBUFFER_MIN_SIZE = 32*1024;
  95. // the maximum Content-Length that we'll preallocate. 1GB. Must fit
  96. // in an int32_t!
  97. const int32_t XML_HTTP_REQUEST_MAX_CONTENT_LENGTH_PREALLOCATE = 1*1024*1024*1024LL;
  98. namespace {
  99. const nsLiteralString ProgressEventTypeStrings[] = {
  100. NS_LITERAL_STRING("loadstart"),
  101. NS_LITERAL_STRING("progress"),
  102. NS_LITERAL_STRING("error"),
  103. NS_LITERAL_STRING("abort"),
  104. NS_LITERAL_STRING("timeout"),
  105. NS_LITERAL_STRING("load"),
  106. NS_LITERAL_STRING("loadend")
  107. };
  108. static_assert(MOZ_ARRAY_LENGTH(ProgressEventTypeStrings) ==
  109. size_t(XMLHttpRequestMainThread::ProgressEventType::ENUM_MAX),
  110. "Mismatched lengths for ProgressEventTypeStrings and ProgressEventType enums");
  111. const nsString kLiteralString_readystatechange = NS_LITERAL_STRING("readystatechange");
  112. const nsString kLiteralString_xmlhttprequest = NS_LITERAL_STRING("xmlhttprequest");
  113. const nsString kLiteralString_DOMContentLoaded = NS_LITERAL_STRING("DOMContentLoaded");
  114. }
  115. // CIDs
  116. #define NS_BADCERTHANDLER_CONTRACTID \
  117. "@mozilla.org/content/xmlhttprequest-bad-cert-handler;1"
  118. #define NS_PROGRESS_EVENT_INTERVAL 50
  119. #define MAX_SYNC_TIMEOUT_WHEN_UNLOADING 10000 /* 10 secs */
  120. NS_IMPL_ISUPPORTS(nsXHRParseEndListener, nsIDOMEventListener)
  121. class nsResumeTimeoutsEvent : public Runnable
  122. {
  123. public:
  124. explicit nsResumeTimeoutsEvent(nsPIDOMWindowInner* aWindow) : mWindow(aWindow) {}
  125. NS_IMETHOD Run() override
  126. {
  127. mWindow->Resume();
  128. return NS_OK;
  129. }
  130. private:
  131. nsCOMPtr<nsPIDOMWindowInner> mWindow;
  132. };
  133. // This helper function adds the given load flags to the request's existing
  134. // load flags.
  135. static void AddLoadFlags(nsIRequest *request, nsLoadFlags newFlags)
  136. {
  137. nsLoadFlags flags;
  138. request->GetLoadFlags(&flags);
  139. flags |= newFlags;
  140. request->SetLoadFlags(flags);
  141. }
  142. /////////////////////////////////////////////
  143. //
  144. //
  145. /////////////////////////////////////////////
  146. bool
  147. XMLHttpRequestMainThread::sDontWarnAboutSyncXHR = false;
  148. XMLHttpRequestMainThread::XMLHttpRequestMainThread()
  149. : mResponseBodyDecodedPos(0),
  150. mResponseType(XMLHttpRequestResponseType::_empty),
  151. mRequestObserver(nullptr),
  152. mState(State::unsent),
  153. mFlagSynchronous(false), mFlagAborted(false), mFlagParseBody(false),
  154. mFlagSyncLooping(false), mFlagBackgroundRequest(false),
  155. mFlagHadUploadListenersOnSend(false), mFlagACwithCredentials(false),
  156. mFlagTimedOut(false), mFlagDeleted(false), mFlagSend(false),
  157. mUploadTransferred(0), mUploadTotal(0), mUploadComplete(true),
  158. mProgressSinceLastProgressEvent(false),
  159. mRequestSentTime(0), mTimeoutMilliseconds(0),
  160. mErrorLoad(false), mErrorParsingXML(false),
  161. mWaitingForOnStopRequest(false),
  162. mProgressTimerIsActive(false),
  163. mIsHtml(false),
  164. mWarnAboutSyncHtml(false),
  165. mLoadTotal(-1),
  166. mIsSystem(false),
  167. mIsAnon(false),
  168. mFirstStartRequestSeen(false),
  169. mInLoadProgressEvent(false),
  170. mResultJSON(JS::UndefinedValue()),
  171. mResultArrayBuffer(nullptr),
  172. mIsMappedArrayBuffer(false),
  173. mXPCOMifier(nullptr)
  174. {
  175. mozilla::HoldJSObjects(this);
  176. }
  177. XMLHttpRequestMainThread::~XMLHttpRequestMainThread()
  178. {
  179. mFlagDeleted = true;
  180. if ((mState == State::opened && mFlagSend) ||
  181. mState == State::loading) {
  182. Abort();
  183. }
  184. MOZ_ASSERT(!mFlagSyncLooping, "we rather crash than hang");
  185. mFlagSyncLooping = false;
  186. mResultJSON.setUndefined();
  187. mResultArrayBuffer = nullptr;
  188. mozilla::DropJSObjects(this);
  189. }
  190. /**
  191. * This Init method is called from the factory constructor.
  192. */
  193. nsresult
  194. XMLHttpRequestMainThread::Init()
  195. {
  196. nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
  197. nsCOMPtr<nsIPrincipal> subjectPrincipal;
  198. if (secMan) {
  199. secMan->GetSystemPrincipal(getter_AddRefs(subjectPrincipal));
  200. }
  201. NS_ENSURE_STATE(subjectPrincipal);
  202. // Instead of grabbing some random global from the context stack,
  203. // let's use the default one (junk scope) for now.
  204. // We should move away from this Init...
  205. Construct(subjectPrincipal, xpc::NativeGlobal(xpc::PrivilegedJunkScope()));
  206. return NS_OK;
  207. }
  208. /**
  209. * This Init method should only be called by C++ consumers.
  210. */
  211. NS_IMETHODIMP
  212. XMLHttpRequestMainThread::Init(nsIPrincipal* aPrincipal,
  213. nsIGlobalObject* aGlobalObject,
  214. nsIURI* aBaseURI,
  215. nsILoadGroup* aLoadGroup)
  216. {
  217. NS_ENSURE_ARG_POINTER(aPrincipal);
  218. Construct(aPrincipal, aGlobalObject, aBaseURI, aLoadGroup);
  219. return NS_OK;
  220. }
  221. void
  222. XMLHttpRequestMainThread::InitParameters(bool aAnon, bool aSystem)
  223. {
  224. if (!aAnon && !aSystem) {
  225. return;
  226. }
  227. // Check for permissions.
  228. // Chrome is always allowed access, so do the permission check only
  229. // for non-chrome pages.
  230. if (!IsSystemXHR() && aSystem) {
  231. nsIGlobalObject* global = GetOwnerGlobal();
  232. if (NS_WARN_IF(!global)) {
  233. SetParameters(aAnon, false);
  234. return;
  235. }
  236. nsIPrincipal* principal = global->PrincipalOrNull();
  237. if (NS_WARN_IF(!principal)) {
  238. SetParameters(aAnon, false);
  239. return;
  240. }
  241. nsCOMPtr<nsIPermissionManager> permMgr =
  242. services::GetPermissionManager();
  243. if (NS_WARN_IF(!permMgr)) {
  244. SetParameters(aAnon, false);
  245. return;
  246. }
  247. uint32_t permission;
  248. nsresult rv =
  249. permMgr->TestPermissionFromPrincipal(principal, "systemXHR", &permission);
  250. if (NS_FAILED(rv) || permission != nsIPermissionManager::ALLOW_ACTION) {
  251. SetParameters(aAnon, false);
  252. return;
  253. }
  254. }
  255. SetParameters(aAnon, aSystem);
  256. }
  257. void
  258. XMLHttpRequestMainThread::ResetResponse()
  259. {
  260. mResponseXML = nullptr;
  261. mResponseBody.Truncate();
  262. TruncateResponseText();
  263. mResponseBlob = nullptr;
  264. mDOMBlob = nullptr;
  265. mBlobStorage = nullptr;
  266. mBlobSet = nullptr;
  267. mResultArrayBuffer = nullptr;
  268. mArrayBufferBuilder.reset();
  269. mResultJSON.setUndefined();
  270. mDataAvailable = 0;
  271. mLoadTransferred = 0;
  272. mResponseBodyDecodedPos = 0;
  273. }
  274. void
  275. XMLHttpRequestMainThread::SetRequestObserver(nsIRequestObserver* aObserver)
  276. {
  277. mRequestObserver = aObserver;
  278. }
  279. NS_IMPL_CYCLE_COLLECTION_CLASS(XMLHttpRequestMainThread)
  280. NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(XMLHttpRequestMainThread)
  281. bool isBlack = tmp->IsBlack();
  282. if (isBlack || tmp->mWaitingForOnStopRequest) {
  283. if (tmp->mListenerManager) {
  284. tmp->mListenerManager->MarkForCC();
  285. }
  286. if (!isBlack && tmp->PreservingWrapper()) {
  287. // This marks the wrapper black.
  288. tmp->GetWrapper();
  289. }
  290. return true;
  291. }
  292. NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
  293. NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(XMLHttpRequestMainThread)
  294. return tmp->
  295. IsBlackAndDoesNotNeedTracing(static_cast<DOMEventTargetHelper*>(tmp));
  296. NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
  297. NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(XMLHttpRequestMainThread)
  298. return tmp->IsBlack();
  299. NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
  300. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(XMLHttpRequestMainThread,
  301. XMLHttpRequestEventTarget)
  302. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
  303. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannel)
  304. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResponseXML)
  305. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXMLParserStreamListener)
  306. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mResponseBlob)
  307. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMBlob)
  308. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotificationCallbacks)
  309. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannelEventSink)
  310. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mProgressEventSink)
  311. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUpload)
  312. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  313. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(XMLHttpRequestMainThread,
  314. XMLHttpRequestEventTarget)
  315. tmp->mResultArrayBuffer = nullptr;
  316. tmp->mArrayBufferBuilder.reset();
  317. tmp->mResultJSON.setUndefined();
  318. NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
  319. NS_IMPL_CYCLE_COLLECTION_UNLINK(mChannel)
  320. NS_IMPL_CYCLE_COLLECTION_UNLINK(mResponseXML)
  321. NS_IMPL_CYCLE_COLLECTION_UNLINK(mXMLParserStreamListener)
  322. NS_IMPL_CYCLE_COLLECTION_UNLINK(mResponseBlob)
  323. NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMBlob)
  324. NS_IMPL_CYCLE_COLLECTION_UNLINK(mNotificationCallbacks)
  325. NS_IMPL_CYCLE_COLLECTION_UNLINK(mChannelEventSink)
  326. NS_IMPL_CYCLE_COLLECTION_UNLINK(mProgressEventSink)
  327. NS_IMPL_CYCLE_COLLECTION_UNLINK(mUpload)
  328. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  329. NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(XMLHttpRequestMainThread,
  330. XMLHttpRequestEventTarget)
  331. NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultArrayBuffer)
  332. NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mResultJSON)
  333. NS_IMPL_CYCLE_COLLECTION_TRACE_END
  334. // QueryInterface implementation for XMLHttpRequestMainThread
  335. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(XMLHttpRequestMainThread)
  336. NS_INTERFACE_MAP_ENTRY(nsIXMLHttpRequest)
  337. NS_INTERFACE_MAP_ENTRY(nsIJSXMLHttpRequest)
  338. NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
  339. NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
  340. NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
  341. NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
  342. NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
  343. NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
  344. NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
  345. NS_INTERFACE_MAP_ENTRY(nsISizeOfEventTarget)
  346. NS_INTERFACE_MAP_END_INHERITING(XMLHttpRequestEventTarget)
  347. NS_IMPL_ADDREF_INHERITED(XMLHttpRequestMainThread, XMLHttpRequestEventTarget)
  348. NS_IMPL_RELEASE_INHERITED(XMLHttpRequestMainThread, XMLHttpRequestEventTarget)
  349. NS_IMPL_EVENT_HANDLER(XMLHttpRequestMainThread, readystatechange)
  350. void
  351. XMLHttpRequestMainThread::DisconnectFromOwner()
  352. {
  353. XMLHttpRequestEventTarget::DisconnectFromOwner();
  354. Abort();
  355. }
  356. size_t
  357. XMLHttpRequestMainThread::SizeOfEventTargetIncludingThis(
  358. MallocSizeOf aMallocSizeOf) const
  359. {
  360. size_t n = aMallocSizeOf(this);
  361. n += mResponseBody.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
  362. // Why is this safe? Because no-one else will report this string. The
  363. // other possible sharers of this string are as follows.
  364. //
  365. // - The JS engine could hold copies if the JS code holds references, e.g.
  366. // |var text = XHR.responseText|. However, those references will be via JS
  367. // external strings, for which the JS memory reporter does *not* report the
  368. // chars.
  369. //
  370. // - Binary extensions, but they're *extremely* unlikely to do any memory
  371. // reporting.
  372. //
  373. n += mResponseText.SizeOfThis(aMallocSizeOf);
  374. return n;
  375. // Measurement of the following members may be added later if DMD finds it is
  376. // worthwhile:
  377. // - lots
  378. }
  379. NS_IMETHODIMP
  380. XMLHttpRequestMainThread::GetChannel(nsIChannel **aChannel)
  381. {
  382. NS_ENSURE_ARG_POINTER(aChannel);
  383. NS_IF_ADDREF(*aChannel = mChannel);
  384. return NS_OK;
  385. }
  386. static void LogMessage(const char* aWarning, nsPIDOMWindowInner* aWindow,
  387. const char16_t** aParams=nullptr, uint32_t aParamCount=0)
  388. {
  389. nsCOMPtr<nsIDocument> doc;
  390. if (aWindow) {
  391. doc = aWindow->GetExtantDoc();
  392. }
  393. nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
  394. NS_LITERAL_CSTRING("DOM"), doc,
  395. nsContentUtils::eDOM_PROPERTIES,
  396. aWarning, aParams, aParamCount);
  397. }
  398. NS_IMETHODIMP
  399. XMLHttpRequestMainThread::GetResponseXML(nsIDOMDocument **aResponseXML)
  400. {
  401. ErrorResult rv;
  402. nsIDocument* responseXML = GetResponseXML(rv);
  403. if (rv.Failed()) {
  404. return rv.StealNSResult();
  405. }
  406. if (!responseXML) {
  407. *aResponseXML = nullptr;
  408. return NS_OK;
  409. }
  410. return CallQueryInterface(responseXML, aResponseXML);
  411. }
  412. nsIDocument*
  413. XMLHttpRequestMainThread::GetResponseXML(ErrorResult& aRv)
  414. {
  415. if (mResponseType != XMLHttpRequestResponseType::_empty &&
  416. mResponseType != XMLHttpRequestResponseType::Document) {
  417. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_WRONG_RESPONSETYPE_FOR_RESPONSEXML);
  418. return nullptr;
  419. }
  420. if (mWarnAboutSyncHtml) {
  421. mWarnAboutSyncHtml = false;
  422. LogMessage("HTMLSyncXHRWarning", GetOwner());
  423. }
  424. if (mState != State::done) {
  425. return nullptr;
  426. }
  427. return mResponseXML;
  428. }
  429. /*
  430. * This piece copied from XMLDocument, we try to get the charset
  431. * from HTTP headers.
  432. */
  433. nsresult
  434. XMLHttpRequestMainThread::DetectCharset()
  435. {
  436. mResponseCharset.Truncate();
  437. mDecoder = nullptr;
  438. if (mResponseType != XMLHttpRequestResponseType::_empty &&
  439. mResponseType != XMLHttpRequestResponseType::Text &&
  440. mResponseType != XMLHttpRequestResponseType::Json &&
  441. mResponseType != XMLHttpRequestResponseType::Moz_chunked_text) {
  442. return NS_OK;
  443. }
  444. nsAutoCString charsetVal;
  445. bool ok = mChannel &&
  446. NS_SUCCEEDED(mChannel->GetContentCharset(charsetVal)) &&
  447. EncodingUtils::FindEncodingForLabel(charsetVal, mResponseCharset);
  448. if (!ok || mResponseCharset.IsEmpty()) {
  449. // MS documentation states UTF-8 is default for responseText
  450. mResponseCharset.AssignLiteral("UTF-8");
  451. }
  452. if (mResponseType == XMLHttpRequestResponseType::Json &&
  453. !mResponseCharset.EqualsLiteral("UTF-8")) {
  454. // The XHR spec says only UTF-8 is supported for responseType == "json"
  455. LogMessage("JSONCharsetWarning", GetOwner());
  456. mResponseCharset.AssignLiteral("UTF-8");
  457. }
  458. mDecoder = EncodingUtils::DecoderForEncoding(mResponseCharset);
  459. return NS_OK;
  460. }
  461. nsresult
  462. XMLHttpRequestMainThread::AppendToResponseText(const char * aSrcBuffer,
  463. uint32_t aSrcBufferLen)
  464. {
  465. NS_ENSURE_STATE(mDecoder);
  466. int32_t destBufferLen;
  467. nsresult rv = mDecoder->GetMaxLength(aSrcBuffer, aSrcBufferLen,
  468. &destBufferLen);
  469. NS_ENSURE_SUCCESS(rv, rv);
  470. CheckedInt32 size = mResponseText.Length();
  471. size += destBufferLen;
  472. if (!size.isValid()) {
  473. return NS_ERROR_OUT_OF_MEMORY;
  474. }
  475. XMLHttpRequestStringWriterHelper helper(mResponseText);
  476. if (!helper.AddCapacity(destBufferLen)) {
  477. return NS_ERROR_OUT_OF_MEMORY;
  478. }
  479. // This code here is basically a copy of a similar thing in
  480. // nsScanner::Append(const char* aBuffer, uint32_t aLen).
  481. int32_t srclen = (int32_t)aSrcBufferLen;
  482. int32_t destlen = (int32_t)destBufferLen;
  483. rv = mDecoder->Convert(aSrcBuffer,
  484. &srclen,
  485. helper.EndOfExistingData(),
  486. &destlen);
  487. MOZ_ASSERT(NS_SUCCEEDED(rv));
  488. MOZ_ASSERT(destlen <= destBufferLen);
  489. helper.AddLength(destlen);
  490. return NS_OK;
  491. }
  492. NS_IMETHODIMP
  493. XMLHttpRequestMainThread::GetResponseText(nsAString& aResponseText)
  494. {
  495. ErrorResult rv;
  496. DOMString str;
  497. GetResponseText(str, rv);
  498. if (NS_WARN_IF(rv.Failed())) {
  499. return rv.StealNSResult();
  500. }
  501. str.ToString(aResponseText);
  502. return NS_OK;
  503. }
  504. void
  505. XMLHttpRequestMainThread::GetResponseText(DOMString& aResponseText,
  506. ErrorResult& aRv)
  507. {
  508. XMLHttpRequestStringSnapshot snapshot;
  509. GetResponseText(snapshot, aRv);
  510. if (aRv.Failed()) {
  511. return;
  512. }
  513. if (!snapshot.GetAsString(aResponseText)) {
  514. aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
  515. return;
  516. }
  517. }
  518. void
  519. XMLHttpRequestMainThread::GetResponseText(XMLHttpRequestStringSnapshot& aSnapshot,
  520. ErrorResult& aRv)
  521. {
  522. aSnapshot.Reset();
  523. if (mResponseType != XMLHttpRequestResponseType::_empty &&
  524. mResponseType != XMLHttpRequestResponseType::Text &&
  525. mResponseType != XMLHttpRequestResponseType::Moz_chunked_text) {
  526. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_HAS_WRONG_RESPONSETYPE_FOR_RESPONSETEXT);
  527. return;
  528. }
  529. if (mResponseType == XMLHttpRequestResponseType::Moz_chunked_text &&
  530. !mInLoadProgressEvent) {
  531. aSnapshot.SetVoid();
  532. return;
  533. }
  534. if (mState != State::loading && mState != State::done) {
  535. return;
  536. }
  537. // We only decode text lazily if we're also parsing to a doc.
  538. // Also, if we've decoded all current data already, then no need to decode
  539. // more.
  540. if ((!mResponseXML && !mErrorParsingXML) ||
  541. mResponseBodyDecodedPos == mResponseBody.Length()) {
  542. mResponseText.CreateSnapshot(aSnapshot);
  543. return;
  544. }
  545. MatchCharsetAndDecoderToResponseDocument();
  546. NS_ASSERTION(mResponseBodyDecodedPos < mResponseBody.Length(),
  547. "Unexpected mResponseBodyDecodedPos");
  548. aRv = AppendToResponseText(mResponseBody.get() + mResponseBodyDecodedPos,
  549. mResponseBody.Length() - mResponseBodyDecodedPos);
  550. if (aRv.Failed()) {
  551. return;
  552. }
  553. mResponseBodyDecodedPos = mResponseBody.Length();
  554. if (mState == State::done) {
  555. // Free memory buffer which we no longer need
  556. mResponseBody.Truncate();
  557. mResponseBodyDecodedPos = 0;
  558. }
  559. mResponseText.CreateSnapshot(aSnapshot);
  560. }
  561. nsresult
  562. XMLHttpRequestMainThread::CreateResponseParsedJSON(JSContext* aCx)
  563. {
  564. if (!aCx) {
  565. return NS_ERROR_FAILURE;
  566. }
  567. nsAutoString string;
  568. if (!mResponseText.GetAsString(string)) {
  569. return NS_ERROR_OUT_OF_MEMORY;
  570. }
  571. // The Unicode converter has already zapped the BOM if there was one
  572. JS::Rooted<JS::Value> value(aCx);
  573. if (!JS_ParseJSON(aCx, string.BeginReading(), string.Length(), &value)) {
  574. return NS_ERROR_FAILURE;
  575. }
  576. mResultJSON = value;
  577. return NS_OK;
  578. }
  579. void
  580. XMLHttpRequestMainThread::CreatePartialBlob(ErrorResult& aRv)
  581. {
  582. if (mDOMBlob) {
  583. // Use progress info to determine whether load is complete, but use
  584. // mDataAvailable to ensure a slice is created based on the uncompressed
  585. // data count.
  586. if (mState == State::done) {
  587. mResponseBlob = mDOMBlob;
  588. } else {
  589. mResponseBlob = mDOMBlob->CreateSlice(0, mDataAvailable,
  590. EmptyString(), aRv);
  591. }
  592. return;
  593. }
  594. // mBlobSet can be null if the request has been canceled
  595. if (!mBlobSet) {
  596. return;
  597. }
  598. nsAutoCString contentType;
  599. if (mState == State::done) {
  600. mChannel->GetContentType(contentType);
  601. }
  602. nsTArray<RefPtr<BlobImpl>> subImpls(mBlobSet->GetBlobImpls());
  603. RefPtr<BlobImpl> blobImpl =
  604. MultipartBlobImpl::Create(Move(subImpls),
  605. NS_ConvertASCIItoUTF16(contentType),
  606. aRv);
  607. if (NS_WARN_IF(aRv.Failed())) {
  608. return;
  609. }
  610. mResponseBlob = Blob::Create(GetOwner(), blobImpl);
  611. }
  612. NS_IMETHODIMP XMLHttpRequestMainThread::GetResponseType(nsAString& aResponseType)
  613. {
  614. MOZ_ASSERT(mResponseType < XMLHttpRequestResponseType::EndGuard_);
  615. const EnumEntry& entry =
  616. XMLHttpRequestResponseTypeValues::strings[static_cast<uint32_t>(mResponseType)];
  617. aResponseType.AssignASCII(entry.value, entry.length);
  618. return NS_OK;
  619. }
  620. NS_IMETHODIMP XMLHttpRequestMainThread::SetResponseType(const nsAString& aResponseType)
  621. {
  622. uint32_t i = 0;
  623. for (const EnumEntry* entry = XMLHttpRequestResponseTypeValues::strings;
  624. entry->value; ++entry, ++i) {
  625. if (aResponseType.EqualsASCII(entry->value, entry->length)) {
  626. ErrorResult rv;
  627. SetResponseType(static_cast<XMLHttpRequestResponseType>(i), rv);
  628. return rv.StealNSResult();
  629. }
  630. }
  631. return NS_OK;
  632. }
  633. void
  634. XMLHttpRequestMainThread::SetResponseType(XMLHttpRequestResponseType aResponseType,
  635. ErrorResult& aRv)
  636. {
  637. if (mState == State::loading || mState == State::done) {
  638. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_LOADING_OR_DONE);
  639. return;
  640. }
  641. // sync request is not allowed setting responseType in window context
  642. if (HasOrHasHadOwner() && mState != State::unsent && mFlagSynchronous) {
  643. LogMessage("ResponseTypeSyncXHRWarning", GetOwner());
  644. aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_XHR_TIMEOUT_AND_RESPONSETYPE_UNSUPPORTED_FOR_SYNC);
  645. return;
  646. }
  647. if (mFlagSynchronous &&
  648. (aResponseType == XMLHttpRequestResponseType::Moz_chunked_text ||
  649. aResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer)) {
  650. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_CHUNKED_RESPONSETYPES_UNSUPPORTED_FOR_SYNC);
  651. return;
  652. }
  653. // Set the responseType attribute's value to the given value.
  654. mResponseType = aResponseType;
  655. }
  656. NS_IMETHODIMP
  657. XMLHttpRequestMainThread::GetResponse(JSContext *aCx, JS::MutableHandle<JS::Value> aResult)
  658. {
  659. ErrorResult rv;
  660. GetResponse(aCx, aResult, rv);
  661. return rv.StealNSResult();
  662. }
  663. void
  664. XMLHttpRequestMainThread::GetResponse(JSContext* aCx,
  665. JS::MutableHandle<JS::Value> aResponse,
  666. ErrorResult& aRv)
  667. {
  668. switch (mResponseType) {
  669. case XMLHttpRequestResponseType::_empty:
  670. case XMLHttpRequestResponseType::Text:
  671. case XMLHttpRequestResponseType::Moz_chunked_text:
  672. {
  673. DOMString str;
  674. GetResponseText(str, aRv);
  675. if (aRv.Failed()) {
  676. return;
  677. }
  678. if (!xpc::StringToJsval(aCx, str, aResponse)) {
  679. aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
  680. }
  681. return;
  682. }
  683. case XMLHttpRequestResponseType::Arraybuffer:
  684. case XMLHttpRequestResponseType::Moz_chunked_arraybuffer:
  685. {
  686. if (!(mResponseType == XMLHttpRequestResponseType::Arraybuffer &&
  687. mState == State::done) &&
  688. !(mResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer &&
  689. mInLoadProgressEvent)) {
  690. aResponse.setNull();
  691. return;
  692. }
  693. if (!mResultArrayBuffer) {
  694. mResultArrayBuffer = mArrayBufferBuilder.getArrayBuffer(aCx);
  695. if (!mResultArrayBuffer) {
  696. aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
  697. return;
  698. }
  699. }
  700. aResponse.setObject(*mResultArrayBuffer);
  701. return;
  702. }
  703. case XMLHttpRequestResponseType::Blob:
  704. case XMLHttpRequestResponseType::Moz_blob:
  705. {
  706. if (mState != State::done) {
  707. if (mResponseType != XMLHttpRequestResponseType::Moz_blob) {
  708. aResponse.setNull();
  709. return;
  710. }
  711. if (!mResponseBlob) {
  712. CreatePartialBlob(aRv);
  713. }
  714. }
  715. if (!mResponseBlob) {
  716. aResponse.setNull();
  717. return;
  718. }
  719. GetOrCreateDOMReflector(aCx, mResponseBlob, aResponse);
  720. return;
  721. }
  722. case XMLHttpRequestResponseType::Document:
  723. {
  724. if (!mResponseXML || mState != State::done) {
  725. aResponse.setNull();
  726. return;
  727. }
  728. aRv = nsContentUtils::WrapNative(aCx, mResponseXML, aResponse);
  729. return;
  730. }
  731. case XMLHttpRequestResponseType::Json:
  732. {
  733. if (mState != State::done) {
  734. aResponse.setNull();
  735. return;
  736. }
  737. if (mResultJSON.isUndefined()) {
  738. aRv = CreateResponseParsedJSON(aCx);
  739. TruncateResponseText();
  740. if (aRv.Failed()) {
  741. // Per spec, errors aren't propagated. null is returned instead.
  742. aRv = NS_OK;
  743. // It would be nice to log the error to the console. That's hard to
  744. // do without calling window.onerror as a side effect, though.
  745. JS_ClearPendingException(aCx);
  746. mResultJSON.setNull();
  747. }
  748. }
  749. aResponse.set(mResultJSON);
  750. return;
  751. }
  752. default:
  753. NS_ERROR("Should not happen");
  754. }
  755. aResponse.setNull();
  756. }
  757. bool
  758. XMLHttpRequestMainThread::IsCrossSiteCORSRequest() const
  759. {
  760. if (!mChannel) {
  761. return false;
  762. }
  763. nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
  764. MOZ_ASSERT(loadInfo);
  765. return loadInfo->GetTainting() == LoadTainting::CORS;
  766. }
  767. bool
  768. XMLHttpRequestMainThread::IsDeniedCrossSiteCORSRequest()
  769. {
  770. if (IsCrossSiteCORSRequest()) {
  771. nsresult rv;
  772. mChannel->GetStatus(&rv);
  773. if (NS_FAILED(rv)) {
  774. return true;
  775. }
  776. }
  777. return false;
  778. }
  779. void
  780. XMLHttpRequestMainThread::GetResponseURL(nsAString& aUrl)
  781. {
  782. aUrl.Truncate();
  783. uint16_t readyState = ReadyState();
  784. if ((readyState == UNSENT || readyState == OPENED) || !mChannel) {
  785. return;
  786. }
  787. // Make sure we don't leak responseURL information from denied cross-site
  788. // requests.
  789. if (IsDeniedCrossSiteCORSRequest()) {
  790. return;
  791. }
  792. nsCOMPtr<nsIURI> responseUrl;
  793. mChannel->GetURI(getter_AddRefs(responseUrl));
  794. if (!responseUrl) {
  795. return;
  796. }
  797. nsAutoCString temp;
  798. responseUrl->GetSpecIgnoringRef(temp);
  799. CopyUTF8toUTF16(temp, aUrl);
  800. }
  801. NS_IMETHODIMP
  802. XMLHttpRequestMainThread::GetStatus(uint32_t *aStatus)
  803. {
  804. ErrorResult rv;
  805. *aStatus = GetStatus(rv);
  806. return rv.StealNSResult();
  807. }
  808. uint32_t
  809. XMLHttpRequestMainThread::GetStatus(ErrorResult& aRv)
  810. {
  811. // Make sure we don't leak status information from denied cross-site
  812. // requests.
  813. if (IsDeniedCrossSiteCORSRequest()) {
  814. return 0;
  815. }
  816. uint16_t readyState = ReadyState();
  817. if (readyState == UNSENT || readyState == OPENED) {
  818. return 0;
  819. }
  820. if (mErrorLoad) {
  821. // Let's simulate the http protocol for jar/app requests:
  822. nsCOMPtr<nsIJARChannel> jarChannel = GetCurrentJARChannel();
  823. if (jarChannel) {
  824. nsresult status;
  825. mChannel->GetStatus(&status);
  826. if (status == NS_ERROR_FILE_NOT_FOUND) {
  827. return 404; // Not Found
  828. } else {
  829. return 500; // Internal Error
  830. }
  831. }
  832. return 0;
  833. }
  834. nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
  835. if (!httpChannel) {
  836. // Pretend like we got a 200 response, since our load was successful
  837. return 200;
  838. }
  839. uint32_t status;
  840. nsresult rv = httpChannel->GetResponseStatus(&status);
  841. if (NS_FAILED(rv)) {
  842. status = 0;
  843. }
  844. return status;
  845. }
  846. NS_IMETHODIMP
  847. XMLHttpRequestMainThread::GetStatusText(nsACString& aOut)
  848. {
  849. ErrorResult rv;
  850. GetStatusText(aOut, rv);
  851. return rv.StealNSResult();
  852. }
  853. void
  854. XMLHttpRequestMainThread::GetStatusText(nsACString& aStatusText,
  855. ErrorResult& aRv)
  856. {
  857. // Return an empty status text on all error loads.
  858. aStatusText.Truncate();
  859. // Make sure we don't leak status information from denied cross-site
  860. // requests.
  861. if (IsDeniedCrossSiteCORSRequest()) {
  862. return;
  863. }
  864. // Check the current XHR state to see if it is valid to obtain the statusText
  865. // value. This check is to prevent the status text for redirects from being
  866. // available before all the redirects have been followed and HTTP headers have
  867. // been received.
  868. uint16_t readyState = ReadyState();
  869. if (readyState == UNSENT || readyState == OPENED) {
  870. return;
  871. }
  872. if (mErrorLoad) {
  873. return;
  874. }
  875. nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
  876. if (httpChannel) {
  877. httpChannel->GetResponseStatusText(aStatusText);
  878. } else {
  879. aStatusText.AssignLiteral("OK");
  880. }
  881. }
  882. void
  883. XMLHttpRequestMainThread::CloseRequest()
  884. {
  885. mWaitingForOnStopRequest = false;
  886. if (mChannel) {
  887. mChannel->Cancel(NS_BINDING_ABORTED);
  888. }
  889. if (mTimeoutTimer) {
  890. mTimeoutTimer->Cancel();
  891. }
  892. }
  893. void
  894. XMLHttpRequestMainThread::CloseRequestWithError(const ProgressEventType aType)
  895. {
  896. CloseRequest();
  897. ResetResponse();
  898. // If we're in the destructor, don't risk dispatching an event.
  899. if (mFlagDeleted) {
  900. mFlagSyncLooping = false;
  901. return;
  902. }
  903. if (mState != State::unsent &&
  904. !(mState == State::opened && !mFlagSend) &&
  905. mState != State::done) {
  906. ChangeState(State::done, true);
  907. if (!mFlagSyncLooping) {
  908. if (mUpload && !mUploadComplete) {
  909. mUploadComplete = true;
  910. DispatchProgressEvent(mUpload, aType, 0, -1);
  911. }
  912. DispatchProgressEvent(this, aType, 0, -1);
  913. }
  914. }
  915. // The ChangeState call above calls onreadystatechange handlers which
  916. // if they load a new url will cause XMLHttpRequestMainThread::Open to clear
  917. // the abort state bit. If this occurs we're not uninitialized (bug 361773).
  918. if (mFlagAborted) {
  919. ChangeState(State::unsent, false); // IE seems to do it
  920. }
  921. mFlagSyncLooping = false;
  922. }
  923. void
  924. XMLHttpRequestMainThread::RequestErrorSteps(const ProgressEventType aEventType,
  925. const nsresult aOptionalException,
  926. ErrorResult& aRv)
  927. {
  928. // Step 1
  929. mState = State::done;
  930. StopProgressEventTimer();
  931. // Step 2
  932. mFlagSend = false;
  933. // Step 3
  934. ResetResponse();
  935. // If we're in the destructor, don't risk dispatching an event.
  936. if (mFlagDeleted) {
  937. mFlagSyncLooping = false;
  938. return;
  939. }
  940. // Step 4
  941. if (mFlagSynchronous && NS_FAILED(aOptionalException)) {
  942. aRv.Throw(aOptionalException);
  943. return;
  944. }
  945. // Step 5
  946. FireReadystatechangeEvent();
  947. // Step 6
  948. if (mUpload && !mUploadComplete) {
  949. // Step 6-1
  950. mUploadComplete = true;
  951. // Step 6-2
  952. if (mFlagHadUploadListenersOnSend) {
  953. // Steps 6-3, 6-4 (loadend is fired for us)
  954. DispatchProgressEvent(mUpload, aEventType, 0, -1);
  955. }
  956. }
  957. // Steps 7 and 8 (loadend is fired for us)
  958. DispatchProgressEvent(this, aEventType, 0, -1);
  959. }
  960. void
  961. XMLHttpRequestMainThread::Abort(ErrorResult& aRv)
  962. {
  963. mFlagAborted = true;
  964. // Step 1
  965. CloseRequest();
  966. // Step 2
  967. if ((mState == State::opened && mFlagSend) ||
  968. mState == State::headers_received ||
  969. mState == State::loading) {
  970. RequestErrorSteps(ProgressEventType::abort, NS_OK, aRv);
  971. }
  972. // Step 3
  973. if (mState == State::done) {
  974. ChangeState(State::unsent, false); // no ReadystateChange event
  975. }
  976. mFlagSyncLooping = false;
  977. }
  978. NS_IMETHODIMP
  979. XMLHttpRequestMainThread::SlowAbort()
  980. {
  981. Abort();
  982. return NS_OK;
  983. }
  984. /*Method that checks if it is safe to expose a header value to the client.
  985. It is used to check what headers are exposed for CORS requests.*/
  986. bool
  987. XMLHttpRequestMainThread::IsSafeHeader(const nsACString& aHeader,
  988. NotNull<nsIHttpChannel*> aHttpChannel) const
  989. {
  990. // See bug #380418. Hide "Set-Cookie" headers from non-chrome scripts.
  991. if (!IsSystemXHR() && nsContentUtils::IsForbiddenResponseHeader(aHeader)) {
  992. NS_WARNING("blocked access to response header");
  993. return false;
  994. }
  995. // if this is not a CORS call all headers are safe
  996. if (!IsCrossSiteCORSRequest()) {
  997. return true;
  998. }
  999. // Check for dangerous headers
  1000. // Make sure we don't leak header information from denied cross-site
  1001. // requests.
  1002. if (mChannel) {
  1003. nsresult status;
  1004. mChannel->GetStatus(&status);
  1005. if (NS_FAILED(status)) {
  1006. return false;
  1007. }
  1008. }
  1009. const char* kCrossOriginSafeHeaders[] = {
  1010. "cache-control", "content-language", "content-type", "expires",
  1011. "last-modified", "pragma"
  1012. };
  1013. for (uint32_t i = 0; i < ArrayLength(kCrossOriginSafeHeaders); ++i) {
  1014. if (aHeader.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) {
  1015. return true;
  1016. }
  1017. }
  1018. nsAutoCString headerVal;
  1019. // The "Access-Control-Expose-Headers" header contains a comma separated
  1020. // list of method names.
  1021. aHttpChannel->
  1022. GetResponseHeader(NS_LITERAL_CSTRING("Access-Control-Expose-Headers"),
  1023. headerVal);
  1024. nsCCharSeparatedTokenizer exposeTokens(headerVal, ',');
  1025. bool isSafe = false;
  1026. while (exposeTokens.hasMoreTokens()) {
  1027. const nsDependentCSubstring& token = exposeTokens.nextToken();
  1028. if (token.IsEmpty()) {
  1029. continue;
  1030. }
  1031. if (!NS_IsValidHTTPToken(token)) {
  1032. return false;
  1033. }
  1034. if (aHeader.Equals(token, nsCaseInsensitiveCStringComparator())) {
  1035. isSafe = true;
  1036. }
  1037. }
  1038. return isSafe;
  1039. }
  1040. NS_IMETHODIMP
  1041. XMLHttpRequestMainThread::GetAllResponseHeaders(nsACString& aOut)
  1042. {
  1043. ErrorResult rv;
  1044. GetAllResponseHeaders(aOut, rv);
  1045. return rv.StealNSResult();
  1046. }
  1047. void
  1048. XMLHttpRequestMainThread::GetAllResponseHeaders(nsACString& aResponseHeaders,
  1049. ErrorResult& aRv)
  1050. {
  1051. aResponseHeaders.Truncate();
  1052. // If the state is UNSENT or OPENED,
  1053. // return the empty string and terminate these steps.
  1054. if (mState == State::unsent || mState == State::opened) {
  1055. return;
  1056. }
  1057. if (mErrorLoad) {
  1058. return;
  1059. }
  1060. if (nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel()) {
  1061. RefPtr<nsHeaderVisitor> visitor =
  1062. new nsHeaderVisitor(*this, WrapNotNull(httpChannel));
  1063. if (NS_SUCCEEDED(httpChannel->VisitResponseHeaders(visitor))) {
  1064. aResponseHeaders = visitor->Headers();
  1065. }
  1066. return;
  1067. }
  1068. if (!mChannel) {
  1069. return;
  1070. }
  1071. // Even non-http channels supply content type.
  1072. nsAutoCString value;
  1073. if (NS_SUCCEEDED(mChannel->GetContentType(value))) {
  1074. aResponseHeaders.AppendLiteral("Content-Type: ");
  1075. aResponseHeaders.Append(value);
  1076. if (NS_SUCCEEDED(mChannel->GetContentCharset(value)) && !value.IsEmpty()) {
  1077. aResponseHeaders.AppendLiteral(";charset=");
  1078. aResponseHeaders.Append(value);
  1079. }
  1080. aResponseHeaders.AppendLiteral("\r\n");
  1081. }
  1082. // Don't provide Content-Length for data URIs
  1083. nsCOMPtr<nsIURI> uri;
  1084. bool isDataURI;
  1085. if (NS_FAILED(mChannel->GetURI(getter_AddRefs(uri))) ||
  1086. NS_FAILED(uri->SchemeIs("data", &isDataURI)) ||
  1087. !isDataURI) {
  1088. int64_t length;
  1089. if (NS_SUCCEEDED(mChannel->GetContentLength(&length))) {
  1090. aResponseHeaders.AppendLiteral("Content-Length: ");
  1091. aResponseHeaders.AppendInt(length);
  1092. aResponseHeaders.AppendLiteral("\r\n");
  1093. }
  1094. }
  1095. }
  1096. NS_IMETHODIMP
  1097. XMLHttpRequestMainThread::GetResponseHeader(const nsACString& aHeader,
  1098. nsACString& aResult)
  1099. {
  1100. ErrorResult rv;
  1101. GetResponseHeader(aHeader, aResult, rv);
  1102. return rv.StealNSResult();
  1103. }
  1104. void
  1105. XMLHttpRequestMainThread::GetResponseHeader(const nsACString& header,
  1106. nsACString& _retval, ErrorResult& aRv)
  1107. {
  1108. _retval.SetIsVoid(true);
  1109. nsCOMPtr<nsIHttpChannel> httpChannel = GetCurrentHttpChannel();
  1110. if (!httpChannel) {
  1111. // If the state is UNSENT or OPENED,
  1112. // return null and terminate these steps.
  1113. if (mState == State::unsent || mState == State::opened) {
  1114. return;
  1115. }
  1116. // Even non-http channels supply content type and content length.
  1117. // Remember we don't leak header information from denied cross-site
  1118. // requests.
  1119. nsresult status;
  1120. if (!mChannel ||
  1121. NS_FAILED(mChannel->GetStatus(&status)) ||
  1122. NS_FAILED(status)) {
  1123. return;
  1124. }
  1125. // Content Type:
  1126. if (header.LowerCaseEqualsASCII("content-type")) {
  1127. if (NS_FAILED(mChannel->GetContentType(_retval))) {
  1128. // Means no content type
  1129. _retval.SetIsVoid(true);
  1130. return;
  1131. }
  1132. nsCString value;
  1133. if (NS_SUCCEEDED(mChannel->GetContentCharset(value)) &&
  1134. !value.IsEmpty()) {
  1135. _retval.AppendLiteral(";charset=");
  1136. _retval.Append(value);
  1137. }
  1138. }
  1139. // Content Length:
  1140. else if (header.LowerCaseEqualsASCII("content-length")) {
  1141. int64_t length;
  1142. if (NS_SUCCEEDED(mChannel->GetContentLength(&length))) {
  1143. _retval.AppendInt(length);
  1144. }
  1145. }
  1146. return;
  1147. }
  1148. // Check for dangerous headers
  1149. if (!IsSafeHeader(header, WrapNotNull(httpChannel))) {
  1150. return;
  1151. }
  1152. aRv = httpChannel->GetResponseHeader(header, _retval);
  1153. if (aRv.ErrorCodeIs(NS_ERROR_NOT_AVAILABLE)) {
  1154. // Means no header
  1155. _retval.SetIsVoid(true);
  1156. aRv.SuppressException();
  1157. }
  1158. }
  1159. already_AddRefed<nsILoadGroup>
  1160. XMLHttpRequestMainThread::GetLoadGroup() const
  1161. {
  1162. if (mFlagBackgroundRequest) {
  1163. return nullptr;
  1164. }
  1165. if (mLoadGroup) {
  1166. nsCOMPtr<nsILoadGroup> ref = mLoadGroup;
  1167. return ref.forget();
  1168. }
  1169. nsIDocument* doc = GetDocumentIfCurrent();
  1170. if (doc) {
  1171. return doc->GetDocumentLoadGroup();
  1172. }
  1173. return nullptr;
  1174. }
  1175. nsresult
  1176. XMLHttpRequestMainThread::FireReadystatechangeEvent()
  1177. {
  1178. RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
  1179. event->InitEvent(kLiteralString_readystatechange, false, false);
  1180. // We assume anyone who managed to call CreateReadystatechangeEvent is trusted
  1181. event->SetTrusted(true);
  1182. DispatchDOMEvent(nullptr, event, nullptr, nullptr);
  1183. return NS_OK;
  1184. }
  1185. void
  1186. XMLHttpRequestMainThread::DispatchProgressEvent(DOMEventTargetHelper* aTarget,
  1187. const ProgressEventType aType,
  1188. int64_t aLoaded, int64_t aTotal)
  1189. {
  1190. NS_ASSERTION(aTarget, "null target");
  1191. if (NS_FAILED(CheckInnerWindowCorrectness()) ||
  1192. (!AllowUploadProgress() && aTarget == mUpload)) {
  1193. return;
  1194. }
  1195. // If blocked by CORS, zero-out the stats on progress events
  1196. // and never fire "progress" or "load" events at all.
  1197. if (IsDeniedCrossSiteCORSRequest()) {
  1198. if (aType == ProgressEventType::progress ||
  1199. aType == ProgressEventType::load) {
  1200. return;
  1201. }
  1202. aLoaded = 0;
  1203. aTotal = -1;
  1204. }
  1205. if (aType == ProgressEventType::progress) {
  1206. mInLoadProgressEvent = true;
  1207. }
  1208. ProgressEventInit init;
  1209. init.mBubbles = false;
  1210. init.mCancelable = false;
  1211. init.mLengthComputable = aTotal != -1; // XHR spec step 6.1
  1212. init.mLoaded = aLoaded;
  1213. init.mTotal = (aTotal == -1) ? 0 : aTotal;
  1214. const nsAString& typeString = ProgressEventTypeStrings[(uint8_t)aType];
  1215. RefPtr<ProgressEvent> event =
  1216. ProgressEvent::Constructor(aTarget, typeString, init);
  1217. event->SetTrusted(true);
  1218. aTarget->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
  1219. if (aType == ProgressEventType::progress) {
  1220. mInLoadProgressEvent = false;
  1221. // clear chunked responses after every progress event
  1222. if (mResponseType == XMLHttpRequestResponseType::Moz_chunked_text ||
  1223. mResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer) {
  1224. mResponseBody.Truncate();
  1225. TruncateResponseText();
  1226. mResultArrayBuffer = nullptr;
  1227. mArrayBufferBuilder.reset();
  1228. }
  1229. }
  1230. // If we're sending a load, error, timeout or abort event, then
  1231. // also dispatch the subsequent loadend event.
  1232. if (aType == ProgressEventType::load || aType == ProgressEventType::error ||
  1233. aType == ProgressEventType::timeout || aType == ProgressEventType::abort) {
  1234. DispatchProgressEvent(aTarget, ProgressEventType::loadend, aLoaded, aTotal);
  1235. }
  1236. }
  1237. already_AddRefed<nsIHttpChannel>
  1238. XMLHttpRequestMainThread::GetCurrentHttpChannel()
  1239. {
  1240. nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
  1241. return httpChannel.forget();
  1242. }
  1243. already_AddRefed<nsIJARChannel>
  1244. XMLHttpRequestMainThread::GetCurrentJARChannel()
  1245. {
  1246. nsCOMPtr<nsIJARChannel> appChannel = do_QueryInterface(mChannel);
  1247. return appChannel.forget();
  1248. }
  1249. bool
  1250. XMLHttpRequestMainThread::IsSystemXHR() const
  1251. {
  1252. return mIsSystem || nsContentUtils::IsSystemPrincipal(mPrincipal);
  1253. }
  1254. bool
  1255. XMLHttpRequestMainThread::InUploadPhase() const
  1256. {
  1257. // We're in the upload phase while our state is State::opened.
  1258. return mState == State::opened;
  1259. }
  1260. NS_IMETHODIMP
  1261. XMLHttpRequestMainThread::Open(const nsACString& aMethod, const nsACString& aUrl,
  1262. bool aAsync, const nsAString& aUsername,
  1263. const nsAString& aPassword, uint8_t optional_argc)
  1264. {
  1265. return Open(aMethod, aUrl, optional_argc > 0 ? aAsync : true,
  1266. aUsername, aPassword);
  1267. }
  1268. // This case is hit when the async parameter is outright omitted, which
  1269. // should set it to true (and the username and password to null).
  1270. void
  1271. XMLHttpRequestMainThread::Open(const nsACString& aMethod, const nsAString& aUrl,
  1272. ErrorResult& aRv)
  1273. {
  1274. Open(aMethod, aUrl, true, NullString(), NullString(), aRv);
  1275. }
  1276. // This case is hit when the async parameter is specified, even if the
  1277. // JS value was "undefined" (which due to legacy reasons should be
  1278. // treated as true, which is how it will already be passed in here).
  1279. void
  1280. XMLHttpRequestMainThread::Open(const nsACString& aMethod,
  1281. const nsAString& aUrl,
  1282. bool aAsync,
  1283. const nsAString& aUsername,
  1284. const nsAString& aPassword,
  1285. ErrorResult& aRv)
  1286. {
  1287. nsresult rv = Open(aMethod, NS_ConvertUTF16toUTF8(aUrl), aAsync, aUsername, aPassword);
  1288. if (NS_FAILED(rv)) {
  1289. aRv.Throw(rv);
  1290. }
  1291. }
  1292. nsresult
  1293. XMLHttpRequestMainThread::Open(const nsACString& aMethod,
  1294. const nsACString& aUrl,
  1295. bool aAsync,
  1296. const nsAString& aUsername,
  1297. const nsAString& aPassword) {
  1298. // Gecko-specific
  1299. if (!aAsync && !DontWarnAboutSyncXHR() && GetOwner() &&
  1300. GetOwner()->GetExtantDoc()) {
  1301. GetOwner()->GetExtantDoc()->WarnOnceAbout(nsIDocument::eSyncXMLHttpRequest);
  1302. }
  1303. // Step 1
  1304. nsCOMPtr<nsIDocument> responsibleDocument = GetDocumentIfCurrent();
  1305. if (!responsibleDocument) {
  1306. // This could be because we're no longer current or because we're in some
  1307. // non-window context...
  1308. nsresult rv = CheckInnerWindowCorrectness();
  1309. if (NS_WARN_IF(NS_FAILED(rv))) {
  1310. return NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT;
  1311. }
  1312. }
  1313. NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED);
  1314. // Steps 2-4
  1315. nsAutoCString method;
  1316. nsresult rv = FetchUtil::GetValidRequestMethod(aMethod, method);
  1317. if (NS_WARN_IF(NS_FAILED(rv))) {
  1318. return rv;
  1319. }
  1320. // Steps 5-6
  1321. nsCOMPtr<nsIURI> baseURI;
  1322. if (mBaseURI) {
  1323. baseURI = mBaseURI;
  1324. } else if (responsibleDocument) {
  1325. baseURI = responsibleDocument->GetBaseURI();
  1326. }
  1327. nsCOMPtr<nsIURI> parsedURL;
  1328. rv = NS_NewURI(getter_AddRefs(parsedURL), aUrl, nullptr, baseURI);
  1329. if (NS_FAILED(rv)) {
  1330. if (rv == NS_ERROR_MALFORMED_URI) {
  1331. return NS_ERROR_DOM_MALFORMED_URI;
  1332. }
  1333. return rv;
  1334. }
  1335. if (NS_WARN_IF(NS_FAILED(CheckInnerWindowCorrectness()))) {
  1336. return NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT;
  1337. }
  1338. // Step 7
  1339. // This is already handled by the other Open() method, which passes
  1340. // username and password in as NullStrings.
  1341. // Step 8
  1342. nsAutoCString host;
  1343. parsedURL->GetHost(host);
  1344. if (!host.IsEmpty()) {
  1345. nsAutoCString userpass;
  1346. if (!aUsername.IsVoid()) {
  1347. CopyUTF16toUTF8(aUsername, userpass);
  1348. }
  1349. userpass.AppendLiteral(":");
  1350. if (!aPassword.IsVoid()) {
  1351. AppendUTF16toUTF8(aPassword, userpass);
  1352. }
  1353. parsedURL->SetUserPass(userpass);
  1354. }
  1355. // Step 9
  1356. if (!aAsync && HasOrHasHadOwner() && (mTimeoutMilliseconds ||
  1357. mResponseType != XMLHttpRequestResponseType::_empty)) {
  1358. if (mTimeoutMilliseconds) {
  1359. LogMessage("TimeoutSyncXHRWarning", GetOwner());
  1360. }
  1361. if (mResponseType != XMLHttpRequestResponseType::_empty) {
  1362. LogMessage("ResponseTypeSyncXHRWarning", GetOwner());
  1363. }
  1364. return NS_ERROR_DOM_INVALID_ACCESS_XHR_TIMEOUT_AND_RESPONSETYPE_UNSUPPORTED_FOR_SYNC;
  1365. }
  1366. // Step 10
  1367. CloseRequest();
  1368. // Step 11
  1369. // timeouts are handled without a flag
  1370. mFlagSend = false;
  1371. mRequestMethod.Assign(method);
  1372. mRequestURL = parsedURL;
  1373. mFlagSynchronous = !aAsync;
  1374. mAuthorRequestHeaders.Clear();
  1375. ResetResponse();
  1376. // Gecko-specific
  1377. mFlagHadUploadListenersOnSend = false;
  1378. mFlagAborted = false;
  1379. mFlagTimedOut = false;
  1380. // Per spec we should only create the channel on send(), but we have internal
  1381. // code that relies on the channel being created now, and that code is not
  1382. // always IsSystemXHR(). However, we're not supposed to throw channel-creation
  1383. // errors during open(), so we silently ignore those here.
  1384. CreateChannel();
  1385. // Step 12
  1386. if (mState != State::opened) {
  1387. mState = State::opened;
  1388. FireReadystatechangeEvent();
  1389. }
  1390. return NS_OK;
  1391. }
  1392. void
  1393. XMLHttpRequestMainThread::SetOriginAttributes(const OriginAttributesDictionary& aAttrs)
  1394. {
  1395. MOZ_ASSERT((mState == State::opened) && !mFlagSend);
  1396. GenericOriginAttributes attrs(aAttrs);
  1397. NeckoOriginAttributes neckoAttrs;
  1398. neckoAttrs.SetFromGenericAttributes(attrs);
  1399. nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
  1400. MOZ_ASSERT(loadInfo);
  1401. loadInfo->SetOriginAttributes(neckoAttrs);
  1402. }
  1403. void
  1404. XMLHttpRequestMainThread::PopulateNetworkInterfaceId()
  1405. {
  1406. if (mNetworkInterfaceId.IsEmpty()) {
  1407. return;
  1408. }
  1409. nsCOMPtr<nsIHttpChannelInternal> channel(do_QueryInterface(mChannel));
  1410. if (!channel) {
  1411. return;
  1412. }
  1413. channel->SetNetworkInterfaceId(mNetworkInterfaceId);
  1414. }
  1415. /*
  1416. * "Copy" from a stream.
  1417. */
  1418. nsresult
  1419. XMLHttpRequestMainThread::StreamReaderFunc(nsIInputStream* in,
  1420. void* closure,
  1421. const char* fromRawSegment,
  1422. uint32_t toOffset,
  1423. uint32_t count,
  1424. uint32_t *writeCount)
  1425. {
  1426. XMLHttpRequestMainThread* xmlHttpRequest = static_cast<XMLHttpRequestMainThread*>(closure);
  1427. if (!xmlHttpRequest || !writeCount) {
  1428. NS_WARNING("XMLHttpRequest cannot read from stream: no closure or writeCount");
  1429. return NS_ERROR_FAILURE;
  1430. }
  1431. nsresult rv = NS_OK;
  1432. if (xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Blob) {
  1433. if (!xmlHttpRequest->mDOMBlob) {
  1434. xmlHttpRequest->MaybeCreateBlobStorage();
  1435. rv = xmlHttpRequest->mBlobStorage->Append(fromRawSegment, count);
  1436. }
  1437. } else if (xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Moz_blob) {
  1438. if (!xmlHttpRequest->mDOMBlob) {
  1439. if (!xmlHttpRequest->mBlobSet) {
  1440. xmlHttpRequest->mBlobSet = new BlobSet();
  1441. }
  1442. rv = xmlHttpRequest->mBlobSet->AppendVoidPtr(fromRawSegment, count);
  1443. }
  1444. // Clear the cache so that the blob size is updated.
  1445. xmlHttpRequest->mResponseBlob = nullptr;
  1446. } else if ((xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Arraybuffer &&
  1447. !xmlHttpRequest->mIsMappedArrayBuffer) ||
  1448. xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer) {
  1449. // get the initial capacity to something reasonable to avoid a bunch of reallocs right
  1450. // at the start
  1451. if (xmlHttpRequest->mArrayBufferBuilder.capacity() == 0)
  1452. xmlHttpRequest->mArrayBufferBuilder.setCapacity(std::max(count, XML_HTTP_REQUEST_ARRAYBUFFER_MIN_SIZE));
  1453. xmlHttpRequest->mArrayBufferBuilder.append(reinterpret_cast<const uint8_t*>(fromRawSegment), count,
  1454. XML_HTTP_REQUEST_ARRAYBUFFER_MAX_GROWTH);
  1455. } else if (xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::_empty &&
  1456. xmlHttpRequest->mResponseXML) {
  1457. // Copy for our own use
  1458. if (!xmlHttpRequest->mResponseBody.Append(fromRawSegment, count, fallible)) {
  1459. return NS_ERROR_OUT_OF_MEMORY;
  1460. }
  1461. } else if (xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::_empty ||
  1462. xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Text ||
  1463. xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Json ||
  1464. xmlHttpRequest->mResponseType == XMLHttpRequestResponseType::Moz_chunked_text) {
  1465. NS_ASSERTION(!xmlHttpRequest->mResponseXML,
  1466. "We shouldn't be parsing a doc here");
  1467. xmlHttpRequest->AppendToResponseText(fromRawSegment, count);
  1468. }
  1469. if (xmlHttpRequest->mFlagParseBody) {
  1470. // Give the same data to the parser.
  1471. // We need to wrap the data in a new lightweight stream and pass that
  1472. // to the parser, because calling ReadSegments() recursively on the same
  1473. // stream is not supported.
  1474. nsCOMPtr<nsIInputStream> copyStream;
  1475. rv = NS_NewByteInputStream(getter_AddRefs(copyStream), fromRawSegment, count);
  1476. if (NS_SUCCEEDED(rv) && xmlHttpRequest->mXMLParserStreamListener) {
  1477. NS_ASSERTION(copyStream, "NS_NewByteInputStream lied");
  1478. nsresult parsingResult = xmlHttpRequest->mXMLParserStreamListener
  1479. ->OnDataAvailable(xmlHttpRequest->mChannel,
  1480. xmlHttpRequest->mContext,
  1481. copyStream, toOffset, count);
  1482. // No use to continue parsing if we failed here, but we
  1483. // should still finish reading the stream
  1484. if (NS_FAILED(parsingResult)) {
  1485. xmlHttpRequest->mFlagParseBody = false;
  1486. }
  1487. }
  1488. }
  1489. if (NS_SUCCEEDED(rv)) {
  1490. *writeCount = count;
  1491. } else {
  1492. *writeCount = 0;
  1493. }
  1494. return rv;
  1495. }
  1496. bool XMLHttpRequestMainThread::CreateDOMBlob(nsIRequest *request)
  1497. {
  1498. nsCOMPtr<nsIFile> file;
  1499. nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(request);
  1500. if (fc) {
  1501. fc->GetFile(getter_AddRefs(file));
  1502. }
  1503. if (!file)
  1504. return false;
  1505. nsAutoCString contentType;
  1506. mChannel->GetContentType(contentType);
  1507. mDOMBlob = File::CreateFromFile(GetOwner(), file, EmptyString(),
  1508. NS_ConvertASCIItoUTF16(contentType));
  1509. mBlobStorage = nullptr;
  1510. mBlobSet = nullptr;
  1511. NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
  1512. return true;
  1513. }
  1514. NS_IMETHODIMP
  1515. XMLHttpRequestMainThread::OnDataAvailable(nsIRequest *request,
  1516. nsISupports *ctxt,
  1517. nsIInputStream *inStr,
  1518. uint64_t sourceOffset,
  1519. uint32_t count)
  1520. {
  1521. NS_ENSURE_ARG_POINTER(inStr);
  1522. MOZ_ASSERT(mContext.get() == ctxt,"start context different from OnDataAvailable context");
  1523. mProgressSinceLastProgressEvent = true;
  1524. XMLHttpRequestBinding::ClearCachedResponseTextValue(this);
  1525. bool cancelable = false;
  1526. if ((mResponseType == XMLHttpRequestResponseType::Blob ||
  1527. mResponseType == XMLHttpRequestResponseType::Moz_blob) && !mDOMBlob) {
  1528. cancelable = CreateDOMBlob(request);
  1529. // The nsIStreamListener contract mandates us
  1530. // to read from the stream before returning.
  1531. }
  1532. uint32_t totalRead;
  1533. nsresult rv = inStr->ReadSegments(XMLHttpRequestMainThread::StreamReaderFunc,
  1534. (void*)this, count, &totalRead);
  1535. NS_ENSURE_SUCCESS(rv, rv);
  1536. if (cancelable) {
  1537. // We don't have to read from the local file for the blob response
  1538. ErrorResult error;
  1539. mDataAvailable = mDOMBlob->GetSize(error);
  1540. if (NS_WARN_IF(error.Failed())) {
  1541. return error.StealNSResult();
  1542. }
  1543. ChangeState(State::loading);
  1544. return request->Cancel(NS_OK);
  1545. }
  1546. mDataAvailable += totalRead;
  1547. // Fire the first progress event/loading state change
  1548. if (mState != State::loading) {
  1549. ChangeState(State::loading);
  1550. if (!mFlagSynchronous) {
  1551. DispatchProgressEvent(this, ProgressEventType::progress,
  1552. mLoadTransferred, mLoadTotal);
  1553. }
  1554. mProgressSinceLastProgressEvent = false;
  1555. }
  1556. if (!mFlagSynchronous && !mProgressTimerIsActive) {
  1557. StartProgressEventTimer();
  1558. }
  1559. return NS_OK;
  1560. }
  1561. NS_IMETHODIMP
  1562. XMLHttpRequestMainThread::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
  1563. {
  1564. PROFILER_LABEL("XMLHttpRequestMainThread", "OnStartRequest",
  1565. js::ProfileEntry::Category::NETWORK);
  1566. nsresult rv = NS_OK;
  1567. if (!mFirstStartRequestSeen && mRequestObserver) {
  1568. mFirstStartRequestSeen = true;
  1569. mRequestObserver->OnStartRequest(request, ctxt);
  1570. }
  1571. if (request != mChannel) {
  1572. // Can this still happen?
  1573. return NS_OK;
  1574. }
  1575. // Don't do anything if we have been aborted
  1576. if (mState == State::unsent) {
  1577. return NS_OK;
  1578. }
  1579. /* Apparently, Abort() should set State::unsent. See bug 361773.
  1580. XHR2 spec says this is correct. */
  1581. if (mFlagAborted) {
  1582. NS_ERROR("Ugh, still getting data on an aborted XMLHttpRequest!");
  1583. return NS_ERROR_UNEXPECTED;
  1584. }
  1585. // Don't do anything if we have timed out.
  1586. if (mFlagTimedOut) {
  1587. return NS_OK;
  1588. }
  1589. nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
  1590. NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
  1591. nsresult status;
  1592. request->GetStatus(&status);
  1593. mErrorLoad = mErrorLoad || NS_FAILED(status);
  1594. // Upload phase is now over. If we were uploading anything,
  1595. // stop the timer and fire any final progress events.
  1596. if (mUpload && !mUploadComplete && !mErrorLoad && !mFlagSynchronous) {
  1597. StopProgressEventTimer();
  1598. mUploadTransferred = mUploadTotal;
  1599. if (mProgressSinceLastProgressEvent) {
  1600. DispatchProgressEvent(mUpload, ProgressEventType::progress,
  1601. mUploadTransferred, mUploadTotal);
  1602. mProgressSinceLastProgressEvent = false;
  1603. }
  1604. mUploadComplete = true;
  1605. DispatchProgressEvent(mUpload, ProgressEventType::load,
  1606. mUploadTotal, mUploadTotal);
  1607. }
  1608. mContext = ctxt;
  1609. mFlagParseBody = true;
  1610. ChangeState(State::headers_received);
  1611. ResetResponse();
  1612. if (!mOverrideMimeType.IsEmpty()) {
  1613. channel->SetContentType(NS_ConvertUTF16toUTF8(mOverrideMimeType));
  1614. }
  1615. DetectCharset();
  1616. // Set up arraybuffer
  1617. if (mResponseType == XMLHttpRequestResponseType::Arraybuffer &&
  1618. NS_SUCCEEDED(status)) {
  1619. if (mIsMappedArrayBuffer) {
  1620. nsCOMPtr<nsIJARChannel> jarChannel = do_QueryInterface(channel);
  1621. if (jarChannel) {
  1622. nsCOMPtr<nsIURI> uri;
  1623. rv = channel->GetURI(getter_AddRefs(uri));
  1624. if (NS_SUCCEEDED(rv)) {
  1625. nsAutoCString file;
  1626. nsAutoCString scheme;
  1627. uri->GetScheme(scheme);
  1628. if (scheme.LowerCaseEqualsLiteral("jar")) {
  1629. nsCOMPtr<nsIJARURI> jarURI = do_QueryInterface(uri);
  1630. if (jarURI) {
  1631. jarURI->GetJAREntry(file);
  1632. }
  1633. }
  1634. nsCOMPtr<nsIFile> jarFile;
  1635. jarChannel->GetJarFile(getter_AddRefs(jarFile));
  1636. if (!jarFile) {
  1637. mIsMappedArrayBuffer = false;
  1638. } else {
  1639. rv = mArrayBufferBuilder.mapToFileInPackage(file, jarFile);
  1640. if (NS_WARN_IF(NS_FAILED(rv))) {
  1641. mIsMappedArrayBuffer = false;
  1642. } else {
  1643. channel->SetContentType(NS_LITERAL_CSTRING("application/mem-mapped"));
  1644. }
  1645. }
  1646. }
  1647. }
  1648. }
  1649. // If memory mapping failed, mIsMappedArrayBuffer would be set to false,
  1650. // and we want it fallback to the malloc way.
  1651. if (!mIsMappedArrayBuffer) {
  1652. int64_t contentLength;
  1653. rv = channel->GetContentLength(&contentLength);
  1654. if (NS_SUCCEEDED(rv) &&
  1655. contentLength > 0 &&
  1656. contentLength < XML_HTTP_REQUEST_MAX_CONTENT_LENGTH_PREALLOCATE) {
  1657. mArrayBufferBuilder.setCapacity(static_cast<int32_t>(contentLength));
  1658. }
  1659. }
  1660. }
  1661. // Set up responseXML
  1662. bool parseBody = mResponseType == XMLHttpRequestResponseType::_empty ||
  1663. mResponseType == XMLHttpRequestResponseType::Document;
  1664. nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
  1665. if (parseBody && httpChannel) {
  1666. nsAutoCString method;
  1667. httpChannel->GetRequestMethod(method);
  1668. parseBody = !method.EqualsLiteral("HEAD");
  1669. }
  1670. mIsHtml = false;
  1671. mWarnAboutSyncHtml = false;
  1672. if (parseBody && NS_SUCCEEDED(status)) {
  1673. // We can gain a huge performance win by not even trying to
  1674. // parse non-XML data. This also protects us from the situation
  1675. // where we have an XML document and sink, but HTML (or other)
  1676. // parser, which can produce unreliable results.
  1677. nsAutoCString type;
  1678. channel->GetContentType(type);
  1679. if ((mResponseType == XMLHttpRequestResponseType::Document) &&
  1680. type.EqualsLiteral("text/html")) {
  1681. // HTML parsing is only supported for responseType == "document" to
  1682. // avoid running the parser and, worse, populating responseXML for
  1683. // legacy users of XHR who use responseType == "" for retrieving the
  1684. // responseText of text/html resources. This legacy case is so common
  1685. // that it's not useful to emit a warning about it.
  1686. if (mFlagSynchronous) {
  1687. // We don't make cool new features available in the bad synchronous
  1688. // mode. The synchronous mode is for legacy only.
  1689. mWarnAboutSyncHtml = true;
  1690. mFlagParseBody = false;
  1691. } else {
  1692. mIsHtml = true;
  1693. }
  1694. } else if (!(type.EqualsLiteral("text/xml") ||
  1695. type.EqualsLiteral("application/xml") ||
  1696. type.RFind("+xml", true, -1, 4) != kNotFound)) {
  1697. // Follow https://xhr.spec.whatwg.org/
  1698. // If final MIME type is not null, text/html, text/xml, application/xml,
  1699. // or does not end in +xml, return null.
  1700. mFlagParseBody = false;
  1701. }
  1702. } else {
  1703. // The request failed, so we shouldn't be parsing anyway
  1704. mFlagParseBody = false;
  1705. }
  1706. if (mFlagParseBody) {
  1707. nsCOMPtr<nsIURI> baseURI, docURI;
  1708. rv = mChannel->GetURI(getter_AddRefs(docURI));
  1709. NS_ENSURE_SUCCESS(rv, rv);
  1710. baseURI = docURI;
  1711. nsCOMPtr<nsIDocument> doc = GetDocumentIfCurrent();
  1712. nsCOMPtr<nsIURI> chromeXHRDocURI, chromeXHRDocBaseURI;
  1713. if (doc) {
  1714. chromeXHRDocURI = doc->GetDocumentURI();
  1715. chromeXHRDocBaseURI = doc->GetBaseURI();
  1716. } else {
  1717. // If we're no longer current, just kill the load, though it really should
  1718. // have been killed already.
  1719. if (NS_WARN_IF(NS_FAILED(CheckInnerWindowCorrectness()))) {
  1720. return NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT;
  1721. }
  1722. }
  1723. // Create an empty document from it.
  1724. const nsAString& emptyStr = EmptyString();
  1725. nsCOMPtr<nsIDOMDocument> responseDoc;
  1726. nsIGlobalObject* global = DOMEventTargetHelper::GetParentObject();
  1727. nsCOMPtr<nsIPrincipal> requestingPrincipal;
  1728. rv = nsContentUtils::GetSecurityManager()->
  1729. GetChannelResultPrincipal(channel, getter_AddRefs(requestingPrincipal));
  1730. NS_ENSURE_SUCCESS(rv, rv);
  1731. rv = NS_NewDOMDocument(getter_AddRefs(responseDoc),
  1732. emptyStr, emptyStr, nullptr, docURI,
  1733. baseURI, requestingPrincipal, true, global,
  1734. mIsHtml ? DocumentFlavorHTML :
  1735. DocumentFlavorLegacyGuess);
  1736. NS_ENSURE_SUCCESS(rv, rv);
  1737. mResponseXML = do_QueryInterface(responseDoc);
  1738. mResponseXML->SetChromeXHRDocURI(chromeXHRDocURI);
  1739. mResponseXML->SetChromeXHRDocBaseURI(chromeXHRDocBaseURI);
  1740. if (nsContentUtils::IsSystemPrincipal(mPrincipal)) {
  1741. mResponseXML->ForceEnableXULXBL();
  1742. }
  1743. nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
  1744. MOZ_ASSERT(loadInfo);
  1745. bool isCrossSite = loadInfo->GetTainting() != LoadTainting::Basic;
  1746. if (isCrossSite) {
  1747. nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(mResponseXML);
  1748. if (htmlDoc) {
  1749. htmlDoc->DisableCookieAccess();
  1750. }
  1751. }
  1752. nsCOMPtr<nsIStreamListener> listener;
  1753. nsCOMPtr<nsILoadGroup> loadGroup;
  1754. channel->GetLoadGroup(getter_AddRefs(loadGroup));
  1755. // suppress <parsererror> nodes on XML document parse failure, but only
  1756. // for non-privileged code (including Web Extensions). See bug 289714.
  1757. if (!IsSystemXHR()) {
  1758. mResponseXML->SetSuppressParserErrorElement(true);
  1759. }
  1760. rv = mResponseXML->StartDocumentLoad(kLoadAsData, channel, loadGroup,
  1761. nullptr, getter_AddRefs(listener),
  1762. !isCrossSite);
  1763. NS_ENSURE_SUCCESS(rv, rv);
  1764. // the spec requires the response document.referrer to be the empty string
  1765. mResponseXML->SetReferrer(NS_LITERAL_CSTRING(""));
  1766. mXMLParserStreamListener = listener;
  1767. rv = mXMLParserStreamListener->OnStartRequest(request, ctxt);
  1768. NS_ENSURE_SUCCESS(rv, rv);
  1769. }
  1770. // Download phase beginning; start the progress event timer if necessary.
  1771. if (NS_SUCCEEDED(rv) && HasListenersFor(nsGkAtoms::onprogress)) {
  1772. StartProgressEventTimer();
  1773. }
  1774. return NS_OK;
  1775. }
  1776. NS_IMETHODIMP
  1777. XMLHttpRequestMainThread::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult status)
  1778. {
  1779. PROFILER_LABEL("XMLHttpRequestMainThread", "OnStopRequest",
  1780. js::ProfileEntry::Category::NETWORK);
  1781. if (request != mChannel) {
  1782. // Can this still happen?
  1783. return NS_OK;
  1784. }
  1785. mWaitingForOnStopRequest = false;
  1786. if (mRequestObserver) {
  1787. NS_ASSERTION(mFirstStartRequestSeen, "Inconsistent state!");
  1788. mFirstStartRequestSeen = false;
  1789. mRequestObserver->OnStopRequest(request, ctxt, status);
  1790. }
  1791. // suppress parsing failure messages to console for status 204/304 (see bug 884693).
  1792. if (mResponseXML) {
  1793. uint32_t responseStatus;
  1794. if (NS_SUCCEEDED(GetStatus(&responseStatus)) &&
  1795. (responseStatus == 204 || responseStatus == 304)) {
  1796. mResponseXML->SetSuppressParserErrorConsoleMessages(true);
  1797. }
  1798. }
  1799. // make sure to notify the listener if we were aborted
  1800. // XXX in fact, why don't we do the cleanup below in this case??
  1801. // State::unsent is for abort calls. See OnStartRequest above.
  1802. if (mState == State::unsent || mFlagTimedOut) {
  1803. if (mXMLParserStreamListener)
  1804. (void) mXMLParserStreamListener->OnStopRequest(request, ctxt, status);
  1805. return NS_OK;
  1806. }
  1807. // Is this good enough here?
  1808. if (mXMLParserStreamListener && mFlagParseBody) {
  1809. mXMLParserStreamListener->OnStopRequest(request, ctxt, status);
  1810. }
  1811. mXMLParserStreamListener = nullptr;
  1812. mContext = nullptr;
  1813. bool waitingForBlobCreation = false;
  1814. if (NS_SUCCEEDED(status) &&
  1815. (mResponseType == XMLHttpRequestResponseType::Blob ||
  1816. mResponseType == XMLHttpRequestResponseType::Moz_blob)) {
  1817. ErrorResult rv;
  1818. if (!mDOMBlob) {
  1819. CreateDOMBlob(request);
  1820. }
  1821. if (mDOMBlob) {
  1822. mResponseBlob = mDOMBlob;
  1823. mDOMBlob = nullptr;
  1824. } else {
  1825. // Smaller files may be written in cache map instead of separate files.
  1826. // Also, no-store response cannot be written in persistent cache.
  1827. nsAutoCString contentType;
  1828. mChannel->GetContentType(contentType);
  1829. if (mResponseType == XMLHttpRequestResponseType::Blob) {
  1830. // mBlobStorage can be null if the channel is non-file non-cacheable
  1831. // and if the response length is zero.
  1832. MaybeCreateBlobStorage();
  1833. mBlobStorage->GetBlobWhenReady(GetOwner(), contentType, this);
  1834. waitingForBlobCreation = true;
  1835. } else {
  1836. // mBlobSet can be null if the channel is non-file non-cacheable
  1837. // and if the response length is zero.
  1838. if (!mBlobSet) {
  1839. mBlobSet = new BlobSet();
  1840. }
  1841. nsTArray<RefPtr<BlobImpl>> subImpls(mBlobSet->GetBlobImpls());
  1842. RefPtr<BlobImpl> blobImpl =
  1843. MultipartBlobImpl::Create(Move(subImpls),
  1844. NS_ConvertASCIItoUTF16(contentType),
  1845. rv);
  1846. mBlobSet = nullptr;
  1847. if (NS_WARN_IF(rv.Failed())) {
  1848. return rv.StealNSResult();
  1849. }
  1850. mResponseBlob = Blob::Create(GetOwner(), blobImpl);
  1851. }
  1852. }
  1853. NS_ASSERTION(mResponseBody.IsEmpty(), "mResponseBody should be empty");
  1854. NS_ASSERTION(mResponseText.IsEmpty(), "mResponseText should be empty");
  1855. } else if (NS_SUCCEEDED(status) &&
  1856. ((mResponseType == XMLHttpRequestResponseType::Arraybuffer &&
  1857. !mIsMappedArrayBuffer) ||
  1858. mResponseType == XMLHttpRequestResponseType::Moz_chunked_arraybuffer)) {
  1859. // set the capacity down to the actual length, to realloc back
  1860. // down to the actual size
  1861. if (!mArrayBufferBuilder.setCapacity(mArrayBufferBuilder.length())) {
  1862. // this should never happen!
  1863. status = NS_ERROR_UNEXPECTED;
  1864. }
  1865. }
  1866. nsCOMPtr<nsIChannel> channel(do_QueryInterface(request));
  1867. NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
  1868. channel->SetNotificationCallbacks(nullptr);
  1869. mNotificationCallbacks = nullptr;
  1870. mChannelEventSink = nullptr;
  1871. mProgressEventSink = nullptr;
  1872. mFlagSyncLooping = false;
  1873. // update our charset and decoder to match mResponseXML,
  1874. // before it is possibly nulled out
  1875. MatchCharsetAndDecoderToResponseDocument();
  1876. if (NS_FAILED(status)) {
  1877. // This can happen if the server is unreachable. Other possible
  1878. // reasons are that the user leaves the page or hits the ESC key.
  1879. mErrorLoad = true;
  1880. mResponseXML = nullptr;
  1881. }
  1882. // If we're uninitialized at this point, we encountered an error
  1883. // earlier and listeners have already been notified. Also we do
  1884. // not want to do this if we already completed.
  1885. if (mState == State::unsent || mState == State::done) {
  1886. return NS_OK;
  1887. }
  1888. if (!mResponseXML) {
  1889. mFlagParseBody = false;
  1890. //We postpone the 'done' until the creation of the Blob is completed.
  1891. if (!waitingForBlobCreation) {
  1892. ChangeStateToDone();
  1893. }
  1894. return NS_OK;
  1895. }
  1896. if (mIsHtml) {
  1897. NS_ASSERTION(!mFlagSyncLooping,
  1898. "We weren't supposed to support HTML parsing with XHR!");
  1899. nsCOMPtr<EventTarget> eventTarget = do_QueryInterface(mResponseXML);
  1900. EventListenerManager* manager =
  1901. eventTarget->GetOrCreateListenerManager();
  1902. manager->AddEventListenerByType(new nsXHRParseEndListener(this),
  1903. kLiteralString_DOMContentLoaded,
  1904. TrustedEventsAtSystemGroupBubble());
  1905. return NS_OK;
  1906. } else {
  1907. mFlagParseBody = false;
  1908. }
  1909. // We might have been sent non-XML data. If that was the case,
  1910. // we should null out the document member. The idea in this
  1911. // check here is that if there is no document element it is not
  1912. // an XML document. We might need a fancier check...
  1913. if (!mResponseXML->GetRootElement()) {
  1914. mErrorParsingXML = true;
  1915. mResponseXML = nullptr;
  1916. }
  1917. ChangeStateToDone();
  1918. return NS_OK;
  1919. }
  1920. void
  1921. XMLHttpRequestMainThread::OnBodyParseEnd()
  1922. {
  1923. mFlagParseBody = false;
  1924. ChangeStateToDone();
  1925. }
  1926. void
  1927. XMLHttpRequestMainThread::MatchCharsetAndDecoderToResponseDocument()
  1928. {
  1929. if (mResponseXML && mResponseCharset != mResponseXML->GetDocumentCharacterSet()) {
  1930. mResponseCharset = mResponseXML->GetDocumentCharacterSet();
  1931. TruncateResponseText();
  1932. mResponseBodyDecodedPos = 0;
  1933. mDecoder = EncodingUtils::DecoderForEncoding(mResponseCharset);
  1934. }
  1935. }
  1936. void
  1937. XMLHttpRequestMainThread::ChangeStateToDone()
  1938. {
  1939. StopProgressEventTimer();
  1940. MOZ_ASSERT(!mFlagParseBody,
  1941. "ChangeStateToDone() called before async HTML parsing is done.");
  1942. mFlagSend = false;
  1943. if (mTimeoutTimer) {
  1944. mTimeoutTimer->Cancel();
  1945. }
  1946. // Per spec, fire the last download progress event, if any,
  1947. // before readystatechange=4/done. (Note that 0-sized responses
  1948. // will have not sent a progress event yet, so one must be sent here).
  1949. if (!mFlagSynchronous &&
  1950. (!mLoadTransferred || mProgressSinceLastProgressEvent)) {
  1951. DispatchProgressEvent(this, ProgressEventType::progress,
  1952. mLoadTransferred, mLoadTotal);
  1953. mProgressSinceLastProgressEvent = false;
  1954. }
  1955. // Per spec, fire readystatechange=4/done before final error events.
  1956. ChangeState(State::done, true);
  1957. // Per spec, if we failed in the upload phase, fire a final error
  1958. // and loadend events for the upload after readystatechange=4/done.
  1959. if (!mFlagSynchronous && mUpload && !mUploadComplete) {
  1960. DispatchProgressEvent(mUpload, ProgressEventType::error, 0, -1);
  1961. }
  1962. // Per spec, fire download's load/error and loadend events after
  1963. // readystatechange=4/done (and of course all upload events).
  1964. DispatchProgressEvent(this,
  1965. mErrorLoad ? ProgressEventType::error :
  1966. ProgressEventType::load,
  1967. mErrorLoad ? 0 : mLoadTransferred,
  1968. mErrorLoad ? -1 : mLoadTotal);
  1969. if (mErrorLoad) {
  1970. // By nulling out channel here we make it so that Send() can test
  1971. // for that and throw. Also calling the various status
  1972. // methods/members will not throw.
  1973. // This matches what IE does.
  1974. mChannel = nullptr;
  1975. }
  1976. }
  1977. template<> nsresult
  1978. XMLHttpRequestMainThread::RequestBody<nsIDocument>::GetAsStream(
  1979. nsIInputStream** aResult, uint64_t* aContentLength,
  1980. nsACString& aContentType, nsACString& aCharset) const
  1981. {
  1982. nsCOMPtr<nsIDOMDocument> domdoc(do_QueryInterface(mBody));
  1983. NS_ENSURE_STATE(domdoc);
  1984. aCharset.AssignLiteral("UTF-8");
  1985. nsresult rv;
  1986. nsCOMPtr<nsIStorageStream> storStream;
  1987. rv = NS_NewStorageStream(4096, UINT32_MAX, getter_AddRefs(storStream));
  1988. NS_ENSURE_SUCCESS(rv, rv);
  1989. nsCOMPtr<nsIOutputStream> output;
  1990. rv = storStream->GetOutputStream(0, getter_AddRefs(output));
  1991. NS_ENSURE_SUCCESS(rv, rv);
  1992. if (mBody->IsHTMLDocument()) {
  1993. aContentType.AssignLiteral("text/html");
  1994. nsString serialized;
  1995. if (!nsContentUtils::SerializeNodeToMarkup(mBody, true, serialized)) {
  1996. return NS_ERROR_OUT_OF_MEMORY;
  1997. }
  1998. nsAutoCString utf8Serialized;
  1999. if (!AppendUTF16toUTF8(serialized, utf8Serialized, fallible)) {
  2000. return NS_ERROR_OUT_OF_MEMORY;
  2001. }
  2002. uint32_t written;
  2003. rv = output->Write(utf8Serialized.get(), utf8Serialized.Length(), &written);
  2004. NS_ENSURE_SUCCESS(rv, rv);
  2005. MOZ_ASSERT(written == utf8Serialized.Length());
  2006. } else {
  2007. aContentType.AssignLiteral("application/xml");
  2008. nsCOMPtr<nsIDOMSerializer> serializer =
  2009. do_CreateInstance(NS_XMLSERIALIZER_CONTRACTID, &rv);
  2010. NS_ENSURE_SUCCESS(rv, rv);
  2011. // Make sure to use the encoding we'll send
  2012. rv = serializer->SerializeToStream(domdoc, output, aCharset);
  2013. NS_ENSURE_SUCCESS(rv, rv);
  2014. }
  2015. output->Close();
  2016. uint32_t length;
  2017. rv = storStream->GetLength(&length);
  2018. NS_ENSURE_SUCCESS(rv, rv);
  2019. *aContentLength = length;
  2020. rv = storStream->NewInputStream(0, aResult);
  2021. NS_ENSURE_SUCCESS(rv, rv);
  2022. return NS_OK;
  2023. }
  2024. template<> nsresult
  2025. XMLHttpRequestMainThread::RequestBody<const nsAString>::GetAsStream(
  2026. nsIInputStream** aResult, uint64_t* aContentLength,
  2027. nsACString& aContentType, nsACString& aCharset) const
  2028. {
  2029. aContentType.AssignLiteral("text/plain");
  2030. aCharset.AssignLiteral("UTF-8");
  2031. nsAutoCString converted;
  2032. if (!AppendUTF16toUTF8(*mBody, converted, fallible)) {
  2033. return NS_ERROR_OUT_OF_MEMORY;
  2034. }
  2035. *aContentLength = converted.Length();
  2036. nsresult rv = NS_NewCStringInputStream(aResult, converted);
  2037. NS_ENSURE_SUCCESS(rv, rv);
  2038. return NS_OK;
  2039. }
  2040. template<> nsresult
  2041. XMLHttpRequestMainThread::RequestBody<nsIInputStream>::GetAsStream(
  2042. nsIInputStream** aResult, uint64_t* aContentLength,
  2043. nsACString& aContentType, nsACString& aCharset) const
  2044. {
  2045. aContentType.AssignLiteral("text/plain");
  2046. aCharset.Truncate();
  2047. nsresult rv = mBody->Available(aContentLength);
  2048. NS_ENSURE_SUCCESS(rv, rv);
  2049. nsCOMPtr<nsIInputStream> stream(mBody);
  2050. stream.forget(aResult);
  2051. return NS_OK;
  2052. }
  2053. template<> nsresult
  2054. XMLHttpRequestMainThread::RequestBody<Blob>::GetAsStream(
  2055. nsIInputStream** aResult, uint64_t* aContentLength,
  2056. nsACString& aContentType, nsACString& aCharset) const
  2057. {
  2058. return mBody->GetSendInfo(aResult, aContentLength, aContentType, aCharset);
  2059. }
  2060. template<> nsresult
  2061. XMLHttpRequestMainThread::RequestBody<FormData>::GetAsStream(
  2062. nsIInputStream** aResult, uint64_t* aContentLength,
  2063. nsACString& aContentType, nsACString& aCharset) const
  2064. {
  2065. return mBody->GetSendInfo(aResult, aContentLength, aContentType, aCharset);
  2066. }
  2067. template<> nsresult
  2068. XMLHttpRequestMainThread::RequestBody<URLSearchParams>::GetAsStream(
  2069. nsIInputStream** aResult, uint64_t* aContentLength,
  2070. nsACString& aContentType, nsACString& aCharset) const
  2071. {
  2072. return mBody->GetSendInfo(aResult, aContentLength, aContentType, aCharset);
  2073. }
  2074. template<> nsresult
  2075. XMLHttpRequestMainThread::RequestBody<nsIXHRSendable>::GetAsStream(
  2076. nsIInputStream** aResult, uint64_t* aContentLength,
  2077. nsACString& aContentType, nsACString& aCharset) const
  2078. {
  2079. return mBody->GetSendInfo(aResult, aContentLength, aContentType, aCharset);
  2080. }
  2081. static nsresult
  2082. GetBufferDataAsStream(const uint8_t* aData, uint32_t aDataLength,
  2083. nsIInputStream** aResult, uint64_t* aContentLength,
  2084. nsACString& aContentType, nsACString& aCharset)
  2085. {
  2086. aContentType.SetIsVoid(true);
  2087. aCharset.Truncate();
  2088. *aContentLength = aDataLength;
  2089. const char* data = reinterpret_cast<const char*>(aData);
  2090. nsCOMPtr<nsIInputStream> stream;
  2091. nsresult rv = NS_NewByteInputStream(getter_AddRefs(stream), data, aDataLength,
  2092. NS_ASSIGNMENT_COPY);
  2093. NS_ENSURE_SUCCESS(rv, rv);
  2094. stream.forget(aResult);
  2095. return NS_OK;
  2096. }
  2097. template<> nsresult
  2098. XMLHttpRequestMainThread::RequestBody<const ArrayBuffer>::GetAsStream(
  2099. nsIInputStream** aResult, uint64_t* aContentLength,
  2100. nsACString& aContentType, nsACString& aCharset) const
  2101. {
  2102. mBody->ComputeLengthAndData();
  2103. return GetBufferDataAsStream(mBody->Data(), mBody->Length(),
  2104. aResult, aContentLength, aContentType, aCharset);
  2105. }
  2106. template<> nsresult
  2107. XMLHttpRequestMainThread::RequestBody<const ArrayBufferView>::GetAsStream(
  2108. nsIInputStream** aResult, uint64_t* aContentLength,
  2109. nsACString& aContentType, nsACString& aCharset) const
  2110. {
  2111. mBody->ComputeLengthAndData();
  2112. return GetBufferDataAsStream(mBody->Data(), mBody->Length(),
  2113. aResult, aContentLength, aContentType, aCharset);
  2114. }
  2115. nsresult
  2116. XMLHttpRequestMainThread::CreateChannel()
  2117. {
  2118. // When we are called from JS we can find the load group for the page,
  2119. // and add ourselves to it. This way any pending requests
  2120. // will be automatically aborted if the user leaves the page.
  2121. nsCOMPtr<nsILoadGroup> loadGroup = GetLoadGroup();
  2122. nsSecurityFlags secFlags;
  2123. nsLoadFlags loadFlags = nsIRequest::LOAD_BACKGROUND |
  2124. nsIChannel::LOAD_CLASSIFY_URI;
  2125. if (nsContentUtils::IsSystemPrincipal(mPrincipal)) {
  2126. // When chrome is loading we want to make sure to sandbox any potential
  2127. // result document. We also want to allow cross-origin loads.
  2128. secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL |
  2129. nsILoadInfo::SEC_SANDBOXED;
  2130. } else if (IsSystemXHR()) {
  2131. // For pages that have appropriate permissions, we want to still allow
  2132. // cross-origin loads, but make sure that the any potential result
  2133. // documents get the same principal as the loader.
  2134. secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
  2135. nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
  2136. loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER;
  2137. } else {
  2138. // Otherwise use CORS. Again, make sure that potential result documents
  2139. // use the same principal as the loader.
  2140. secFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS |
  2141. nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
  2142. }
  2143. if (mIsAnon) {
  2144. secFlags |= nsILoadInfo::SEC_COOKIES_OMIT;
  2145. }
  2146. // Use the responsibleDocument if we have it, except for dedicated workers
  2147. // where it will be the parent document, which is not the one we want to use.
  2148. nsresult rv;
  2149. nsCOMPtr<nsIDocument> responsibleDocument = GetDocumentIfCurrent();
  2150. if (responsibleDocument && responsibleDocument->NodePrincipal() == mPrincipal) {
  2151. rv = NS_NewChannel(getter_AddRefs(mChannel),
  2152. mRequestURL,
  2153. responsibleDocument,
  2154. secFlags,
  2155. nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST,
  2156. loadGroup,
  2157. nullptr, // aCallbacks
  2158. loadFlags);
  2159. } else {
  2160. // Otherwise use the principal.
  2161. rv = NS_NewChannel(getter_AddRefs(mChannel),
  2162. mRequestURL,
  2163. mPrincipal,
  2164. secFlags,
  2165. nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST,
  2166. loadGroup,
  2167. nullptr, // aCallbacks
  2168. loadFlags);
  2169. }
  2170. NS_ENSURE_SUCCESS(rv, rv);
  2171. nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
  2172. if (httpChannel) {
  2173. rv = httpChannel->SetRequestMethod(mRequestMethod);
  2174. NS_ENSURE_SUCCESS(rv, rv);
  2175. // Set the initiator type
  2176. nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(httpChannel));
  2177. if (timedChannel) {
  2178. timedChannel->SetInitiatorType(NS_LITERAL_STRING("xmlhttprequest"));
  2179. }
  2180. }
  2181. // Using the provided principal as the triggeringPrincipal is fine, since we
  2182. // want to be able to access any of the origins that the principal has access
  2183. // to during the security checks, but we don't want a document to inherit an
  2184. // expanded principal, so in that case we need to select the principal in the
  2185. // expanded principal's whitelist that can load our URL as principalToInherit.
  2186. nsCOMPtr<nsIPrincipal> resultingDocumentPrincipal(mPrincipal);
  2187. nsCOMPtr<nsIExpandedPrincipal> ep = do_QueryInterface(mPrincipal);
  2188. if (ep) {
  2189. nsTArray<nsCOMPtr<nsIPrincipal>>* whitelist = nullptr;
  2190. ep->GetWhiteList(&whitelist);
  2191. if (!whitelist) {
  2192. return NS_ERROR_FAILURE;
  2193. }
  2194. MOZ_ASSERT(!(secFlags & nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS));
  2195. bool dataInherits = (secFlags &
  2196. (nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
  2197. nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS)) != 0;
  2198. for (const auto& principal : *whitelist) {
  2199. if (NS_SUCCEEDED(principal->CheckMayLoad(mRequestURL, false, dataInherits))) {
  2200. resultingDocumentPrincipal = principal;
  2201. break;
  2202. }
  2203. }
  2204. }
  2205. nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
  2206. rv = loadInfo->SetPrincipalToInherit(resultingDocumentPrincipal);
  2207. NS_ENSURE_SUCCESS(rv, rv);
  2208. return NS_OK;
  2209. }
  2210. nsresult
  2211. XMLHttpRequestMainThread::InitiateFetch(nsIInputStream* aUploadStream,
  2212. int64_t aUploadLength,
  2213. nsACString& aUploadContentType)
  2214. {
  2215. nsresult rv;
  2216. // nsIRequest::LOAD_BACKGROUND prevents throbber from becoming active, which
  2217. // in turn keeps STOP button from becoming active. If the consumer passed in
  2218. // a progress event handler we must load with nsIRequest::LOAD_NORMAL or
  2219. // necko won't generate any progress notifications.
  2220. if (HasListenersFor(nsGkAtoms::onprogress) ||
  2221. (mUpload && mUpload->HasListenersFor(nsGkAtoms::onprogress))) {
  2222. nsLoadFlags loadFlags;
  2223. mChannel->GetLoadFlags(&loadFlags);
  2224. loadFlags &= ~nsIRequest::LOAD_BACKGROUND;
  2225. loadFlags |= nsIRequest::LOAD_NORMAL;
  2226. mChannel->SetLoadFlags(loadFlags);
  2227. }
  2228. nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
  2229. if (httpChannel) {
  2230. // If the user hasn't overridden the Accept header, set it to */* per spec.
  2231. if (!mAuthorRequestHeaders.Has("accept")) {
  2232. mAuthorRequestHeaders.Set("accept", NS_LITERAL_CSTRING("*/*"));
  2233. }
  2234. mAuthorRequestHeaders.ApplyToChannel(httpChannel);
  2235. if (!IsSystemXHR()) {
  2236. nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner();
  2237. nsCOMPtr<nsIDocument> doc = owner ? owner->GetExtantDoc() : nullptr;
  2238. nsContentUtils::SetFetchReferrerURIWithPolicy(mPrincipal, doc,
  2239. httpChannel,
  2240. mozilla::net::RP_Default);
  2241. }
  2242. // Some extensions override the http protocol handler and provide their own
  2243. // implementation. The channels returned from that implementation don't
  2244. // always seem to implement the nsIUploadChannel2 interface, presumably
  2245. // because it's a new interface. Eventually we should remove this and simply
  2246. // require that http channels implement the new interface (see bug 529041).
  2247. nsCOMPtr<nsIUploadChannel2> uploadChannel2 = do_QueryInterface(httpChannel);
  2248. if (!uploadChannel2) {
  2249. nsCOMPtr<nsIConsoleService> consoleService =
  2250. do_GetService(NS_CONSOLESERVICE_CONTRACTID);
  2251. if (consoleService) {
  2252. consoleService->LogStringMessage(NS_LITERAL_STRING(
  2253. "Http channel implementation doesn't support nsIUploadChannel2. "
  2254. "An extension has supplied a non-functional http protocol handler. "
  2255. "This will break behavior and in future releases not work at all."
  2256. ).get());
  2257. }
  2258. }
  2259. if (aUploadStream) {
  2260. // If necessary, wrap the stream in a buffered stream so as to guarantee
  2261. // support for our upload when calling ExplicitSetUploadStream.
  2262. nsCOMPtr<nsIInputStream> bufferedStream;
  2263. if (!NS_InputStreamIsBuffered(aUploadStream)) {
  2264. rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
  2265. aUploadStream, 4096);
  2266. NS_ENSURE_SUCCESS(rv, rv);
  2267. aUploadStream = bufferedStream;
  2268. }
  2269. // We want to use a newer version of the upload channel that won't
  2270. // ignore the necessary headers for an empty Content-Type.
  2271. nsCOMPtr<nsIUploadChannel2> uploadChannel2(do_QueryInterface(httpChannel));
  2272. // This assertion will fire if buggy extensions are installed
  2273. NS_ASSERTION(uploadChannel2, "http must support nsIUploadChannel2");
  2274. if (uploadChannel2) {
  2275. uploadChannel2->ExplicitSetUploadStream(aUploadStream,
  2276. aUploadContentType,
  2277. mUploadTotal, mRequestMethod,
  2278. false);
  2279. } else {
  2280. // The http channel doesn't support the new nsIUploadChannel2.
  2281. // Emulate it as best we can using nsIUploadChannel.
  2282. if (aUploadContentType.IsEmpty()) {
  2283. aUploadContentType.AssignLiteral("application/octet-stream");
  2284. }
  2285. nsCOMPtr<nsIUploadChannel> uploadChannel =
  2286. do_QueryInterface(httpChannel);
  2287. uploadChannel->SetUploadStream(aUploadStream, aUploadContentType,
  2288. mUploadTotal);
  2289. // Reset the method to its original value
  2290. httpChannel->SetRequestMethod(mRequestMethod);
  2291. }
  2292. }
  2293. }
  2294. // Due to the chrome-only XHR.channel API, we need a hacky way to set the
  2295. // SEC_COOKIES_INCLUDE *after* the channel has been has been created, since
  2296. // .withCredentials can be called after open() is called.
  2297. // Not doing this for privileged system XHRs since those don't use CORS.
  2298. if (!IsSystemXHR() && !mIsAnon && mFlagACwithCredentials) {
  2299. nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
  2300. static_cast<net::LoadInfo*>(loadInfo.get())->SetIncludeCookiesSecFlag();
  2301. }
  2302. // Blocking gets are common enough out of XHR that we should mark
  2303. // the channel slow by default for pipeline purposes
  2304. AddLoadFlags(mChannel, nsIRequest::INHIBIT_PIPELINE);
  2305. // We never let XHR be blocked by head CSS/JS loads to avoid potential
  2306. // deadlock where server generation of CSS/JS requires an XHR signal.
  2307. nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(mChannel));
  2308. if (cos) {
  2309. cos->AddClassFlags(nsIClassOfService::Unblocked);
  2310. }
  2311. // Disable Necko-internal response timeouts.
  2312. nsCOMPtr<nsIHttpChannelInternal>
  2313. internalHttpChannel(do_QueryInterface(mChannel));
  2314. if (internalHttpChannel) {
  2315. internalHttpChannel->SetResponseTimeoutEnabled(false);
  2316. }
  2317. if (!mIsAnon) {
  2318. AddLoadFlags(mChannel, nsIChannel::LOAD_EXPLICIT_CREDENTIALS);
  2319. }
  2320. // Bypass the network cache in cases where it makes no sense:
  2321. // POST responses are always unique, and we provide no API that would
  2322. // allow our consumers to specify a "cache key" to access old POST
  2323. // responses, so they are not worth caching.
  2324. if (mRequestMethod.EqualsLiteral("POST")) {
  2325. AddLoadFlags(mChannel,
  2326. nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE |
  2327. nsIRequest::INHIBIT_CACHING);
  2328. } else {
  2329. // When we are sync loading, we need to bypass the local cache when it would
  2330. // otherwise block us waiting for exclusive access to the cache. If we don't
  2331. // do this, then we could dead lock in some cases (see bug 309424).
  2332. //
  2333. // Also don't block on the cache entry on async if it is busy - favoring parallelism
  2334. // over cache hit rate for xhr. This does not disable the cache everywhere -
  2335. // only in cases where more than one channel for the same URI is accessed
  2336. // simultanously.
  2337. AddLoadFlags(mChannel, nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY);
  2338. }
  2339. // Since we expect XML data, set the type hint accordingly
  2340. // if the channel doesn't know any content type.
  2341. // This means that we always try to parse local files as XML
  2342. // ignoring return value, as this is not critical
  2343. nsAutoCString contentType;
  2344. if (NS_FAILED(mChannel->GetContentType(contentType)) ||
  2345. contentType.IsEmpty() ||
  2346. contentType.Equals(UNKNOWN_CONTENT_TYPE)) {
  2347. mChannel->SetContentType(NS_LITERAL_CSTRING("application/xml"));
  2348. }
  2349. // Set up the preflight if needed
  2350. if (!IsSystemXHR()) {
  2351. nsTArray<nsCString> CORSUnsafeHeaders;
  2352. mAuthorRequestHeaders.GetCORSUnsafeHeaders(CORSUnsafeHeaders);
  2353. nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
  2354. loadInfo->SetCorsPreflightInfo(CORSUnsafeHeaders,
  2355. mFlagHadUploadListenersOnSend);
  2356. }
  2357. // Hook us up to listen to redirects and the like. Only do this very late
  2358. // since this creates a cycle between the channel and us. This cycle has
  2359. // to be manually broken if anything below fails.
  2360. mChannel->GetNotificationCallbacks(getter_AddRefs(mNotificationCallbacks));
  2361. mChannel->SetNotificationCallbacks(this);
  2362. if (internalHttpChannel) {
  2363. internalHttpChannel->SetBlockAuthPrompt(ShouldBlockAuthPrompt());
  2364. }
  2365. // Because of bug 682305, we can't let listener be the XHR object itself
  2366. // because JS wouldn't be able to use it. So create a listener around 'this'.
  2367. // Make sure to hold a strong reference so that we don't leak the wrapper.
  2368. nsCOMPtr<nsIStreamListener> listener = new net::nsStreamListenerWrapper(this);
  2369. // Start reading from the channel
  2370. rv = mChannel->AsyncOpen2(listener);
  2371. listener = nullptr;
  2372. if (NS_WARN_IF(NS_FAILED(rv))) {
  2373. // Drop our ref to the channel to avoid cycles. Also drop channel's
  2374. // ref to us to be extra safe.
  2375. mChannel->SetNotificationCallbacks(mNotificationCallbacks);
  2376. mChannel = nullptr;
  2377. mErrorLoad = true;
  2378. // Per spec, we throw on sync errors, but not async.
  2379. if (mFlagSynchronous) {
  2380. return NS_ERROR_DOM_NETWORK_ERR;
  2381. }
  2382. }
  2383. return NS_OK;
  2384. }
  2385. NS_IMETHODIMP
  2386. XMLHttpRequestMainThread::Send(nsIVariant* aVariant)
  2387. {
  2388. if (!aVariant) {
  2389. return SendInternal(nullptr);
  2390. }
  2391. uint16_t dataType;
  2392. nsresult rv = aVariant->GetDataType(&dataType);
  2393. NS_ENSURE_SUCCESS(rv, rv);
  2394. if (dataType == nsIDataType::VTYPE_INTERFACE ||
  2395. dataType == nsIDataType::VTYPE_INTERFACE_IS) {
  2396. nsCOMPtr<nsISupports> supports;
  2397. nsID *iid;
  2398. rv = aVariant->GetAsInterface(&iid, getter_AddRefs(supports));
  2399. NS_ENSURE_SUCCESS(rv, rv);
  2400. free(iid);
  2401. // document?
  2402. nsCOMPtr<nsIDocument> doc = do_QueryInterface(supports);
  2403. if (doc) {
  2404. RequestBody<nsIDocument> body(doc);
  2405. return SendInternal(&body);
  2406. }
  2407. // nsISupportsString?
  2408. nsCOMPtr<nsISupportsString> wstr = do_QueryInterface(supports);
  2409. if (wstr) {
  2410. nsAutoString string;
  2411. wstr->GetData(string);
  2412. RequestBody<const nsAString> body(&string);
  2413. return SendInternal(&body);
  2414. }
  2415. // nsIInputStream?
  2416. nsCOMPtr<nsIInputStream> stream = do_QueryInterface(supports);
  2417. if (stream) {
  2418. RequestBody<nsIInputStream> body(stream);
  2419. return SendInternal(&body);
  2420. }
  2421. // nsIXHRSendable?
  2422. nsCOMPtr<nsIXHRSendable> sendable = do_QueryInterface(supports);
  2423. if (sendable) {
  2424. RequestBody<nsIXHRSendable> body(sendable);
  2425. return SendInternal(&body);
  2426. }
  2427. // ArrayBuffer?
  2428. JS::RootingContext* rootingCx = RootingCx();
  2429. JS::Rooted<JS::Value> realVal(rootingCx);
  2430. nsresult rv = aVariant->GetAsJSVal(&realVal);
  2431. if (NS_SUCCEEDED(rv) && !realVal.isPrimitive()) {
  2432. JS::Rooted<JSObject*> obj(rootingCx, realVal.toObjectOrNull());
  2433. RootedTypedArray<ArrayBuffer> buf(rootingCx);
  2434. if (buf.Init(obj)) {
  2435. RequestBody<const ArrayBuffer> body(&buf);
  2436. return SendInternal(&body);
  2437. }
  2438. }
  2439. } else if (dataType == nsIDataType::VTYPE_VOID ||
  2440. dataType == nsIDataType::VTYPE_EMPTY) {
  2441. return SendInternal(nullptr);
  2442. }
  2443. char16_t* data = nullptr;
  2444. uint32_t len = 0;
  2445. rv = aVariant->GetAsWStringWithSize(&len, &data);
  2446. NS_ENSURE_SUCCESS(rv, rv);
  2447. nsString string;
  2448. string.Adopt(data, len);
  2449. RequestBody<const nsAString> body(&string);
  2450. return SendInternal(&body);
  2451. }
  2452. nsresult
  2453. XMLHttpRequestMainThread::SendInternal(const RequestBodyBase* aBody)
  2454. {
  2455. NS_ENSURE_TRUE(mPrincipal, NS_ERROR_NOT_INITIALIZED);
  2456. // Step 1
  2457. if (mState != State::opened) {
  2458. return NS_ERROR_DOM_INVALID_STATE_XHR_MUST_BE_OPENED;
  2459. }
  2460. // Step 2
  2461. if (mFlagSend) {
  2462. return NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_SENDING;
  2463. }
  2464. nsresult rv = CheckInnerWindowCorrectness();
  2465. if (NS_FAILED(rv)) {
  2466. return NS_ERROR_DOM_INVALID_STATE_XHR_HAS_INVALID_CONTEXT;
  2467. }
  2468. // If open() failed to create the channel, then throw a network error
  2469. // as per spec. We really should create the channel here in send(), but
  2470. // we have internal code relying on the channel being created in open().
  2471. if (!mChannel) {
  2472. return NS_ERROR_DOM_NETWORK_ERR;
  2473. }
  2474. // non-GET requests aren't allowed for blob.
  2475. if (IsBlobURI(mRequestURL) && !mRequestMethod.EqualsLiteral("GET")) {
  2476. return NS_ERROR_DOM_NETWORK_ERR;
  2477. }
  2478. PopulateNetworkInterfaceId();
  2479. // XXX We should probably send a warning to the JS console
  2480. // if there are no event listeners set and we are doing
  2481. // an asynchronous call.
  2482. mUploadTransferred = 0;
  2483. mUploadTotal = 0;
  2484. // By default we don't have any upload, so mark upload complete.
  2485. mUploadComplete = true;
  2486. mErrorLoad = false;
  2487. mLoadTotal = -1;
  2488. nsCOMPtr<nsIInputStream> uploadStream;
  2489. nsAutoCString uploadContentType;
  2490. nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
  2491. if (aBody && httpChannel &&
  2492. !mRequestMethod.EqualsLiteral("GET") &&
  2493. !mRequestMethod.EqualsLiteral("HEAD")) {
  2494. nsAutoCString charset;
  2495. nsAutoCString defaultContentType;
  2496. uint64_t size_u64;
  2497. rv = aBody->GetAsStream(getter_AddRefs(uploadStream),
  2498. &size_u64, defaultContentType, charset);
  2499. NS_ENSURE_SUCCESS(rv, rv);
  2500. // make sure it fits within js MAX_SAFE_INTEGER
  2501. mUploadTotal =
  2502. net::InScriptableRange(size_u64) ? static_cast<int64_t>(size_u64) : -1;
  2503. if (uploadStream) {
  2504. // If author set no Content-Type, use the default from GetAsStream().
  2505. mAuthorRequestHeaders.Get("content-type", uploadContentType);
  2506. if (uploadContentType.IsVoid()) {
  2507. uploadContentType = defaultContentType;
  2508. if (!charset.IsEmpty()) {
  2509. // If we are providing the default content type, then we also need to
  2510. // provide a charset declaration.
  2511. uploadContentType.Append(NS_LITERAL_CSTRING(";charset="));
  2512. uploadContentType.Append(charset);
  2513. }
  2514. }
  2515. // We don't want to set a charset for streams.
  2516. if (!charset.IsEmpty()) {
  2517. // Replace all case-insensitive matches of the charset in the
  2518. // content-type with the correct case.
  2519. RequestHeaders::CharsetIterator iter(uploadContentType);
  2520. const nsCaseInsensitiveCStringComparator cmp;
  2521. while (iter.Next()) {
  2522. if (!iter.Equals(charset, cmp)) {
  2523. iter.Replace(charset);
  2524. }
  2525. }
  2526. }
  2527. mUploadComplete = false;
  2528. }
  2529. }
  2530. ResetResponse();
  2531. // Check if we should enable cross-origin upload listeners.
  2532. if (mUpload && mUpload->HasListeners()) {
  2533. mFlagHadUploadListenersOnSend = true;
  2534. }
  2535. mIsMappedArrayBuffer = false;
  2536. if (mResponseType == XMLHttpRequestResponseType::Arraybuffer &&
  2537. Preferences::GetBool("dom.mapped_arraybuffer.enabled", true)) {
  2538. nsCOMPtr<nsIURI> uri;
  2539. nsAutoCString scheme;
  2540. rv = mChannel->GetURI(getter_AddRefs(uri));
  2541. if (NS_SUCCEEDED(rv)) {
  2542. uri->GetScheme(scheme);
  2543. if (scheme.LowerCaseEqualsLiteral("jar")) {
  2544. mIsMappedArrayBuffer = true;
  2545. }
  2546. }
  2547. }
  2548. rv = InitiateFetch(uploadStream, mUploadTotal, uploadContentType);
  2549. NS_ENSURE_SUCCESS(rv, rv);
  2550. // Start our timeout
  2551. mRequestSentTime = PR_Now();
  2552. StartTimeoutTimer();
  2553. mWaitingForOnStopRequest = true;
  2554. // Step 8
  2555. mFlagSend = true;
  2556. // If we're synchronous, spin an event loop here and wait
  2557. if (mFlagSynchronous) {
  2558. mFlagSyncLooping = true;
  2559. nsCOMPtr<nsIDocument> suspendedDoc;
  2560. nsCOMPtr<nsIRunnable> resumeTimeoutRunnable;
  2561. if (GetOwner()) {
  2562. if (nsCOMPtr<nsPIDOMWindowOuter> topWindow = GetOwner()->GetOuterWindow()->GetTop()) {
  2563. if (nsCOMPtr<nsPIDOMWindowInner> topInner = topWindow->GetCurrentInnerWindow()) {
  2564. suspendedDoc = topWindow->GetExtantDoc();
  2565. if (suspendedDoc) {
  2566. suspendedDoc->SuppressEventHandling(nsIDocument::eEvents);
  2567. }
  2568. topInner->Suspend();
  2569. resumeTimeoutRunnable = new nsResumeTimeoutsEvent(topInner);
  2570. }
  2571. }
  2572. }
  2573. StopProgressEventTimer();
  2574. SyncTimeoutType syncTimeoutType = MaybeStartSyncTimeoutTimer();
  2575. if (syncTimeoutType == eErrorOrExpired) {
  2576. Abort();
  2577. rv = NS_ERROR_DOM_NETWORK_ERR;
  2578. }
  2579. if (NS_SUCCEEDED(rv)) {
  2580. nsAutoSyncOperation sync(suspendedDoc);
  2581. nsIThread *thread = NS_GetCurrentThread();
  2582. while (mFlagSyncLooping) {
  2583. if (!NS_ProcessNextEvent(thread)) {
  2584. rv = NS_ERROR_UNEXPECTED;
  2585. break;
  2586. }
  2587. }
  2588. // Time expired... We should throw.
  2589. if (syncTimeoutType == eTimerStarted && !mSyncTimeoutTimer) {
  2590. rv = NS_ERROR_DOM_NETWORK_ERR;
  2591. }
  2592. CancelSyncTimeoutTimer();
  2593. }
  2594. if (suspendedDoc) {
  2595. suspendedDoc->UnsuppressEventHandlingAndFireEvents(nsIDocument::eEvents,
  2596. true);
  2597. }
  2598. if (resumeTimeoutRunnable) {
  2599. NS_DispatchToCurrentThread(resumeTimeoutRunnable);
  2600. }
  2601. } else {
  2602. // Now that we've successfully opened the channel, we can change state. Note
  2603. // that this needs to come after the AsyncOpen() and rv check, because this
  2604. // can run script that would try to restart this request, and that could end
  2605. // up doing our AsyncOpen on a null channel if the reentered AsyncOpen fails.
  2606. StopProgressEventTimer();
  2607. // Upload phase beginning; start the progress event timer if necessary.
  2608. if (mUpload && mUpload->HasListenersFor(nsGkAtoms::onprogress)) {
  2609. StartProgressEventTimer();
  2610. }
  2611. // Dispatch loadstart events
  2612. DispatchProgressEvent(this, ProgressEventType::loadstart, 0, -1);
  2613. if (mUpload && !mUploadComplete) {
  2614. DispatchProgressEvent(mUpload, ProgressEventType::loadstart,
  2615. 0, mUploadTotal);
  2616. }
  2617. }
  2618. if (!mChannel) {
  2619. // Per spec, silently fail on async request failures; throw for sync.
  2620. if (mFlagSynchronous) {
  2621. return NS_ERROR_DOM_NETWORK_ERR;
  2622. } else {
  2623. // Defer the actual sending of async events just in case listeners
  2624. // are attached after the send() method is called.
  2625. NS_DispatchToCurrentThread(
  2626. NewRunnableMethod<ProgressEventType>(this,
  2627. &XMLHttpRequestMainThread::CloseRequestWithError,
  2628. ProgressEventType::error));
  2629. return NS_OK;
  2630. }
  2631. }
  2632. return rv;
  2633. }
  2634. // http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html#dom-xmlhttprequest-setrequestheader
  2635. NS_IMETHODIMP
  2636. XMLHttpRequestMainThread::SetRequestHeader(const nsACString& aName,
  2637. const nsACString& aValue)
  2638. {
  2639. // Step 1
  2640. if (mState != State::opened) {
  2641. return NS_ERROR_DOM_INVALID_STATE_XHR_MUST_BE_OPENED;
  2642. }
  2643. // Step 2
  2644. if (mFlagSend) {
  2645. return NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_SENDING;
  2646. }
  2647. // Step 3
  2648. nsAutoCString value(aValue);
  2649. static const char kHTTPWhitespace[] = "\n\t\r ";
  2650. value.Trim(kHTTPWhitespace);
  2651. // Step 4
  2652. if (!NS_IsValidHTTPToken(aName) || !NS_IsReasonableHTTPHeaderValue(value)) {
  2653. return NS_ERROR_DOM_INVALID_HEADER_NAME;
  2654. }
  2655. // Step 5
  2656. bool isPrivilegedCaller = IsSystemXHR();
  2657. bool isForbiddenHeader = nsContentUtils::IsForbiddenRequestHeader(aName);
  2658. if (!isPrivilegedCaller && isForbiddenHeader) {
  2659. NS_ConvertUTF8toUTF16 name(aName);
  2660. const char16_t* params[] = { name.get() };
  2661. LogMessage("ForbiddenHeaderWarning", GetOwner(), params, ArrayLength(params));
  2662. return NS_OK;
  2663. }
  2664. // Step 6.1
  2665. // Skipping for now, as normalizing the case of header names may not be
  2666. // web-compatible. See bug 1285036.
  2667. // Step 6.2-6.3
  2668. // Gecko-specific: invalid headers can be set by privileged
  2669. // callers, but will not merge.
  2670. if (isPrivilegedCaller && isForbiddenHeader) {
  2671. mAuthorRequestHeaders.Set(aName, value);
  2672. } else {
  2673. mAuthorRequestHeaders.MergeOrSet(aName, value);
  2674. }
  2675. return NS_OK;
  2676. }
  2677. NS_IMETHODIMP
  2678. XMLHttpRequestMainThread::GetTimeout(uint32_t *aTimeout)
  2679. {
  2680. *aTimeout = Timeout();
  2681. return NS_OK;
  2682. }
  2683. NS_IMETHODIMP
  2684. XMLHttpRequestMainThread::SetTimeout(uint32_t aTimeout)
  2685. {
  2686. ErrorResult rv;
  2687. SetTimeout(aTimeout, rv);
  2688. return rv.StealNSResult();
  2689. }
  2690. void
  2691. XMLHttpRequestMainThread::SetTimeout(uint32_t aTimeout, ErrorResult& aRv)
  2692. {
  2693. if (mFlagSynchronous && mState != State::unsent && HasOrHasHadOwner()) {
  2694. /* Timeout is not supported for synchronous requests with an owning window,
  2695. per XHR2 spec. */
  2696. LogMessage("TimeoutSyncXHRWarning", GetOwner());
  2697. aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_XHR_TIMEOUT_AND_RESPONSETYPE_UNSUPPORTED_FOR_SYNC);
  2698. return;
  2699. }
  2700. mTimeoutMilliseconds = aTimeout;
  2701. if (mRequestSentTime) {
  2702. StartTimeoutTimer();
  2703. }
  2704. }
  2705. void
  2706. XMLHttpRequestMainThread::StartTimeoutTimer()
  2707. {
  2708. MOZ_ASSERT(mRequestSentTime,
  2709. "StartTimeoutTimer mustn't be called before the request was sent!");
  2710. if (mState == State::done) {
  2711. // do nothing!
  2712. return;
  2713. }
  2714. if (mTimeoutTimer) {
  2715. mTimeoutTimer->Cancel();
  2716. }
  2717. if (!mTimeoutMilliseconds) {
  2718. return;
  2719. }
  2720. if (!mTimeoutTimer) {
  2721. mTimeoutTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
  2722. }
  2723. uint32_t elapsed =
  2724. (uint32_t)((PR_Now() - mRequestSentTime) / PR_USEC_PER_MSEC);
  2725. mTimeoutTimer->InitWithCallback(
  2726. this,
  2727. mTimeoutMilliseconds > elapsed ? mTimeoutMilliseconds - elapsed : 0,
  2728. nsITimer::TYPE_ONE_SHOT
  2729. );
  2730. }
  2731. NS_IMETHODIMP
  2732. XMLHttpRequestMainThread::GetReadyState(uint16_t *aState)
  2733. {
  2734. *aState = ReadyState();
  2735. return NS_OK;
  2736. }
  2737. uint16_t
  2738. XMLHttpRequestMainThread::ReadyState() const
  2739. {
  2740. // Translate some of our internal states for external consumers
  2741. switch(mState) {
  2742. case State::unsent:
  2743. return UNSENT;
  2744. case State::opened:
  2745. return OPENED;
  2746. case State::headers_received:
  2747. return HEADERS_RECEIVED;
  2748. case State::loading:
  2749. return LOADING;
  2750. case State::done:
  2751. return DONE;
  2752. default:
  2753. MOZ_CRASH("Unknown state");
  2754. }
  2755. return 0;
  2756. }
  2757. void XMLHttpRequestMainThread::OverrideMimeType(const nsAString& aMimeType, ErrorResult& aRv)
  2758. {
  2759. if (mState == State::loading || mState == State::done) {
  2760. ResetResponse();
  2761. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_LOADING_OR_DONE);
  2762. return;
  2763. }
  2764. mOverrideMimeType = aMimeType;
  2765. }
  2766. NS_IMETHODIMP
  2767. XMLHttpRequestMainThread::SlowOverrideMimeType(const nsAString& aMimeType)
  2768. {
  2769. ErrorResult aRv;
  2770. OverrideMimeType(aMimeType, aRv);
  2771. return aRv.StealNSResult();
  2772. }
  2773. NS_IMETHODIMP
  2774. XMLHttpRequestMainThread::GetMozBackgroundRequest(bool *_retval)
  2775. {
  2776. *_retval = MozBackgroundRequest();
  2777. return NS_OK;
  2778. }
  2779. bool
  2780. XMLHttpRequestMainThread::MozBackgroundRequest() const
  2781. {
  2782. return mFlagBackgroundRequest;
  2783. }
  2784. NS_IMETHODIMP
  2785. XMLHttpRequestMainThread::SetMozBackgroundRequest(bool aMozBackgroundRequest)
  2786. {
  2787. if (!IsSystemXHR()) {
  2788. return NS_ERROR_DOM_SECURITY_ERR;
  2789. }
  2790. if (mState != State::unsent) {
  2791. // Can't change this while we're in the middle of something.
  2792. return NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_SENDING;
  2793. }
  2794. mFlagBackgroundRequest = aMozBackgroundRequest;
  2795. return NS_OK;
  2796. }
  2797. void
  2798. XMLHttpRequestMainThread::SetMozBackgroundRequest(bool aMozBackgroundRequest,
  2799. ErrorResult& aRv)
  2800. {
  2801. // No errors for this webIDL method on main-thread.
  2802. SetMozBackgroundRequest(aMozBackgroundRequest);
  2803. }
  2804. NS_IMETHODIMP
  2805. XMLHttpRequestMainThread::GetWithCredentials(bool *_retval)
  2806. {
  2807. *_retval = WithCredentials();
  2808. return NS_OK;
  2809. }
  2810. bool
  2811. XMLHttpRequestMainThread::WithCredentials() const
  2812. {
  2813. return mFlagACwithCredentials;
  2814. }
  2815. NS_IMETHODIMP
  2816. XMLHttpRequestMainThread::SetWithCredentials(bool aWithCredentials)
  2817. {
  2818. ErrorResult rv;
  2819. SetWithCredentials(aWithCredentials, rv);
  2820. return rv.StealNSResult();
  2821. }
  2822. void
  2823. XMLHttpRequestMainThread::SetWithCredentials(bool aWithCredentials, ErrorResult& aRv)
  2824. {
  2825. // Return error if we're already processing a request. Note that we can't use
  2826. // ReadyState() here, because it can't differentiate between "opened" and
  2827. // "sent", so we use mState directly.
  2828. if ((mState != State::unsent && mState != State::opened) ||
  2829. mFlagSend || mIsAnon) {
  2830. aRv.Throw(NS_ERROR_DOM_INVALID_STATE_XHR_MUST_NOT_BE_SENDING);
  2831. return;
  2832. }
  2833. mFlagACwithCredentials = aWithCredentials;
  2834. }
  2835. nsresult
  2836. XMLHttpRequestMainThread::ChangeState(State aState, bool aBroadcast)
  2837. {
  2838. mState = aState;
  2839. nsresult rv = NS_OK;
  2840. if (aState != State::headers_received && aState != State::loading) {
  2841. StopProgressEventTimer();
  2842. }
  2843. if (aBroadcast && (!mFlagSynchronous ||
  2844. aState == State::opened ||
  2845. aState == State::done)) {
  2846. rv = FireReadystatechangeEvent();
  2847. }
  2848. return rv;
  2849. }
  2850. /////////////////////////////////////////////////////
  2851. // nsIChannelEventSink methods:
  2852. //
  2853. NS_IMETHODIMP
  2854. XMLHttpRequestMainThread::AsyncOnChannelRedirect(nsIChannel *aOldChannel,
  2855. nsIChannel *aNewChannel,
  2856. uint32_t aFlags,
  2857. nsIAsyncVerifyRedirectCallback *callback)
  2858. {
  2859. NS_PRECONDITION(aNewChannel, "Redirect without a channel?");
  2860. // Prepare to receive callback
  2861. mRedirectCallback = callback;
  2862. mNewRedirectChannel = aNewChannel;
  2863. if (mChannelEventSink) {
  2864. nsCOMPtr<nsIAsyncVerifyRedirectCallback> fwd =
  2865. EnsureXPCOMifier();
  2866. nsresult rv = mChannelEventSink->AsyncOnChannelRedirect(aOldChannel,
  2867. aNewChannel,
  2868. aFlags, fwd);
  2869. if (NS_FAILED(rv)) {
  2870. mRedirectCallback = nullptr;
  2871. mNewRedirectChannel = nullptr;
  2872. }
  2873. return rv;
  2874. }
  2875. OnRedirectVerifyCallback(NS_OK);
  2876. return NS_OK;
  2877. }
  2878. nsresult
  2879. XMLHttpRequestMainThread::OnRedirectVerifyCallback(nsresult result)
  2880. {
  2881. NS_ASSERTION(mRedirectCallback, "mRedirectCallback not set in callback");
  2882. NS_ASSERTION(mNewRedirectChannel, "mNewRedirectChannel not set in callback");
  2883. if (NS_SUCCEEDED(result)) {
  2884. mChannel = mNewRedirectChannel;
  2885. nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(mChannel));
  2886. if (httpChannel) {
  2887. // Ensure all original headers are duplicated for the new channel (bug #553888)
  2888. mAuthorRequestHeaders.ApplyToChannel(httpChannel);
  2889. }
  2890. } else {
  2891. mErrorLoad = true;
  2892. }
  2893. mNewRedirectChannel = nullptr;
  2894. mRedirectCallback->OnRedirectVerifyCallback(result);
  2895. mRedirectCallback = nullptr;
  2896. // It's important that we return success here. If we return the result code
  2897. // that we were passed, JavaScript callers who cancel the redirect will wind
  2898. // up throwing an exception in the process.
  2899. return NS_OK;
  2900. }
  2901. /////////////////////////////////////////////////////
  2902. // nsIProgressEventSink methods:
  2903. //
  2904. NS_IMETHODIMP
  2905. XMLHttpRequestMainThread::OnProgress(nsIRequest *aRequest, nsISupports *aContext, int64_t aProgress, int64_t aProgressMax)
  2906. {
  2907. // When uploading, OnProgress reports also headers in aProgress and aProgressMax.
  2908. // So, try to remove the headers, if possible.
  2909. bool lengthComputable = (aProgressMax != -1);
  2910. if (InUploadPhase()) {
  2911. int64_t loaded = aProgress;
  2912. if (lengthComputable) {
  2913. int64_t headerSize = aProgressMax - mUploadTotal;
  2914. loaded -= headerSize;
  2915. }
  2916. mUploadTransferred = loaded;
  2917. mProgressSinceLastProgressEvent = true;
  2918. if (!mFlagSynchronous && !mProgressTimerIsActive) {
  2919. StartProgressEventTimer();
  2920. }
  2921. } else {
  2922. mLoadTotal = aProgressMax;
  2923. mLoadTransferred = aProgress;
  2924. // OnDataAvailable() handles mProgressSinceLastProgressEvent
  2925. // for the download phase.
  2926. }
  2927. if (mProgressEventSink) {
  2928. mProgressEventSink->OnProgress(aRequest, aContext, aProgress,
  2929. aProgressMax);
  2930. }
  2931. return NS_OK;
  2932. }
  2933. NS_IMETHODIMP
  2934. XMLHttpRequestMainThread::OnStatus(nsIRequest *aRequest, nsISupports *aContext, nsresult aStatus, const char16_t *aStatusArg)
  2935. {
  2936. if (mProgressEventSink) {
  2937. mProgressEventSink->OnStatus(aRequest, aContext, aStatus, aStatusArg);
  2938. }
  2939. return NS_OK;
  2940. }
  2941. bool
  2942. XMLHttpRequestMainThread::AllowUploadProgress()
  2943. {
  2944. return !IsCrossSiteCORSRequest() ||
  2945. mFlagHadUploadListenersOnSend;
  2946. }
  2947. /////////////////////////////////////////////////////
  2948. // nsIInterfaceRequestor methods:
  2949. //
  2950. NS_IMETHODIMP
  2951. XMLHttpRequestMainThread::GetInterface(const nsIID & aIID, void **aResult)
  2952. {
  2953. nsresult rv;
  2954. // Make sure to return ourselves for the channel event sink interface and
  2955. // progress event sink interface, no matter what. We can forward these to
  2956. // mNotificationCallbacks if it wants to get notifications for them. But we
  2957. // need to see these notifications for proper functioning.
  2958. if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
  2959. mChannelEventSink = do_GetInterface(mNotificationCallbacks);
  2960. *aResult = static_cast<nsIChannelEventSink*>(EnsureXPCOMifier().take());
  2961. return NS_OK;
  2962. } else if (aIID.Equals(NS_GET_IID(nsIProgressEventSink))) {
  2963. mProgressEventSink = do_GetInterface(mNotificationCallbacks);
  2964. *aResult = static_cast<nsIProgressEventSink*>(EnsureXPCOMifier().take());
  2965. return NS_OK;
  2966. }
  2967. // Now give mNotificationCallbacks (if non-null) a chance to return the
  2968. // desired interface.
  2969. if (mNotificationCallbacks) {
  2970. rv = mNotificationCallbacks->GetInterface(aIID, aResult);
  2971. if (NS_SUCCEEDED(rv)) {
  2972. NS_ASSERTION(*aResult, "Lying nsIInterfaceRequestor implementation!");
  2973. return rv;
  2974. }
  2975. }
  2976. if (mFlagBackgroundRequest) {
  2977. nsCOMPtr<nsIInterfaceRequestor> badCertHandler(do_CreateInstance(NS_BADCERTHANDLER_CONTRACTID, &rv));
  2978. // Ignore failure to get component, we may not have all its dependencies
  2979. // available
  2980. if (NS_SUCCEEDED(rv)) {
  2981. rv = badCertHandler->GetInterface(aIID, aResult);
  2982. if (NS_SUCCEEDED(rv))
  2983. return rv;
  2984. }
  2985. }
  2986. else if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) ||
  2987. aIID.Equals(NS_GET_IID(nsIAuthPrompt2))) {
  2988. nsCOMPtr<nsIPromptFactory> wwatch =
  2989. do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv);
  2990. NS_ENSURE_SUCCESS(rv, rv);
  2991. // Get the an auth prompter for our window so that the parenting
  2992. // of the dialogs works as it should when using tabs.
  2993. nsCOMPtr<nsPIDOMWindowOuter> window;
  2994. if (GetOwner()) {
  2995. window = GetOwner()->GetOuterWindow();
  2996. }
  2997. return wwatch->GetPrompt(window, aIID,
  2998. reinterpret_cast<void**>(aResult));
  2999. }
  3000. // Now check for the various XHR non-DOM interfaces, except
  3001. // nsIProgressEventSink and nsIChannelEventSink which we already
  3002. // handled above.
  3003. else if (aIID.Equals(NS_GET_IID(nsIStreamListener))) {
  3004. *aResult = static_cast<nsIStreamListener*>(EnsureXPCOMifier().take());
  3005. return NS_OK;
  3006. }
  3007. else if (aIID.Equals(NS_GET_IID(nsIRequestObserver))) {
  3008. *aResult = static_cast<nsIRequestObserver*>(EnsureXPCOMifier().take());
  3009. return NS_OK;
  3010. }
  3011. else if (aIID.Equals(NS_GET_IID(nsITimerCallback))) {
  3012. *aResult = static_cast<nsITimerCallback*>(EnsureXPCOMifier().take());
  3013. return NS_OK;
  3014. }
  3015. return QueryInterface(aIID, aResult);
  3016. }
  3017. void
  3018. XMLHttpRequestMainThread::GetInterface(JSContext* aCx, nsIJSID* aIID,
  3019. JS::MutableHandle<JS::Value> aRetval,
  3020. ErrorResult& aRv)
  3021. {
  3022. dom::GetInterface(aCx, this, aIID, aRetval, aRv);
  3023. }
  3024. XMLHttpRequestUpload*
  3025. XMLHttpRequestMainThread::GetUpload(ErrorResult& aRv)
  3026. {
  3027. if (!mUpload) {
  3028. mUpload = new XMLHttpRequestUpload(this);
  3029. }
  3030. return mUpload;
  3031. }
  3032. NS_IMETHODIMP
  3033. XMLHttpRequestMainThread::GetUpload(nsIXMLHttpRequestUpload** aUpload)
  3034. {
  3035. ErrorResult rv;
  3036. RefPtr<XMLHttpRequestUpload> upload = GetUpload(rv);
  3037. upload.forget(aUpload);
  3038. return rv.StealNSResult();
  3039. }
  3040. bool
  3041. XMLHttpRequestMainThread::MozAnon() const
  3042. {
  3043. return mIsAnon;
  3044. }
  3045. NS_IMETHODIMP
  3046. XMLHttpRequestMainThread::GetMozAnon(bool* aAnon)
  3047. {
  3048. *aAnon = MozAnon();
  3049. return NS_OK;
  3050. }
  3051. bool
  3052. XMLHttpRequestMainThread::MozSystem() const
  3053. {
  3054. return IsSystemXHR();
  3055. }
  3056. NS_IMETHODIMP
  3057. XMLHttpRequestMainThread::GetMozSystem(bool* aSystem)
  3058. {
  3059. *aSystem = MozSystem();
  3060. return NS_OK;
  3061. }
  3062. void
  3063. XMLHttpRequestMainThread::HandleTimeoutCallback()
  3064. {
  3065. if (mState == State::done) {
  3066. NS_NOTREACHED("XMLHttpRequestMainThread::HandleTimeoutCallback with completed request");
  3067. // do nothing!
  3068. return;
  3069. }
  3070. mFlagTimedOut = true;
  3071. CloseRequestWithError(ProgressEventType::timeout);
  3072. }
  3073. NS_IMETHODIMP
  3074. XMLHttpRequestMainThread::Notify(nsITimer* aTimer)
  3075. {
  3076. if (mProgressNotifier == aTimer) {
  3077. HandleProgressTimerCallback();
  3078. return NS_OK;
  3079. }
  3080. if (mTimeoutTimer == aTimer) {
  3081. HandleTimeoutCallback();
  3082. return NS_OK;
  3083. }
  3084. if (mSyncTimeoutTimer == aTimer) {
  3085. HandleSyncTimeoutTimer();
  3086. return NS_OK;
  3087. }
  3088. // Just in case some JS user wants to QI to nsITimerCallback and play with us...
  3089. NS_WARNING("Unexpected timer!");
  3090. return NS_ERROR_INVALID_POINTER;
  3091. }
  3092. void
  3093. XMLHttpRequestMainThread::HandleProgressTimerCallback()
  3094. {
  3095. // Don't fire the progress event if mLoadTotal is 0, see XHR spec step 6.1
  3096. if (!mLoadTotal && mLoadTransferred) {
  3097. return;
  3098. }
  3099. mProgressTimerIsActive = false;
  3100. if (!mProgressSinceLastProgressEvent || mErrorLoad) {
  3101. return;
  3102. }
  3103. if (InUploadPhase()) {
  3104. if (mUpload && !mUploadComplete) {
  3105. DispatchProgressEvent(mUpload, ProgressEventType::progress,
  3106. mUploadTransferred, mUploadTotal);
  3107. }
  3108. } else {
  3109. FireReadystatechangeEvent();
  3110. DispatchProgressEvent(this, ProgressEventType::progress,
  3111. mLoadTransferred, mLoadTotal);
  3112. }
  3113. mProgressSinceLastProgressEvent = false;
  3114. StartProgressEventTimer();
  3115. }
  3116. void
  3117. XMLHttpRequestMainThread::StopProgressEventTimer()
  3118. {
  3119. if (mProgressNotifier) {
  3120. mProgressTimerIsActive = false;
  3121. mProgressNotifier->Cancel();
  3122. }
  3123. }
  3124. void
  3125. XMLHttpRequestMainThread::StartProgressEventTimer()
  3126. {
  3127. if (!mProgressNotifier) {
  3128. mProgressNotifier = do_CreateInstance(NS_TIMER_CONTRACTID);
  3129. }
  3130. if (mProgressNotifier) {
  3131. mProgressTimerIsActive = true;
  3132. mProgressNotifier->Cancel();
  3133. mProgressNotifier->InitWithCallback(this, NS_PROGRESS_EVENT_INTERVAL,
  3134. nsITimer::TYPE_ONE_SHOT);
  3135. }
  3136. }
  3137. XMLHttpRequestMainThread::SyncTimeoutType
  3138. XMLHttpRequestMainThread::MaybeStartSyncTimeoutTimer()
  3139. {
  3140. MOZ_ASSERT(mFlagSynchronous);
  3141. nsIDocument* doc = GetDocumentIfCurrent();
  3142. if (!doc || !doc->GetPageUnloadingEventTimeStamp()) {
  3143. return eNoTimerNeeded;
  3144. }
  3145. // If we are in a beforeunload or a unload event, we must force a timeout.
  3146. TimeDuration diff = (TimeStamp::NowLoRes() - doc->GetPageUnloadingEventTimeStamp());
  3147. if (diff.ToMilliseconds() > MAX_SYNC_TIMEOUT_WHEN_UNLOADING) {
  3148. return eErrorOrExpired;
  3149. }
  3150. mSyncTimeoutTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
  3151. if (!mSyncTimeoutTimer) {
  3152. return eErrorOrExpired;
  3153. }
  3154. uint32_t timeout = MAX_SYNC_TIMEOUT_WHEN_UNLOADING - diff.ToMilliseconds();
  3155. nsresult rv = mSyncTimeoutTimer->InitWithCallback(this, timeout,
  3156. nsITimer::TYPE_ONE_SHOT);
  3157. return NS_FAILED(rv) ? eErrorOrExpired : eTimerStarted;
  3158. }
  3159. void
  3160. XMLHttpRequestMainThread::HandleSyncTimeoutTimer()
  3161. {
  3162. MOZ_ASSERT(mSyncTimeoutTimer);
  3163. MOZ_ASSERT(mFlagSyncLooping);
  3164. CancelSyncTimeoutTimer();
  3165. Abort();
  3166. }
  3167. void
  3168. XMLHttpRequestMainThread::CancelSyncTimeoutTimer()
  3169. {
  3170. if (mSyncTimeoutTimer) {
  3171. mSyncTimeoutTimer->Cancel();
  3172. mSyncTimeoutTimer = nullptr;
  3173. }
  3174. }
  3175. already_AddRefed<nsXMLHttpRequestXPCOMifier>
  3176. XMLHttpRequestMainThread::EnsureXPCOMifier()
  3177. {
  3178. if (!mXPCOMifier) {
  3179. mXPCOMifier = new nsXMLHttpRequestXPCOMifier(this);
  3180. }
  3181. RefPtr<nsXMLHttpRequestXPCOMifier> newRef(mXPCOMifier);
  3182. return newRef.forget();
  3183. }
  3184. bool
  3185. XMLHttpRequestMainThread::ShouldBlockAuthPrompt()
  3186. {
  3187. // Verify that it's ok to prompt for credentials here, per spec
  3188. // http://xhr.spec.whatwg.org/#the-send%28%29-method
  3189. if (mAuthorRequestHeaders.Has("authorization")) {
  3190. return true;
  3191. }
  3192. nsCOMPtr<nsIURI> uri;
  3193. nsresult rv = mChannel->GetURI(getter_AddRefs(uri));
  3194. if (NS_WARN_IF(NS_FAILED(rv))) {
  3195. return false;
  3196. }
  3197. // Also skip if a username and/or password is provided in the URI.
  3198. nsCString username;
  3199. rv = uri->GetUsername(username);
  3200. if (NS_WARN_IF(NS_FAILED(rv))) {
  3201. return false;
  3202. }
  3203. nsCString password;
  3204. rv = uri->GetPassword(password);
  3205. if (NS_WARN_IF(NS_FAILED(rv))) {
  3206. return false;
  3207. }
  3208. if (!username.IsEmpty() || !password.IsEmpty()) {
  3209. return true;
  3210. }
  3211. return false;
  3212. }
  3213. void
  3214. XMLHttpRequestMainThread::TruncateResponseText()
  3215. {
  3216. mResponseText.Truncate();
  3217. XMLHttpRequestBinding::ClearCachedResponseTextValue(this);
  3218. }
  3219. NS_IMPL_ISUPPORTS(XMLHttpRequestMainThread::nsHeaderVisitor, nsIHttpHeaderVisitor)
  3220. NS_IMETHODIMP XMLHttpRequestMainThread::
  3221. nsHeaderVisitor::VisitHeader(const nsACString &header, const nsACString &value)
  3222. {
  3223. if (mXHR.IsSafeHeader(header, mHttpChannel)) {
  3224. mHeaders.Append(header);
  3225. mHeaders.AppendLiteral(": ");
  3226. mHeaders.Append(value);
  3227. mHeaders.AppendLiteral("\r\n");
  3228. }
  3229. return NS_OK;
  3230. }
  3231. void
  3232. XMLHttpRequestMainThread::MaybeCreateBlobStorage()
  3233. {
  3234. MOZ_ASSERT(mResponseType == XMLHttpRequestResponseType::Blob);
  3235. if (mBlobStorage) {
  3236. return;
  3237. }
  3238. MutableBlobStorage::MutableBlobStorageType storageType =
  3239. BasePrincipal::Cast(mPrincipal)->PrivateBrowsingId() == 0
  3240. ? MutableBlobStorage::eCouldBeInTemporaryFile
  3241. : MutableBlobStorage::eOnlyInMemory;
  3242. mBlobStorage = new MutableBlobStorage(storageType);
  3243. }
  3244. void
  3245. XMLHttpRequestMainThread::BlobStoreCompleted(MutableBlobStorage* aBlobStorage,
  3246. Blob* aBlob, nsresult aRv)
  3247. {
  3248. // Ok, the state is changed...
  3249. if (mBlobStorage != aBlobStorage || NS_FAILED(aRv)) {
  3250. return;
  3251. }
  3252. MOZ_ASSERT(mState != State::done);
  3253. mResponseBlob = aBlob;
  3254. mBlobStorage = nullptr;
  3255. ChangeStateToDone();
  3256. }
  3257. // nsXMLHttpRequestXPCOMifier implementation
  3258. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsXMLHttpRequestXPCOMifier)
  3259. NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
  3260. NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
  3261. NS_INTERFACE_MAP_ENTRY(nsIChannelEventSink)
  3262. NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
  3263. NS_INTERFACE_MAP_ENTRY(nsIProgressEventSink)
  3264. NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor)
  3265. NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
  3266. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStreamListener)
  3267. NS_INTERFACE_MAP_END
  3268. NS_IMPL_CYCLE_COLLECTING_ADDREF(nsXMLHttpRequestXPCOMifier)
  3269. NS_IMPL_CYCLE_COLLECTING_RELEASE(nsXMLHttpRequestXPCOMifier)
  3270. // Can't NS_IMPL_CYCLE_COLLECTION( because mXHR has ambiguous
  3271. // inheritance from nsISupports.
  3272. NS_IMPL_CYCLE_COLLECTION_CLASS(nsXMLHttpRequestXPCOMifier)
  3273. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsXMLHttpRequestXPCOMifier)
  3274. if (tmp->mXHR) {
  3275. tmp->mXHR->mXPCOMifier = nullptr;
  3276. }
  3277. NS_IMPL_CYCLE_COLLECTION_UNLINK(mXHR)
  3278. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  3279. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsXMLHttpRequestXPCOMifier)
  3280. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mXHR)
  3281. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  3282. NS_IMETHODIMP
  3283. nsXMLHttpRequestXPCOMifier::GetInterface(const nsIID & aIID, void **aResult)
  3284. {
  3285. // Return ourselves for the things we implement (except
  3286. // nsIInterfaceRequestor) and the XHR for the rest.
  3287. if (!aIID.Equals(NS_GET_IID(nsIInterfaceRequestor))) {
  3288. nsresult rv = QueryInterface(aIID, aResult);
  3289. if (NS_SUCCEEDED(rv)) {
  3290. return rv;
  3291. }
  3292. }
  3293. return mXHR->GetInterface(aIID, aResult);
  3294. }
  3295. ArrayBufferBuilder::ArrayBufferBuilder()
  3296. : mDataPtr(nullptr),
  3297. mCapacity(0),
  3298. mLength(0),
  3299. mMapPtr(nullptr)
  3300. {
  3301. }
  3302. ArrayBufferBuilder::~ArrayBufferBuilder()
  3303. {
  3304. reset();
  3305. }
  3306. void
  3307. ArrayBufferBuilder::reset()
  3308. {
  3309. if (mDataPtr) {
  3310. JS_free(nullptr, mDataPtr);
  3311. }
  3312. if (mMapPtr) {
  3313. JS_ReleaseMappedArrayBufferContents(mMapPtr, mLength);
  3314. mMapPtr = nullptr;
  3315. }
  3316. mDataPtr = nullptr;
  3317. mCapacity = mLength = 0;
  3318. }
  3319. bool
  3320. ArrayBufferBuilder::setCapacity(uint32_t aNewCap)
  3321. {
  3322. MOZ_ASSERT(!mMapPtr);
  3323. // To ensure that realloc won't free mDataPtr, use a size of 1
  3324. // instead of 0.
  3325. uint8_t* newdata = (uint8_t *) js_realloc(mDataPtr, aNewCap ? aNewCap : 1);
  3326. if (!newdata) {
  3327. return false;
  3328. }
  3329. if (aNewCap > mCapacity) {
  3330. memset(newdata + mCapacity, 0, aNewCap - mCapacity);
  3331. }
  3332. mDataPtr = newdata;
  3333. mCapacity = aNewCap;
  3334. if (mLength > aNewCap) {
  3335. mLength = aNewCap;
  3336. }
  3337. return true;
  3338. }
  3339. bool
  3340. ArrayBufferBuilder::append(const uint8_t *aNewData, uint32_t aDataLen,
  3341. uint32_t aMaxGrowth)
  3342. {
  3343. MOZ_ASSERT(!mMapPtr);
  3344. CheckedUint32 neededCapacity = mLength;
  3345. neededCapacity += aDataLen;
  3346. if (!neededCapacity.isValid()) {
  3347. return false;
  3348. }
  3349. if (mLength + aDataLen > mCapacity) {
  3350. CheckedUint32 newcap = mCapacity;
  3351. // Double while under aMaxGrowth or if not specified.
  3352. if (!aMaxGrowth || mCapacity < aMaxGrowth) {
  3353. newcap *= 2;
  3354. } else {
  3355. newcap += aMaxGrowth;
  3356. }
  3357. if (!newcap.isValid()) {
  3358. return false;
  3359. }
  3360. // But make sure there's always enough to satisfy our request.
  3361. if (newcap.value() < neededCapacity.value()) {
  3362. newcap = neededCapacity;
  3363. }
  3364. if (!setCapacity(newcap.value())) {
  3365. return false;
  3366. }
  3367. }
  3368. // Assert that the region isn't overlapping so we can memcpy.
  3369. MOZ_ASSERT(!areOverlappingRegions(aNewData, aDataLen, mDataPtr + mLength,
  3370. aDataLen));
  3371. memcpy(mDataPtr + mLength, aNewData, aDataLen);
  3372. mLength += aDataLen;
  3373. return true;
  3374. }
  3375. JSObject*
  3376. ArrayBufferBuilder::getArrayBuffer(JSContext* aCx)
  3377. {
  3378. if (mMapPtr) {
  3379. JSObject* obj = JS_NewMappedArrayBufferWithContents(aCx, mLength, mMapPtr);
  3380. if (!obj) {
  3381. JS_ReleaseMappedArrayBufferContents(mMapPtr, mLength);
  3382. }
  3383. mMapPtr = nullptr;
  3384. // The memory-mapped contents will be released when the ArrayBuffer becomes
  3385. // detached or is GC'd.
  3386. return obj;
  3387. }
  3388. // we need to check for mLength == 0, because nothing may have been
  3389. // added
  3390. if (mCapacity > mLength || mLength == 0) {
  3391. if (!setCapacity(mLength)) {
  3392. return nullptr;
  3393. }
  3394. }
  3395. JSObject* obj = JS_NewArrayBufferWithContents(aCx, mLength, mDataPtr);
  3396. mLength = mCapacity = 0;
  3397. if (!obj) {
  3398. js_free(mDataPtr);
  3399. }
  3400. mDataPtr = nullptr;
  3401. return obj;
  3402. }
  3403. nsresult
  3404. ArrayBufferBuilder::mapToFileInPackage(const nsCString& aFile,
  3405. nsIFile* aJarFile)
  3406. {
  3407. nsresult rv;
  3408. // Open Jar file to get related attributes of target file.
  3409. RefPtr<nsZipArchive> zip = new nsZipArchive();
  3410. rv = zip->OpenArchive(aJarFile);
  3411. if (NS_FAILED(rv)) {
  3412. return rv;
  3413. }
  3414. nsZipItem* zipItem = zip->GetItem(aFile.get());
  3415. if (!zipItem) {
  3416. return NS_ERROR_FILE_TARGET_DOES_NOT_EXIST;
  3417. }
  3418. // If file was added to the package as stored(uncompressed), map to the
  3419. // offset of file in zip package.
  3420. if (!zipItem->Compression()) {
  3421. uint32_t offset = zip->GetDataOffset(zipItem);
  3422. uint32_t size = zipItem->RealSize();
  3423. mozilla::AutoFDClose pr_fd;
  3424. rv = aJarFile->OpenNSPRFileDesc(PR_RDONLY, 0, &pr_fd.rwget());
  3425. if (NS_FAILED(rv)) {
  3426. return rv;
  3427. }
  3428. mMapPtr = JS_CreateMappedArrayBufferContents(PR_FileDesc2NativeHandle(pr_fd),
  3429. offset, size);
  3430. if (mMapPtr) {
  3431. mLength = size;
  3432. return NS_OK;
  3433. }
  3434. }
  3435. return NS_ERROR_FAILURE;
  3436. }
  3437. /* static */ bool
  3438. ArrayBufferBuilder::areOverlappingRegions(const uint8_t* aStart1,
  3439. uint32_t aLength1,
  3440. const uint8_t* aStart2,
  3441. uint32_t aLength2)
  3442. {
  3443. const uint8_t* end1 = aStart1 + aLength1;
  3444. const uint8_t* end2 = aStart2 + aLength2;
  3445. const uint8_t* max_start = aStart1 > aStart2 ? aStart1 : aStart2;
  3446. const uint8_t* min_end = end1 < end2 ? end1 : end2;
  3447. return max_start < min_end;
  3448. }
  3449. RequestHeaders::RequestHeader*
  3450. RequestHeaders::Find(const nsACString& aName)
  3451. {
  3452. const nsCaseInsensitiveCStringComparator ignoreCase;
  3453. for (RequestHeaders::RequestHeader& header : mHeaders) {
  3454. if (header.mName.Equals(aName, ignoreCase)) {
  3455. return &header;
  3456. }
  3457. }
  3458. return nullptr;
  3459. }
  3460. bool
  3461. RequestHeaders::Has(const char* aName)
  3462. {
  3463. return Has(nsDependentCString(aName));
  3464. }
  3465. bool
  3466. RequestHeaders::Has(const nsACString& aName)
  3467. {
  3468. return !!Find(aName);
  3469. }
  3470. void
  3471. RequestHeaders::Get(const char* aName, nsACString& aValue)
  3472. {
  3473. Get(nsDependentCString(aName), aValue);
  3474. }
  3475. void
  3476. RequestHeaders::Get(const nsACString& aName, nsACString& aValue)
  3477. {
  3478. RequestHeader* header = Find(aName);
  3479. if (header) {
  3480. aValue = header->mValue;
  3481. } else {
  3482. aValue.SetIsVoid(true);
  3483. }
  3484. }
  3485. void
  3486. RequestHeaders::Set(const char* aName, const nsACString& aValue)
  3487. {
  3488. Set(nsDependentCString(aName), aValue);
  3489. }
  3490. void
  3491. RequestHeaders::Set(const nsACString& aName, const nsACString& aValue)
  3492. {
  3493. RequestHeader* header = Find(aName);
  3494. if (header) {
  3495. header->mValue.Assign(aValue);
  3496. } else {
  3497. RequestHeader newHeader = {
  3498. nsCString(aName), nsCString(aValue)
  3499. };
  3500. mHeaders.AppendElement(newHeader);
  3501. }
  3502. }
  3503. void
  3504. RequestHeaders::MergeOrSet(const char* aName, const nsACString& aValue)
  3505. {
  3506. MergeOrSet(nsDependentCString(aName), aValue);
  3507. }
  3508. void
  3509. RequestHeaders::MergeOrSet(const nsACString& aName, const nsACString& aValue)
  3510. {
  3511. RequestHeader* header = Find(aName);
  3512. if (header) {
  3513. header->mValue.AppendLiteral(", ");
  3514. header->mValue.Append(aValue);
  3515. } else {
  3516. RequestHeader newHeader = {
  3517. nsCString(aName), nsCString(aValue)
  3518. };
  3519. mHeaders.AppendElement(newHeader);
  3520. }
  3521. }
  3522. void
  3523. RequestHeaders::Clear()
  3524. {
  3525. mHeaders.Clear();
  3526. }
  3527. void
  3528. RequestHeaders::ApplyToChannel(nsIHttpChannel* aHttpChannel) const
  3529. {
  3530. for (const RequestHeader& header : mHeaders) {
  3531. if (header.mValue.IsEmpty()) {
  3532. aHttpChannel->SetEmptyRequestHeader(header.mName);
  3533. } else {
  3534. aHttpChannel->SetRequestHeader(header.mName, header.mValue, false);
  3535. }
  3536. }
  3537. }
  3538. void
  3539. RequestHeaders::GetCORSUnsafeHeaders(nsTArray<nsCString>& aArray) const
  3540. {
  3541. static const char *kCrossOriginSafeHeaders[] = {
  3542. "accept", "accept-language", "content-language", "content-type",
  3543. "last-event-id"
  3544. };
  3545. const uint32_t kCrossOriginSafeHeadersLength =
  3546. ArrayLength(kCrossOriginSafeHeaders);
  3547. for (const RequestHeader& header : mHeaders) {
  3548. bool safe = false;
  3549. for (uint32_t i = 0; i < kCrossOriginSafeHeadersLength; ++i) {
  3550. if (header.mName.LowerCaseEqualsASCII(kCrossOriginSafeHeaders[i])) {
  3551. safe = true;
  3552. break;
  3553. }
  3554. }
  3555. if (!safe) {
  3556. aArray.AppendElement(header.mName);
  3557. }
  3558. }
  3559. }
  3560. RequestHeaders::CharsetIterator::CharsetIterator(nsACString& aSource) :
  3561. mValid(false),
  3562. mCurPos(-1),
  3563. mCurLen(-1),
  3564. mCutoff(aSource.Length()),
  3565. mSource(aSource)
  3566. {
  3567. }
  3568. bool
  3569. RequestHeaders::CharsetIterator::Equals(const nsACString& aOther,
  3570. const nsCStringComparator& aCmp) const
  3571. {
  3572. if (mValid) {
  3573. return Substring(mSource, mCurPos, mCurLen).Equals(aOther, aCmp);
  3574. } else {
  3575. return false;
  3576. }
  3577. }
  3578. void
  3579. RequestHeaders::CharsetIterator::Replace(const nsACString& aReplacement)
  3580. {
  3581. if (mValid) {
  3582. mSource.Replace(mCurPos, mCurLen, aReplacement);
  3583. mCurLen = aReplacement.Length();
  3584. }
  3585. }
  3586. bool
  3587. RequestHeaders::CharsetIterator::Next()
  3588. {
  3589. int32_t start, end;
  3590. nsAutoCString charset;
  3591. // Look for another charset declaration in the string, limiting the
  3592. // search to only the characters before the parts we've already searched
  3593. // (before mCutoff), so that we don't find the same charset twice.
  3594. NS_ExtractCharsetFromContentType(Substring(mSource, 0, mCutoff),
  3595. charset, &mValid, &start, &end);
  3596. if (!mValid) {
  3597. return false;
  3598. }
  3599. // Everything after the = sign is the part of the charset we want.
  3600. mCurPos = mSource.FindChar('=', start) + 1;
  3601. mCurLen = end - mCurPos;
  3602. // Special case: the extracted charset is quoted with single quotes.
  3603. // For the purpose of preserving what was set we want to handle them
  3604. // as delimiters (although they aren't really).
  3605. if (charset.Length() >= 2 &&
  3606. charset.First() == '\'' &&
  3607. charset.Last() == '\'') {
  3608. ++mCurPos;
  3609. mCurLen -= 2;
  3610. }
  3611. mCutoff = start;
  3612. return true;
  3613. }
  3614. } // dom namespace
  3615. } // mozilla namespace