WebSocketChannel.cpp 123 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059
  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 "WebSocketFrame.h"
  6. #include "WebSocketLog.h"
  7. #include "WebSocketChannel.h"
  8. #include "mozilla/Atomics.h"
  9. #include "mozilla/Attributes.h"
  10. #include "mozilla/EndianUtils.h"
  11. #include "mozilla/MathAlgorithms.h"
  12. #include "mozilla/net/WebSocketEventService.h"
  13. #include "nsIURI.h"
  14. #include "nsIChannel.h"
  15. #include "nsICryptoHash.h"
  16. #include "nsIRunnable.h"
  17. #include "nsIPrefBranch.h"
  18. #include "nsIPrefService.h"
  19. #include "nsICancelable.h"
  20. #include "nsIClassOfService.h"
  21. #include "nsIDNSRecord.h"
  22. #include "nsIDNSService.h"
  23. #include "nsIStreamConverterService.h"
  24. #include "nsIIOService2.h"
  25. #include "nsIProtocolProxyService.h"
  26. #include "nsIProxyInfo.h"
  27. #include "nsIProxiedChannel.h"
  28. #include "nsIAsyncVerifyRedirectCallback.h"
  29. #include "nsIDashboardEventNotifier.h"
  30. #include "nsIEventTarget.h"
  31. #include "nsIHttpChannel.h"
  32. #include "nsILoadGroup.h"
  33. #include "nsIProtocolHandler.h"
  34. #include "nsIRandomGenerator.h"
  35. #include "nsISocketTransport.h"
  36. #include "nsThreadUtils.h"
  37. #include "nsINetworkLinkService.h"
  38. #include "nsIObserverService.h"
  39. #include "nsITransportProvider.h"
  40. #include "nsCharSeparatedTokenizer.h"
  41. #include "nsAutoPtr.h"
  42. #include "nsNetCID.h"
  43. #include "nsServiceManagerUtils.h"
  44. #include "nsCRT.h"
  45. #include "nsThreadUtils.h"
  46. #include "nsError.h"
  47. #include "nsStringStream.h"
  48. #include "nsAlgorithm.h"
  49. #include "nsProxyRelease.h"
  50. #include "nsNetUtil.h"
  51. #include "nsINode.h"
  52. #include "mozilla/StaticMutex.h"
  53. #include "mozilla/TimeStamp.h"
  54. #include "nsSocketTransportService2.h"
  55. #include "plbase64.h"
  56. #include "prmem.h"
  57. #include "prnetdb.h"
  58. #include "zlib.h"
  59. #include <algorithm>
  60. // rather than slurp up all of nsIWebSocket.idl, which lives outside necko, just
  61. // dupe one constant we need from it
  62. #define CLOSE_GOING_AWAY 1001
  63. using namespace mozilla;
  64. using namespace mozilla::net;
  65. namespace mozilla {
  66. namespace net {
  67. NS_IMPL_ISUPPORTS(WebSocketChannel,
  68. nsIWebSocketChannel,
  69. nsIHttpUpgradeListener,
  70. nsIRequestObserver,
  71. nsIStreamListener,
  72. nsIProtocolHandler,
  73. nsIInputStreamCallback,
  74. nsIOutputStreamCallback,
  75. nsITimerCallback,
  76. nsIDNSListener,
  77. nsIProtocolProxyCallback,
  78. nsIInterfaceRequestor,
  79. nsIChannelEventSink,
  80. nsIThreadRetargetableRequest,
  81. nsIObserver)
  82. // We implement RFC 6455, which uses Sec-WebSocket-Version: 13 on the wire.
  83. #define SEC_WEBSOCKET_VERSION "13"
  84. /*
  85. * About SSL unsigned certificates
  86. *
  87. * wss will not work to a host using an unsigned certificate unless there
  88. * is already an exception (i.e. it cannot popup a dialog asking for
  89. * a security exception). This is similar to how an inlined img will
  90. * fail without a dialog if fails for the same reason. This should not
  91. * be a problem in practice as it is expected the websocket javascript
  92. * is served from the same host as the websocket server (or of course,
  93. * a valid cert could just be provided).
  94. *
  95. */
  96. // some helper classes
  97. //-----------------------------------------------------------------------------
  98. // FailDelayManager
  99. //
  100. // Stores entries (searchable by {host, port}) of connections that have recently
  101. // failed, so we can do delay of reconnects per RFC 6455 Section 7.2.3
  102. //-----------------------------------------------------------------------------
  103. // Initial reconnect delay is randomly chosen between 200-400 ms.
  104. // This is a gentler backoff than the 0-5 seconds the spec offhandedly suggests.
  105. const uint32_t kWSReconnectInitialBaseDelay = 200;
  106. const uint32_t kWSReconnectInitialRandomDelay = 200;
  107. // Base lifetime (in ms) of a FailDelay: kept longer if more failures occur
  108. const uint32_t kWSReconnectBaseLifeTime = 60 * 1000;
  109. // Maximum reconnect delay (in ms)
  110. const uint32_t kWSReconnectMaxDelay = 60 * 1000;
  111. // hold record of failed connections, and calculates needed delay for reconnects
  112. // to same host/port.
  113. class FailDelay
  114. {
  115. public:
  116. FailDelay(nsCString address, int32_t port)
  117. : mAddress(address), mPort(port)
  118. {
  119. mLastFailure = TimeStamp::Now();
  120. mNextDelay = kWSReconnectInitialBaseDelay +
  121. (rand() % kWSReconnectInitialRandomDelay);
  122. }
  123. // Called to update settings when connection fails again.
  124. void FailedAgain()
  125. {
  126. mLastFailure = TimeStamp::Now();
  127. // We use a truncated exponential backoff as suggested by RFC 6455,
  128. // but multiply by 1.5 instead of 2 to be more gradual.
  129. mNextDelay = static_cast<uint32_t>(
  130. std::min<double>(kWSReconnectMaxDelay, mNextDelay * 1.5));
  131. LOG(("WebSocket: FailedAgain: host=%s, port=%d: incremented delay to %lu",
  132. mAddress.get(), mPort, mNextDelay));
  133. }
  134. // returns 0 if there is no need to delay (i.e. delay interval is over)
  135. uint32_t RemainingDelay(TimeStamp rightNow)
  136. {
  137. TimeDuration dur = rightNow - mLastFailure;
  138. uint32_t sinceFail = (uint32_t) dur.ToMilliseconds();
  139. if (sinceFail > mNextDelay)
  140. return 0;
  141. return mNextDelay - sinceFail;
  142. }
  143. bool IsExpired(TimeStamp rightNow)
  144. {
  145. return (mLastFailure +
  146. TimeDuration::FromMilliseconds(kWSReconnectBaseLifeTime + mNextDelay))
  147. <= rightNow;
  148. }
  149. nsCString mAddress; // IP address (or hostname if using proxy)
  150. int32_t mPort;
  151. private:
  152. TimeStamp mLastFailure; // Time of last failed attempt
  153. // mLastFailure + mNextDelay is the soonest we'll allow a reconnect
  154. uint32_t mNextDelay; // milliseconds
  155. };
  156. class FailDelayManager
  157. {
  158. public:
  159. FailDelayManager()
  160. {
  161. MOZ_COUNT_CTOR(FailDelayManager);
  162. mDelaysDisabled = false;
  163. nsCOMPtr<nsIPrefBranch> prefService =
  164. do_GetService(NS_PREFSERVICE_CONTRACTID);
  165. if (!prefService) {
  166. return;
  167. }
  168. bool boolpref = true;
  169. nsresult rv;
  170. rv = prefService->GetBoolPref("network.websocket.delay-failed-reconnects",
  171. &boolpref);
  172. if (NS_SUCCEEDED(rv) && !boolpref) {
  173. mDelaysDisabled = true;
  174. }
  175. }
  176. ~FailDelayManager()
  177. {
  178. MOZ_COUNT_DTOR(FailDelayManager);
  179. for (uint32_t i = 0; i < mEntries.Length(); i++) {
  180. delete mEntries[i];
  181. }
  182. }
  183. void Add(nsCString &address, int32_t port)
  184. {
  185. if (mDelaysDisabled)
  186. return;
  187. FailDelay *record = new FailDelay(address, port);
  188. mEntries.AppendElement(record);
  189. }
  190. // Element returned may not be valid after next main thread event: don't keep
  191. // pointer to it around
  192. FailDelay* Lookup(nsCString &address, int32_t port,
  193. uint32_t *outIndex = nullptr)
  194. {
  195. if (mDelaysDisabled)
  196. return nullptr;
  197. FailDelay *result = nullptr;
  198. TimeStamp rightNow = TimeStamp::Now();
  199. // We also remove expired entries during search: iterate from end to make
  200. // indexing simpler
  201. for (int32_t i = mEntries.Length() - 1; i >= 0; --i) {
  202. FailDelay *fail = mEntries[i];
  203. if (fail->mAddress.Equals(address) && fail->mPort == port) {
  204. if (outIndex)
  205. *outIndex = i;
  206. result = fail;
  207. // break here: removing more entries would mess up *outIndex.
  208. // Any remaining expired entries will be deleted next time Lookup
  209. // finds nothing, which is the most common case anyway.
  210. break;
  211. } else if (fail->IsExpired(rightNow)) {
  212. mEntries.RemoveElementAt(i);
  213. delete fail;
  214. }
  215. }
  216. return result;
  217. }
  218. // returns true if channel connects immediately, or false if it's delayed
  219. void DelayOrBegin(WebSocketChannel *ws)
  220. {
  221. if (!mDelaysDisabled) {
  222. uint32_t failIndex = 0;
  223. FailDelay *fail = Lookup(ws->mAddress, ws->mPort, &failIndex);
  224. if (fail) {
  225. TimeStamp rightNow = TimeStamp::Now();
  226. uint32_t remainingDelay = fail->RemainingDelay(rightNow);
  227. if (remainingDelay) {
  228. // reconnecting within delay interval: delay by remaining time
  229. nsresult rv;
  230. ws->mReconnectDelayTimer =
  231. do_CreateInstance("@mozilla.org/timer;1", &rv);
  232. if (NS_SUCCEEDED(rv)) {
  233. rv = ws->mReconnectDelayTimer->InitWithCallback(
  234. ws, remainingDelay, nsITimer::TYPE_ONE_SHOT);
  235. if (NS_SUCCEEDED(rv)) {
  236. LOG(("WebSocket: delaying websocket [this=%p] by %lu ms, changing"
  237. " state to CONNECTING_DELAYED", ws,
  238. (unsigned long)remainingDelay));
  239. ws->mConnecting = CONNECTING_DELAYED;
  240. return;
  241. }
  242. }
  243. // if timer fails (which is very unlikely), drop down to BeginOpen call
  244. } else if (fail->IsExpired(rightNow)) {
  245. mEntries.RemoveElementAt(failIndex);
  246. delete fail;
  247. }
  248. }
  249. }
  250. // Delays disabled, or no previous failure, or we're reconnecting after scheduled
  251. // delay interval has passed: connect.
  252. ws->BeginOpen(true);
  253. }
  254. // Remove() also deletes all expired entries as it iterates: better for
  255. // battery life than using a periodic timer.
  256. void Remove(nsCString &address, int32_t port)
  257. {
  258. TimeStamp rightNow = TimeStamp::Now();
  259. // iterate from end, to make deletion indexing easier
  260. for (int32_t i = mEntries.Length() - 1; i >= 0; --i) {
  261. FailDelay *entry = mEntries[i];
  262. if ((entry->mAddress.Equals(address) && entry->mPort == port) ||
  263. entry->IsExpired(rightNow)) {
  264. mEntries.RemoveElementAt(i);
  265. delete entry;
  266. }
  267. }
  268. }
  269. private:
  270. nsTArray<FailDelay *> mEntries;
  271. bool mDelaysDisabled;
  272. };
  273. //-----------------------------------------------------------------------------
  274. // nsWSAdmissionManager
  275. //
  276. // 1) Ensures that only one websocket at a time is CONNECTING to a given IP
  277. // address (or hostname, if using proxy), per RFC 6455 Section 4.1.
  278. // 2) Delays reconnects to IP/host after connection failure, per Section 7.2.3
  279. //-----------------------------------------------------------------------------
  280. class nsWSAdmissionManager
  281. {
  282. public:
  283. static void Init()
  284. {
  285. StaticMutexAutoLock lock(sLock);
  286. if (!sManager) {
  287. sManager = new nsWSAdmissionManager();
  288. }
  289. }
  290. static void Shutdown()
  291. {
  292. StaticMutexAutoLock lock(sLock);
  293. delete sManager;
  294. sManager = nullptr;
  295. }
  296. // Determine if we will open connection immediately (returns true), or
  297. // delay/queue the connection (returns false)
  298. static void ConditionallyConnect(WebSocketChannel *ws)
  299. {
  300. LOG(("Websocket: ConditionallyConnect: [this=%p]", ws));
  301. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  302. MOZ_ASSERT(ws->mConnecting == NOT_CONNECTING, "opening state");
  303. StaticMutexAutoLock lock(sLock);
  304. if (!sManager) {
  305. return;
  306. }
  307. // If there is already another WS channel connecting to this IP address,
  308. // defer BeginOpen and mark as waiting in queue.
  309. bool found = (sManager->IndexOf(ws->mAddress) >= 0);
  310. // Always add ourselves to queue, even if we'll connect immediately
  311. nsOpenConn *newdata = new nsOpenConn(ws->mAddress, ws);
  312. LOG(("Websocket: adding conn %p to the queue", newdata));
  313. sManager->mQueue.AppendElement(newdata);
  314. if (found) {
  315. LOG(("Websocket: some other channel is connecting, changing state to "
  316. "CONNECTING_QUEUED"));
  317. ws->mConnecting = CONNECTING_QUEUED;
  318. } else {
  319. sManager->mFailures.DelayOrBegin(ws);
  320. }
  321. }
  322. static void OnConnected(WebSocketChannel *aChannel)
  323. {
  324. LOG(("Websocket: OnConnected: [this=%p]", aChannel));
  325. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  326. MOZ_ASSERT(aChannel->mConnecting == CONNECTING_IN_PROGRESS,
  327. "Channel completed connect, but not connecting?");
  328. StaticMutexAutoLock lock(sLock);
  329. if (!sManager) {
  330. return;
  331. }
  332. LOG(("Websocket: changing state to NOT_CONNECTING"));
  333. aChannel->mConnecting = NOT_CONNECTING;
  334. // Remove from queue
  335. sManager->RemoveFromQueue(aChannel);
  336. // Connection succeeded, so stop keeping track of any previous failures
  337. sManager->mFailures.Remove(aChannel->mAddress, aChannel->mPort);
  338. // Check for queued connections to same host.
  339. // Note: still need to check for failures, since next websocket with same
  340. // host may have different port
  341. sManager->ConnectNext(aChannel->mAddress);
  342. }
  343. // Called every time a websocket channel ends its session (including going away
  344. // w/o ever successfully creating a connection)
  345. static void OnStopSession(WebSocketChannel *aChannel, nsresult aReason)
  346. {
  347. LOG(("Websocket: OnStopSession: [this=%p, reason=0x%08x]", aChannel,
  348. aReason));
  349. StaticMutexAutoLock lock(sLock);
  350. if (!sManager) {
  351. return;
  352. }
  353. if (NS_FAILED(aReason)) {
  354. // Have we seen this failure before?
  355. FailDelay *knownFailure = sManager->mFailures.Lookup(aChannel->mAddress,
  356. aChannel->mPort);
  357. if (knownFailure) {
  358. if (aReason == NS_ERROR_NOT_CONNECTED) {
  359. // Don't count close() before connection as a network error
  360. LOG(("Websocket close() before connection to %s, %d completed"
  361. " [this=%p]", aChannel->mAddress.get(), (int)aChannel->mPort,
  362. aChannel));
  363. } else {
  364. // repeated failure to connect: increase delay for next connection
  365. knownFailure->FailedAgain();
  366. }
  367. } else {
  368. // new connection failure: record it.
  369. LOG(("WebSocket: connection to %s, %d failed: [this=%p]",
  370. aChannel->mAddress.get(), (int)aChannel->mPort, aChannel));
  371. sManager->mFailures.Add(aChannel->mAddress, aChannel->mPort);
  372. }
  373. }
  374. if (aChannel->mConnecting) {
  375. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  376. // Only way a connecting channel may get here w/o failing is if it was
  377. // closed with GOING_AWAY (1001) because of navigation, tab close, etc.
  378. MOZ_ASSERT(NS_FAILED(aReason) ||
  379. aChannel->mScriptCloseCode == CLOSE_GOING_AWAY,
  380. "websocket closed while connecting w/o failing?");
  381. sManager->RemoveFromQueue(aChannel);
  382. bool wasNotQueued = (aChannel->mConnecting != CONNECTING_QUEUED);
  383. LOG(("Websocket: changing state to NOT_CONNECTING"));
  384. aChannel->mConnecting = NOT_CONNECTING;
  385. if (wasNotQueued) {
  386. sManager->ConnectNext(aChannel->mAddress);
  387. }
  388. }
  389. }
  390. static void IncrementSessionCount()
  391. {
  392. StaticMutexAutoLock lock(sLock);
  393. if (!sManager) {
  394. return;
  395. }
  396. sManager->mSessionCount++;
  397. }
  398. static void DecrementSessionCount()
  399. {
  400. StaticMutexAutoLock lock(sLock);
  401. if (!sManager) {
  402. return;
  403. }
  404. sManager->mSessionCount--;
  405. }
  406. static void GetSessionCount(int32_t &aSessionCount)
  407. {
  408. StaticMutexAutoLock lock(sLock);
  409. if (!sManager) {
  410. return;
  411. }
  412. aSessionCount = sManager->mSessionCount;
  413. }
  414. private:
  415. nsWSAdmissionManager() : mSessionCount(0)
  416. {
  417. MOZ_COUNT_CTOR(nsWSAdmissionManager);
  418. }
  419. ~nsWSAdmissionManager()
  420. {
  421. MOZ_COUNT_DTOR(nsWSAdmissionManager);
  422. for (uint32_t i = 0; i < mQueue.Length(); i++)
  423. delete mQueue[i];
  424. }
  425. class nsOpenConn
  426. {
  427. public:
  428. nsOpenConn(nsCString &addr, WebSocketChannel *channel)
  429. : mAddress(addr), mChannel(channel) { MOZ_COUNT_CTOR(nsOpenConn); }
  430. ~nsOpenConn() { MOZ_COUNT_DTOR(nsOpenConn); }
  431. nsCString mAddress;
  432. WebSocketChannel *mChannel;
  433. };
  434. void ConnectNext(nsCString &hostName)
  435. {
  436. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  437. int32_t index = IndexOf(hostName);
  438. if (index >= 0) {
  439. WebSocketChannel *chan = mQueue[index]->mChannel;
  440. MOZ_ASSERT(chan->mConnecting == CONNECTING_QUEUED,
  441. "transaction not queued but in queue");
  442. LOG(("WebSocket: ConnectNext: found channel [this=%p] in queue", chan));
  443. mFailures.DelayOrBegin(chan);
  444. }
  445. }
  446. void RemoveFromQueue(WebSocketChannel *aChannel)
  447. {
  448. LOG(("Websocket: RemoveFromQueue: [this=%p]", aChannel));
  449. int32_t index = IndexOf(aChannel);
  450. MOZ_ASSERT(index >= 0, "connection to remove not in queue");
  451. if (index >= 0) {
  452. nsOpenConn *olddata = mQueue[index];
  453. mQueue.RemoveElementAt(index);
  454. LOG(("Websocket: removing conn %p from the queue", olddata));
  455. delete olddata;
  456. }
  457. }
  458. int32_t IndexOf(nsCString &aStr)
  459. {
  460. for (uint32_t i = 0; i < mQueue.Length(); i++)
  461. if (aStr == (mQueue[i])->mAddress)
  462. return i;
  463. return -1;
  464. }
  465. int32_t IndexOf(WebSocketChannel *aChannel)
  466. {
  467. for (uint32_t i = 0; i < mQueue.Length(); i++)
  468. if (aChannel == (mQueue[i])->mChannel)
  469. return i;
  470. return -1;
  471. }
  472. // SessionCount might be decremented from the main or the socket
  473. // thread, so manage it with atomic counters
  474. Atomic<int32_t> mSessionCount;
  475. // Queue for websockets that have not completed connecting yet.
  476. // The first nsOpenConn with a given address will be either be
  477. // CONNECTING_IN_PROGRESS or CONNECTING_DELAYED. Later ones with the same
  478. // hostname must be CONNECTING_QUEUED.
  479. //
  480. // We could hash hostnames instead of using a single big vector here, but the
  481. // dataset is expected to be small.
  482. nsTArray<nsOpenConn *> mQueue;
  483. FailDelayManager mFailures;
  484. static nsWSAdmissionManager *sManager;
  485. static StaticMutex sLock;
  486. };
  487. nsWSAdmissionManager *nsWSAdmissionManager::sManager;
  488. StaticMutex nsWSAdmissionManager::sLock;
  489. //-----------------------------------------------------------------------------
  490. // CallOnMessageAvailable
  491. //-----------------------------------------------------------------------------
  492. class CallOnMessageAvailable final : public nsIRunnable
  493. {
  494. public:
  495. NS_DECL_THREADSAFE_ISUPPORTS
  496. CallOnMessageAvailable(WebSocketChannel* aChannel,
  497. nsACString& aData,
  498. int32_t aLen)
  499. : mChannel(aChannel),
  500. mListenerMT(aChannel->mListenerMT),
  501. mData(aData),
  502. mLen(aLen) {}
  503. NS_IMETHOD Run() override
  504. {
  505. MOZ_ASSERT(mChannel->IsOnTargetThread());
  506. if (mListenerMT) {
  507. if (mLen < 0) {
  508. mListenerMT->mListener->OnMessageAvailable(mListenerMT->mContext,
  509. mData);
  510. } else {
  511. mListenerMT->mListener->OnBinaryMessageAvailable(mListenerMT->mContext,
  512. mData);
  513. }
  514. }
  515. return NS_OK;
  516. }
  517. private:
  518. ~CallOnMessageAvailable() {}
  519. RefPtr<WebSocketChannel> mChannel;
  520. RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
  521. nsCString mData;
  522. int32_t mLen;
  523. };
  524. NS_IMPL_ISUPPORTS(CallOnMessageAvailable, nsIRunnable)
  525. //-----------------------------------------------------------------------------
  526. // CallOnStop
  527. //-----------------------------------------------------------------------------
  528. class CallOnStop final : public nsIRunnable
  529. {
  530. public:
  531. NS_DECL_THREADSAFE_ISUPPORTS
  532. CallOnStop(WebSocketChannel* aChannel,
  533. nsresult aReason)
  534. : mChannel(aChannel),
  535. mListenerMT(mChannel->mListenerMT),
  536. mReason(aReason)
  537. {}
  538. NS_IMETHOD Run() override
  539. {
  540. MOZ_ASSERT(mChannel->IsOnTargetThread());
  541. if (mListenerMT) {
  542. mListenerMT->mListener->OnStop(mListenerMT->mContext, mReason);
  543. mChannel->mListenerMT = nullptr;
  544. }
  545. return NS_OK;
  546. }
  547. private:
  548. ~CallOnStop() {}
  549. RefPtr<WebSocketChannel> mChannel;
  550. RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
  551. nsresult mReason;
  552. };
  553. NS_IMPL_ISUPPORTS(CallOnStop, nsIRunnable)
  554. //-----------------------------------------------------------------------------
  555. // CallOnServerClose
  556. //-----------------------------------------------------------------------------
  557. class CallOnServerClose final : public nsIRunnable
  558. {
  559. public:
  560. NS_DECL_THREADSAFE_ISUPPORTS
  561. CallOnServerClose(WebSocketChannel* aChannel,
  562. uint16_t aCode,
  563. nsACString& aReason)
  564. : mChannel(aChannel),
  565. mListenerMT(mChannel->mListenerMT),
  566. mCode(aCode),
  567. mReason(aReason) {}
  568. NS_IMETHOD Run() override
  569. {
  570. MOZ_ASSERT(mChannel->IsOnTargetThread());
  571. if (mListenerMT) {
  572. mListenerMT->mListener->OnServerClose(mListenerMT->mContext, mCode,
  573. mReason);
  574. }
  575. return NS_OK;
  576. }
  577. private:
  578. ~CallOnServerClose() {}
  579. RefPtr<WebSocketChannel> mChannel;
  580. RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
  581. uint16_t mCode;
  582. nsCString mReason;
  583. };
  584. NS_IMPL_ISUPPORTS(CallOnServerClose, nsIRunnable)
  585. //-----------------------------------------------------------------------------
  586. // CallAcknowledge
  587. //-----------------------------------------------------------------------------
  588. class CallAcknowledge final : public CancelableRunnable
  589. {
  590. public:
  591. CallAcknowledge(WebSocketChannel* aChannel,
  592. uint32_t aSize)
  593. : mChannel(aChannel),
  594. mListenerMT(mChannel->mListenerMT),
  595. mSize(aSize) {}
  596. NS_IMETHOD Run() override
  597. {
  598. MOZ_ASSERT(mChannel->IsOnTargetThread());
  599. LOG(("WebSocketChannel::CallAcknowledge: Size %u\n", mSize));
  600. if (mListenerMT) {
  601. mListenerMT->mListener->OnAcknowledge(mListenerMT->mContext, mSize);
  602. }
  603. return NS_OK;
  604. }
  605. private:
  606. ~CallAcknowledge() {}
  607. RefPtr<WebSocketChannel> mChannel;
  608. RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
  609. uint32_t mSize;
  610. };
  611. //-----------------------------------------------------------------------------
  612. // CallOnTransportAvailable
  613. //-----------------------------------------------------------------------------
  614. class CallOnTransportAvailable final : public nsIRunnable
  615. {
  616. public:
  617. NS_DECL_THREADSAFE_ISUPPORTS
  618. CallOnTransportAvailable(WebSocketChannel *aChannel,
  619. nsISocketTransport *aTransport,
  620. nsIAsyncInputStream *aSocketIn,
  621. nsIAsyncOutputStream *aSocketOut)
  622. : mChannel(aChannel),
  623. mTransport(aTransport),
  624. mSocketIn(aSocketIn),
  625. mSocketOut(aSocketOut) {}
  626. NS_IMETHOD Run() override
  627. {
  628. LOG(("WebSocketChannel::CallOnTransportAvailable %p\n", this));
  629. return mChannel->OnTransportAvailable(mTransport, mSocketIn, mSocketOut);
  630. }
  631. private:
  632. ~CallOnTransportAvailable() {}
  633. RefPtr<WebSocketChannel> mChannel;
  634. nsCOMPtr<nsISocketTransport> mTransport;
  635. nsCOMPtr<nsIAsyncInputStream> mSocketIn;
  636. nsCOMPtr<nsIAsyncOutputStream> mSocketOut;
  637. };
  638. NS_IMPL_ISUPPORTS(CallOnTransportAvailable, nsIRunnable)
  639. //-----------------------------------------------------------------------------
  640. // PMCECompression
  641. //-----------------------------------------------------------------------------
  642. class PMCECompression
  643. {
  644. public:
  645. PMCECompression(bool aNoContextTakeover,
  646. int32_t aLocalMaxWindowBits,
  647. int32_t aRemoteMaxWindowBits)
  648. : mActive(false)
  649. , mNoContextTakeover(aNoContextTakeover)
  650. , mResetDeflater(false)
  651. , mMessageDeflated(false)
  652. {
  653. MOZ_COUNT_CTOR(PMCECompression);
  654. mDeflater.zalloc = mInflater.zalloc = Z_NULL;
  655. mDeflater.zfree = mInflater.zfree = Z_NULL;
  656. mDeflater.opaque = mInflater.opaque = Z_NULL;
  657. if (deflateInit2(&mDeflater, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
  658. -aLocalMaxWindowBits, 8, Z_DEFAULT_STRATEGY) == Z_OK) {
  659. if (inflateInit2(&mInflater, -aRemoteMaxWindowBits) == Z_OK) {
  660. mActive = true;
  661. } else {
  662. deflateEnd(&mDeflater);
  663. }
  664. }
  665. }
  666. ~PMCECompression()
  667. {
  668. MOZ_COUNT_DTOR(PMCECompression);
  669. if (mActive) {
  670. inflateEnd(&mInflater);
  671. deflateEnd(&mDeflater);
  672. }
  673. }
  674. bool Active()
  675. {
  676. return mActive;
  677. }
  678. void SetMessageDeflated()
  679. {
  680. MOZ_ASSERT(!mMessageDeflated);
  681. mMessageDeflated = true;
  682. }
  683. bool IsMessageDeflated()
  684. {
  685. return mMessageDeflated;
  686. }
  687. bool UsingContextTakeover()
  688. {
  689. return !mNoContextTakeover;
  690. }
  691. nsresult Deflate(uint8_t *data, uint32_t dataLen, nsACString &_retval)
  692. {
  693. if (mResetDeflater || mNoContextTakeover) {
  694. if (deflateReset(&mDeflater) != Z_OK) {
  695. return NS_ERROR_UNEXPECTED;
  696. }
  697. mResetDeflater = false;
  698. }
  699. mDeflater.avail_out = kBufferLen;
  700. mDeflater.next_out = mBuffer;
  701. mDeflater.avail_in = dataLen;
  702. mDeflater.next_in = data;
  703. while (true) {
  704. int zerr = deflate(&mDeflater, Z_SYNC_FLUSH);
  705. if (zerr != Z_OK) {
  706. mResetDeflater = true;
  707. return NS_ERROR_UNEXPECTED;
  708. }
  709. uint32_t deflated = kBufferLen - mDeflater.avail_out;
  710. if (deflated > 0) {
  711. _retval.Append(reinterpret_cast<char *>(mBuffer), deflated);
  712. }
  713. mDeflater.avail_out = kBufferLen;
  714. mDeflater.next_out = mBuffer;
  715. if (mDeflater.avail_in > 0) {
  716. continue; // There is still some data to deflate
  717. }
  718. if (deflated == kBufferLen) {
  719. continue; // There was not enough space in the buffer
  720. }
  721. break;
  722. }
  723. if (_retval.Length() < 4) {
  724. MOZ_ASSERT(false, "Expected trailing not found in deflated data!");
  725. mResetDeflater = true;
  726. return NS_ERROR_UNEXPECTED;
  727. }
  728. _retval.Truncate(_retval.Length() - 4);
  729. return NS_OK;
  730. }
  731. nsresult Inflate(uint8_t *data, uint32_t dataLen, nsACString &_retval)
  732. {
  733. mMessageDeflated = false;
  734. Bytef trailingData[] = { 0x00, 0x00, 0xFF, 0xFF };
  735. bool trailingDataUsed = false;
  736. mInflater.avail_out = kBufferLen;
  737. mInflater.next_out = mBuffer;
  738. mInflater.avail_in = dataLen;
  739. mInflater.next_in = data;
  740. while (true) {
  741. int zerr = inflate(&mInflater, Z_NO_FLUSH);
  742. if (zerr == Z_STREAM_END) {
  743. Bytef *saveNextIn = mInflater.next_in;
  744. uint32_t saveAvailIn = mInflater.avail_in;
  745. Bytef *saveNextOut = mInflater.next_out;
  746. uint32_t saveAvailOut = mInflater.avail_out;
  747. inflateReset(&mInflater);
  748. mInflater.next_in = saveNextIn;
  749. mInflater.avail_in = saveAvailIn;
  750. mInflater.next_out = saveNextOut;
  751. mInflater.avail_out = saveAvailOut;
  752. } else if (zerr != Z_OK && zerr != Z_BUF_ERROR) {
  753. return NS_ERROR_INVALID_CONTENT_ENCODING;
  754. }
  755. uint32_t inflated = kBufferLen - mInflater.avail_out;
  756. if (inflated > 0) {
  757. _retval.Append(reinterpret_cast<char *>(mBuffer), inflated);
  758. }
  759. mInflater.avail_out = kBufferLen;
  760. mInflater.next_out = mBuffer;
  761. if (mInflater.avail_in > 0) {
  762. continue; // There is still some data to inflate
  763. }
  764. if (inflated == kBufferLen) {
  765. continue; // There was not enough space in the buffer
  766. }
  767. if (!trailingDataUsed) {
  768. trailingDataUsed = true;
  769. mInflater.avail_in = sizeof(trailingData);
  770. mInflater.next_in = trailingData;
  771. continue;
  772. }
  773. return NS_OK;
  774. }
  775. }
  776. private:
  777. bool mActive;
  778. bool mNoContextTakeover;
  779. bool mResetDeflater;
  780. bool mMessageDeflated;
  781. z_stream mDeflater;
  782. z_stream mInflater;
  783. const static uint32_t kBufferLen = 4096;
  784. uint8_t mBuffer[kBufferLen];
  785. };
  786. //-----------------------------------------------------------------------------
  787. // OutboundMessage
  788. //-----------------------------------------------------------------------------
  789. enum WsMsgType {
  790. kMsgTypeString = 0,
  791. kMsgTypeBinaryString,
  792. kMsgTypeStream,
  793. kMsgTypePing,
  794. kMsgTypePong,
  795. kMsgTypeFin
  796. };
  797. static const char* msgNames[] = {
  798. "text",
  799. "binaryString",
  800. "binaryStream",
  801. "ping",
  802. "pong",
  803. "close"
  804. };
  805. class OutboundMessage
  806. {
  807. public:
  808. OutboundMessage(WsMsgType type, nsCString *str)
  809. : mMsgType(type), mDeflated(false), mOrigLength(0)
  810. {
  811. MOZ_COUNT_CTOR(OutboundMessage);
  812. mMsg.pString.mValue = str;
  813. mMsg.pString.mOrigValue = nullptr;
  814. mLength = str ? str->Length() : 0;
  815. }
  816. OutboundMessage(nsIInputStream *stream, uint32_t length)
  817. : mMsgType(kMsgTypeStream), mLength(length), mDeflated(false)
  818. , mOrigLength(0)
  819. {
  820. MOZ_COUNT_CTOR(OutboundMessage);
  821. mMsg.pStream = stream;
  822. mMsg.pStream->AddRef();
  823. }
  824. ~OutboundMessage() {
  825. MOZ_COUNT_DTOR(OutboundMessage);
  826. switch (mMsgType) {
  827. case kMsgTypeString:
  828. case kMsgTypeBinaryString:
  829. case kMsgTypePing:
  830. case kMsgTypePong:
  831. delete mMsg.pString.mValue;
  832. if (mMsg.pString.mOrigValue)
  833. delete mMsg.pString.mOrigValue;
  834. break;
  835. case kMsgTypeStream:
  836. // for now this only gets hit if msg deleted w/o being sent
  837. if (mMsg.pStream) {
  838. mMsg.pStream->Close();
  839. mMsg.pStream->Release();
  840. }
  841. break;
  842. case kMsgTypeFin:
  843. break; // do-nothing: avoid compiler warning
  844. }
  845. }
  846. WsMsgType GetMsgType() const { return mMsgType; }
  847. int32_t Length() const { return mLength; }
  848. int32_t OrigLength() const { return mDeflated ? mOrigLength : mLength; }
  849. uint8_t* BeginWriting() {
  850. MOZ_ASSERT(mMsgType != kMsgTypeStream,
  851. "Stream should have been converted to string by now");
  852. return (uint8_t *)(mMsg.pString.mValue ? mMsg.pString.mValue->BeginWriting() : nullptr);
  853. }
  854. uint8_t* BeginReading() {
  855. MOZ_ASSERT(mMsgType != kMsgTypeStream,
  856. "Stream should have been converted to string by now");
  857. return (uint8_t *)(mMsg.pString.mValue ? mMsg.pString.mValue->BeginReading() : nullptr);
  858. }
  859. uint8_t* BeginOrigReading() {
  860. MOZ_ASSERT(mMsgType != kMsgTypeStream,
  861. "Stream should have been converted to string by now");
  862. if (!mDeflated)
  863. return BeginReading();
  864. return (uint8_t *)(mMsg.pString.mOrigValue ? mMsg.pString.mOrigValue->BeginReading() : nullptr);
  865. }
  866. nsresult ConvertStreamToString()
  867. {
  868. MOZ_ASSERT(mMsgType == kMsgTypeStream, "Not a stream!");
  869. #ifdef DEBUG
  870. // Make sure we got correct length from Blob
  871. uint64_t bytes;
  872. mMsg.pStream->Available(&bytes);
  873. NS_ASSERTION(bytes == mLength, "Stream length != blob length!");
  874. #endif
  875. nsAutoPtr<nsCString> temp(new nsCString());
  876. nsresult rv = NS_ReadInputStreamToString(mMsg.pStream, *temp, mLength);
  877. NS_ENSURE_SUCCESS(rv, rv);
  878. mMsg.pStream->Close();
  879. mMsg.pStream->Release();
  880. mMsg.pString.mValue = temp.forget();
  881. mMsg.pString.mOrigValue = nullptr;
  882. mMsgType = kMsgTypeBinaryString;
  883. return NS_OK;
  884. }
  885. bool DeflatePayload(PMCECompression *aCompressor)
  886. {
  887. MOZ_ASSERT(mMsgType != kMsgTypeStream,
  888. "Stream should have been converted to string by now");
  889. MOZ_ASSERT(!mDeflated);
  890. nsresult rv;
  891. if (mLength == 0) {
  892. // Empty message
  893. return false;
  894. }
  895. nsAutoPtr<nsCString> temp(new nsCString());
  896. rv = aCompressor->Deflate(BeginReading(), mLength, *temp);
  897. if (NS_FAILED(rv)) {
  898. LOG(("WebSocketChannel::OutboundMessage: Deflating payload failed "
  899. "[rv=0x%08x]\n", rv));
  900. return false;
  901. }
  902. if (!aCompressor->UsingContextTakeover() && temp->Length() > mLength) {
  903. // When "<local>_no_context_takeover" was negotiated, do not send deflated
  904. // payload if it's larger that the original one. OTOH, it makes sense
  905. // to send the larger deflated payload when the sliding window is not
  906. // reset between messages because if we would skip some deflated block
  907. // we would need to empty the sliding window which could affect the
  908. // compression of the subsequent messages.
  909. LOG(("WebSocketChannel::OutboundMessage: Not deflating message since the "
  910. "deflated payload is larger than the original one [deflated=%d, "
  911. "original=%d]", temp->Length(), mLength));
  912. return false;
  913. }
  914. mOrigLength = mLength;
  915. mDeflated = true;
  916. mLength = temp->Length();
  917. mMsg.pString.mOrigValue = mMsg.pString.mValue;
  918. mMsg.pString.mValue = temp.forget();
  919. return true;
  920. }
  921. private:
  922. union {
  923. struct {
  924. nsCString *mValue;
  925. nsCString *mOrigValue;
  926. } pString;
  927. nsIInputStream *pStream;
  928. } mMsg;
  929. WsMsgType mMsgType;
  930. uint32_t mLength;
  931. bool mDeflated;
  932. uint32_t mOrigLength;
  933. };
  934. //-----------------------------------------------------------------------------
  935. // OutboundEnqueuer
  936. //-----------------------------------------------------------------------------
  937. class OutboundEnqueuer final : public nsIRunnable
  938. {
  939. public:
  940. NS_DECL_THREADSAFE_ISUPPORTS
  941. OutboundEnqueuer(WebSocketChannel *aChannel, OutboundMessage *aMsg)
  942. : mChannel(aChannel), mMessage(aMsg) {}
  943. NS_IMETHOD Run() override
  944. {
  945. mChannel->EnqueueOutgoingMessage(mChannel->mOutgoingMessages, mMessage);
  946. return NS_OK;
  947. }
  948. private:
  949. ~OutboundEnqueuer() {}
  950. RefPtr<WebSocketChannel> mChannel;
  951. OutboundMessage *mMessage;
  952. };
  953. NS_IMPL_ISUPPORTS(OutboundEnqueuer, nsIRunnable)
  954. //-----------------------------------------------------------------------------
  955. // WebSocketChannel
  956. //-----------------------------------------------------------------------------
  957. WebSocketChannel::WebSocketChannel() :
  958. mPort(0),
  959. mCloseTimeout(20000),
  960. mOpenTimeout(20000),
  961. mConnecting(NOT_CONNECTING),
  962. mMaxConcurrentConnections(200),
  963. mGotUpgradeOK(0),
  964. mRecvdHttpUpgradeTransport(0),
  965. mAutoFollowRedirects(0),
  966. mAllowPMCE(1),
  967. mPingOutstanding(0),
  968. mReleaseOnTransmit(0),
  969. mDataStarted(0),
  970. mRequestedClose(0),
  971. mClientClosed(0),
  972. mServerClosed(0),
  973. mStopped(0),
  974. mCalledOnStop(0),
  975. mTCPClosed(0),
  976. mOpenedHttpChannel(0),
  977. mIncrementedSessionCount(0),
  978. mDecrementedSessionCount(0),
  979. mMaxMessageSize(INT32_MAX),
  980. mStopOnClose(NS_OK),
  981. mServerCloseCode(CLOSE_ABNORMAL),
  982. mScriptCloseCode(0),
  983. mFragmentOpcode(nsIWebSocketFrame::OPCODE_CONTINUATION),
  984. mFragmentAccumulator(0),
  985. mBuffered(0),
  986. mBufferSize(kIncomingBufferInitialSize),
  987. mCurrentOut(nullptr),
  988. mCurrentOutSent(0),
  989. mDynamicOutputSize(0),
  990. mDynamicOutput(nullptr),
  991. mPrivateBrowsing(false),
  992. mConnectionLogService(nullptr),
  993. mCountRecv(0),
  994. mCountSent(0),
  995. mAppId(NECKO_NO_APP_ID),
  996. mIsInIsolatedMozBrowser(false)
  997. {
  998. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  999. LOG(("WebSocketChannel::WebSocketChannel() %p\n", this));
  1000. nsWSAdmissionManager::Init();
  1001. mFramePtr = mBuffer = static_cast<uint8_t *>(moz_xmalloc(mBufferSize));
  1002. nsresult rv;
  1003. mConnectionLogService = do_GetService("@mozilla.org/network/dashboard;1",&rv);
  1004. if (NS_FAILED(rv))
  1005. LOG(("Failed to initiate dashboard service."));
  1006. mService = WebSocketEventService::GetOrCreate();
  1007. }
  1008. WebSocketChannel::~WebSocketChannel()
  1009. {
  1010. LOG(("WebSocketChannel::~WebSocketChannel() %p\n", this));
  1011. if (mWasOpened) {
  1012. MOZ_ASSERT(mCalledOnStop, "WebSocket was opened but OnStop was not called");
  1013. MOZ_ASSERT(mStopped, "WebSocket was opened but never stopped");
  1014. }
  1015. MOZ_ASSERT(!mCancelable, "DNS/Proxy Request still alive at destruction");
  1016. MOZ_ASSERT(!mConnecting, "Should not be connecting in destructor");
  1017. free(mBuffer);
  1018. free(mDynamicOutput);
  1019. delete mCurrentOut;
  1020. while ((mCurrentOut = (OutboundMessage *) mOutgoingPingMessages.PopFront()))
  1021. delete mCurrentOut;
  1022. while ((mCurrentOut = (OutboundMessage *) mOutgoingPongMessages.PopFront()))
  1023. delete mCurrentOut;
  1024. while ((mCurrentOut = (OutboundMessage *) mOutgoingMessages.PopFront()))
  1025. delete mCurrentOut;
  1026. NS_ReleaseOnMainThread(mURI.forget());
  1027. NS_ReleaseOnMainThread(mOriginalURI.forget());
  1028. mListenerMT = nullptr;
  1029. NS_ReleaseOnMainThread(mLoadGroup.forget());
  1030. NS_ReleaseOnMainThread(mLoadInfo.forget());
  1031. NS_ReleaseOnMainThread(mService.forget());
  1032. }
  1033. NS_IMETHODIMP
  1034. WebSocketChannel::Observe(nsISupports *subject,
  1035. const char *topic,
  1036. const char16_t *data)
  1037. {
  1038. LOG(("WebSocketChannel::Observe [topic=\"%s\"]\n", topic));
  1039. if (strcmp(topic, NS_NETWORK_LINK_TOPIC) == 0) {
  1040. nsCString converted = NS_ConvertUTF16toUTF8(data);
  1041. const char *state = converted.get();
  1042. if (strcmp(state, NS_NETWORK_LINK_DATA_CHANGED) == 0) {
  1043. LOG(("WebSocket: received network CHANGED event"));
  1044. if (!mSocketThread) {
  1045. // there has not been an asyncopen yet on the object and then we need
  1046. // no ping.
  1047. LOG(("WebSocket: early object, no ping needed"));
  1048. } else {
  1049. // Next we check mDataStarted, which we need to do on mTargetThread.
  1050. if (!IsOnTargetThread()) {
  1051. mTargetThread->Dispatch(
  1052. NewRunnableMethod(this, &WebSocketChannel::OnNetworkChangedTargetThread),
  1053. NS_DISPATCH_NORMAL);
  1054. } else {
  1055. OnNetworkChangedTargetThread();
  1056. }
  1057. }
  1058. }
  1059. }
  1060. return NS_OK;
  1061. }
  1062. nsresult
  1063. WebSocketChannel::OnNetworkChangedTargetThread()
  1064. {
  1065. LOG(("WebSocketChannel::OnNetworkChangedTargetThread() - on target thread %p", this));
  1066. if (!mDataStarted) {
  1067. LOG(("WebSocket: data not started yet, no ping needed"));
  1068. return NS_OK;
  1069. }
  1070. return mSocketThread->Dispatch(
  1071. NewRunnableMethod(this, &WebSocketChannel::OnNetworkChanged),
  1072. NS_DISPATCH_NORMAL);
  1073. }
  1074. nsresult
  1075. WebSocketChannel::OnNetworkChanged()
  1076. {
  1077. MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "not socket thread");
  1078. LOG(("WebSocketChannel::OnNetworkChanged() - on socket thread %p", this));
  1079. if (mPingOutstanding) {
  1080. // If there's an outstanding ping that's expected to get a pong back
  1081. // we let that do its thing.
  1082. LOG(("WebSocket: pong already pending"));
  1083. return NS_OK;
  1084. }
  1085. if (mPingForced) {
  1086. // avoid more than one
  1087. LOG(("WebSocket: forced ping timer already fired"));
  1088. return NS_OK;
  1089. }
  1090. LOG(("nsWebSocketChannel:: Generating Ping as network changed\n"));
  1091. if (!mPingTimer) {
  1092. // The ping timer is only conditionally running already. If it wasn't
  1093. // already created do it here.
  1094. nsresult rv;
  1095. mPingTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
  1096. if (NS_FAILED(rv)) {
  1097. LOG(("WebSocket: unable to create ping timer!"));
  1098. NS_WARNING("unable to create ping timer!");
  1099. return rv;
  1100. }
  1101. }
  1102. // Trigger the ping timeout asap to fire off a new ping. Wait just
  1103. // a little bit to better avoid multi-triggers.
  1104. mPingForced = 1;
  1105. mPingTimer->InitWithCallback(this, 200, nsITimer::TYPE_ONE_SHOT);
  1106. return NS_OK;
  1107. }
  1108. void
  1109. WebSocketChannel::Shutdown()
  1110. {
  1111. nsWSAdmissionManager::Shutdown();
  1112. }
  1113. bool
  1114. WebSocketChannel::IsOnTargetThread()
  1115. {
  1116. MOZ_ASSERT(mTargetThread);
  1117. bool isOnTargetThread = false;
  1118. nsresult rv = mTargetThread->IsOnCurrentThread(&isOnTargetThread);
  1119. MOZ_ASSERT(NS_SUCCEEDED(rv));
  1120. return NS_FAILED(rv) ? false : isOnTargetThread;
  1121. }
  1122. void
  1123. WebSocketChannel::GetEffectiveURL(nsAString& aEffectiveURL) const
  1124. {
  1125. aEffectiveURL = mEffectiveURL;
  1126. }
  1127. bool
  1128. WebSocketChannel::IsEncrypted() const
  1129. {
  1130. return mEncrypted;
  1131. }
  1132. void
  1133. WebSocketChannel::BeginOpen(bool aCalledFromAdmissionManager)
  1134. {
  1135. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  1136. LOG(("WebSocketChannel::BeginOpen() %p\n", this));
  1137. // Important that we set CONNECTING_IN_PROGRESS before any call to
  1138. // AbortSession here: ensures that any remaining queued connection(s) are
  1139. // scheduled in OnStopSession
  1140. LOG(("Websocket: changing state to CONNECTING_IN_PROGRESS"));
  1141. mConnecting = CONNECTING_IN_PROGRESS;
  1142. if (aCalledFromAdmissionManager) {
  1143. // When called from nsWSAdmissionManager post an event to avoid potential
  1144. // re-entering of nsWSAdmissionManager and its lock.
  1145. NS_DispatchToMainThread(
  1146. NewRunnableMethod(this, &WebSocketChannel::BeginOpenInternal),
  1147. NS_DISPATCH_NORMAL);
  1148. } else {
  1149. BeginOpenInternal();
  1150. }
  1151. }
  1152. void
  1153. WebSocketChannel::BeginOpenInternal()
  1154. {
  1155. LOG(("WebSocketChannel::BeginOpenInternal() %p\n", this));
  1156. nsresult rv;
  1157. if (mRedirectCallback) {
  1158. LOG(("WebSocketChannel::BeginOpenInternal: Resuming Redirect\n"));
  1159. rv = mRedirectCallback->OnRedirectVerifyCallback(NS_OK);
  1160. mRedirectCallback = nullptr;
  1161. return;
  1162. }
  1163. nsCOMPtr<nsIChannel> localChannel = do_QueryInterface(mChannel, &rv);
  1164. if (NS_FAILED(rv)) {
  1165. LOG(("WebSocketChannel::BeginOpenInternal: cannot async open\n"));
  1166. AbortSession(NS_ERROR_UNEXPECTED);
  1167. return;
  1168. }
  1169. if (localChannel) {
  1170. NS_GetAppInfo(localChannel, &mAppId, &mIsInIsolatedMozBrowser);
  1171. }
  1172. rv = NS_MaybeOpenChannelUsingAsyncOpen2(localChannel, this);
  1173. if (NS_FAILED(rv)) {
  1174. LOG(("WebSocketChannel::BeginOpenInternal: cannot async open\n"));
  1175. AbortSession(NS_ERROR_CONNECTION_REFUSED);
  1176. return;
  1177. }
  1178. mOpenedHttpChannel = 1;
  1179. mOpenTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
  1180. if (NS_FAILED(rv)) {
  1181. LOG(("WebSocketChannel::BeginOpenInternal: cannot create open timer\n"));
  1182. AbortSession(NS_ERROR_UNEXPECTED);
  1183. return;
  1184. }
  1185. rv = mOpenTimer->InitWithCallback(this, mOpenTimeout,
  1186. nsITimer::TYPE_ONE_SHOT);
  1187. if (NS_FAILED(rv)) {
  1188. LOG(("WebSocketChannel::BeginOpenInternal: cannot initialize open "
  1189. "timer\n"));
  1190. AbortSession(NS_ERROR_UNEXPECTED);
  1191. return;
  1192. }
  1193. }
  1194. bool
  1195. WebSocketChannel::IsPersistentFramePtr()
  1196. {
  1197. return (mFramePtr >= mBuffer && mFramePtr < mBuffer + mBufferSize);
  1198. }
  1199. // Extends the internal buffer by count and returns the total
  1200. // amount of data available for read
  1201. //
  1202. // Accumulated fragment size is passed in instead of using the member
  1203. // variable beacuse when transitioning from the stack to the persistent
  1204. // read buffer we want to explicitly include them in the buffer instead
  1205. // of as already existing data.
  1206. bool
  1207. WebSocketChannel::UpdateReadBuffer(uint8_t *buffer, uint32_t count,
  1208. uint32_t accumulatedFragments,
  1209. uint32_t *available)
  1210. {
  1211. LOG(("WebSocketChannel::UpdateReadBuffer() %p [%p %u]\n",
  1212. this, buffer, count));
  1213. if (!mBuffered)
  1214. mFramePtr = mBuffer;
  1215. MOZ_ASSERT(IsPersistentFramePtr(), "update read buffer bad mFramePtr");
  1216. MOZ_ASSERT(mFramePtr - accumulatedFragments >= mBuffer,
  1217. "reserved FramePtr bad");
  1218. if (mBuffered + count <= mBufferSize) {
  1219. // append to existing buffer
  1220. LOG(("WebSocketChannel: update read buffer absorbed %u\n", count));
  1221. } else if (mBuffered + count -
  1222. (mFramePtr - accumulatedFragments - mBuffer) <= mBufferSize) {
  1223. // make room in existing buffer by shifting unused data to start
  1224. mBuffered -= (mFramePtr - mBuffer - accumulatedFragments);
  1225. LOG(("WebSocketChannel: update read buffer shifted %u\n", mBuffered));
  1226. ::memmove(mBuffer, mFramePtr - accumulatedFragments, mBuffered);
  1227. mFramePtr = mBuffer + accumulatedFragments;
  1228. } else {
  1229. // existing buffer is not sufficient, extend it
  1230. mBufferSize += count + 8192 + mBufferSize/3;
  1231. LOG(("WebSocketChannel: update read buffer extended to %u\n", mBufferSize));
  1232. uint8_t *old = mBuffer;
  1233. mBuffer = (uint8_t *)realloc(mBuffer, mBufferSize);
  1234. if (!mBuffer) {
  1235. mBuffer = old;
  1236. return false;
  1237. }
  1238. mFramePtr = mBuffer + (mFramePtr - old);
  1239. }
  1240. ::memcpy(mBuffer + mBuffered, buffer, count);
  1241. mBuffered += count;
  1242. if (available)
  1243. *available = mBuffered - (mFramePtr - mBuffer);
  1244. return true;
  1245. }
  1246. nsresult
  1247. WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count)
  1248. {
  1249. LOG(("WebSocketChannel::ProcessInput %p [%d %d]\n", this, count, mBuffered));
  1250. MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "not socket thread");
  1251. nsresult rv;
  1252. // The purpose of ping/pong is to actively probe the peer so that an
  1253. // unreachable peer is not mistaken for a period of idleness. This
  1254. // implementation accepts any application level read activity as a sign of
  1255. // life, it does not necessarily have to be a pong.
  1256. ResetPingTimer();
  1257. uint32_t avail;
  1258. if (!mBuffered) {
  1259. // Most of the time we can process right off the stack buffer without
  1260. // having to accumulate anything
  1261. mFramePtr = buffer;
  1262. avail = count;
  1263. } else {
  1264. if (!UpdateReadBuffer(buffer, count, mFragmentAccumulator, &avail)) {
  1265. return NS_ERROR_FILE_TOO_BIG;
  1266. }
  1267. }
  1268. uint8_t *payload;
  1269. uint32_t totalAvail = avail;
  1270. while (avail >= 2) {
  1271. int64_t payloadLength64 = mFramePtr[1] & kPayloadLengthBitsMask;
  1272. uint8_t finBit = mFramePtr[0] & kFinalFragBit;
  1273. uint8_t rsvBits = mFramePtr[0] & kRsvBitsMask;
  1274. uint8_t rsvBit1 = mFramePtr[0] & kRsv1Bit;
  1275. uint8_t rsvBit2 = mFramePtr[0] & kRsv2Bit;
  1276. uint8_t rsvBit3 = mFramePtr[0] & kRsv3Bit;
  1277. uint8_t opcode = mFramePtr[0] & kOpcodeBitsMask;
  1278. uint8_t maskBit = mFramePtr[1] & kMaskBit;
  1279. uint32_t mask = 0;
  1280. uint32_t framingLength = 2;
  1281. if (maskBit)
  1282. framingLength += 4;
  1283. if (payloadLength64 < 126) {
  1284. if (avail < framingLength)
  1285. break;
  1286. } else if (payloadLength64 == 126) {
  1287. // 16 bit length field
  1288. framingLength += 2;
  1289. if (avail < framingLength)
  1290. break;
  1291. payloadLength64 = mFramePtr[2] << 8 | mFramePtr[3];
  1292. } else {
  1293. // 64 bit length
  1294. framingLength += 8;
  1295. if (avail < framingLength)
  1296. break;
  1297. if (mFramePtr[2] & 0x80) {
  1298. // Section 4.2 says that the most significant bit MUST be
  1299. // 0. (i.e. this is really a 63 bit value)
  1300. LOG(("WebSocketChannel:: high bit of 64 bit length set"));
  1301. return NS_ERROR_ILLEGAL_VALUE;
  1302. }
  1303. // copy this in case it is unaligned
  1304. payloadLength64 = NetworkEndian::readInt64(mFramePtr + 2);
  1305. }
  1306. payload = mFramePtr + framingLength;
  1307. avail -= framingLength;
  1308. LOG(("WebSocketChannel::ProcessInput: payload %lld avail %lu\n",
  1309. payloadLength64, avail));
  1310. CheckedInt<int64_t> payloadLengthChecked(payloadLength64);
  1311. payloadLengthChecked += mFragmentAccumulator;
  1312. if (!payloadLengthChecked.isValid() || payloadLengthChecked.value() >
  1313. mMaxMessageSize) {
  1314. return NS_ERROR_FILE_TOO_BIG;
  1315. }
  1316. uint32_t payloadLength = static_cast<uint32_t>(payloadLength64);
  1317. if (avail < payloadLength)
  1318. break;
  1319. LOG(("WebSocketChannel::ProcessInput: Frame accumulated - opcode %d\n",
  1320. opcode));
  1321. if (!maskBit && mIsServerSide) {
  1322. LOG(("WebSocketChannel::ProcessInput: unmasked frame received "
  1323. "from client\n"));
  1324. return NS_ERROR_ILLEGAL_VALUE;
  1325. }
  1326. if (maskBit) {
  1327. if (!mIsServerSide) {
  1328. // The server should not be allowed to send masked frames to clients.
  1329. // But we've been allowing it for some time, so this should be
  1330. // deprecated with care.
  1331. LOG(("WebSocketChannel:: Client RECEIVING masked frame."));
  1332. }
  1333. mask = NetworkEndian::readUint32(payload - 4);
  1334. }
  1335. if (mask) {
  1336. ApplyMask(mask, payload, payloadLength);
  1337. } else if (mIsServerSide) {
  1338. LOG(("WebSocketChannel::ProcessInput: masked frame with mask 0 received"
  1339. "from client\n"));
  1340. return NS_ERROR_ILLEGAL_VALUE;
  1341. }
  1342. // Control codes are required to have the fin bit set
  1343. if (!finBit && (opcode & kControlFrameMask)) {
  1344. LOG(("WebSocketChannel:: fragmented control frame code %d\n", opcode));
  1345. return NS_ERROR_ILLEGAL_VALUE;
  1346. }
  1347. if (rsvBits) {
  1348. // PMCE sets RSV1 bit in the first fragment when the non-control frame
  1349. // is deflated
  1350. if (mPMCECompressor && rsvBits == kRsv1Bit && mFragmentAccumulator == 0 &&
  1351. !(opcode & kControlFrameMask)) {
  1352. mPMCECompressor->SetMessageDeflated();
  1353. LOG(("WebSocketChannel::ProcessInput: received deflated frame\n"));
  1354. } else {
  1355. LOG(("WebSocketChannel::ProcessInput: unexpected reserved bits %x\n",
  1356. rsvBits));
  1357. return NS_ERROR_ILLEGAL_VALUE;
  1358. }
  1359. }
  1360. if (!finBit || opcode == nsIWebSocketFrame::OPCODE_CONTINUATION) {
  1361. // This is part of a fragment response
  1362. // Only the first frame has a non zero op code: Make sure we don't see a
  1363. // first frame while some old fragments are open
  1364. if ((mFragmentAccumulator != 0) &&
  1365. (opcode != nsIWebSocketFrame::OPCODE_CONTINUATION)) {
  1366. LOG(("WebSocketChannel:: nested fragments\n"));
  1367. return NS_ERROR_ILLEGAL_VALUE;
  1368. }
  1369. LOG(("WebSocketChannel:: Accumulating Fragment %ld\n", payloadLength));
  1370. if (opcode == nsIWebSocketFrame::OPCODE_CONTINUATION) {
  1371. // Make sure this continuation fragment isn't the first fragment
  1372. if (mFragmentOpcode == nsIWebSocketFrame::OPCODE_CONTINUATION) {
  1373. LOG(("WebSocketHeandler:: continuation code in first fragment\n"));
  1374. return NS_ERROR_ILLEGAL_VALUE;
  1375. }
  1376. // For frag > 1 move the data body back on top of the headers
  1377. // so we have contiguous stream of data
  1378. MOZ_ASSERT(mFramePtr + framingLength == payload,
  1379. "payload offset from frameptr wrong");
  1380. ::memmove(mFramePtr, payload, avail);
  1381. payload = mFramePtr;
  1382. if (mBuffered)
  1383. mBuffered -= framingLength;
  1384. } else {
  1385. mFragmentOpcode = opcode;
  1386. }
  1387. if (finBit) {
  1388. LOG(("WebSocketChannel:: Finalizing Fragment\n"));
  1389. payload -= mFragmentAccumulator;
  1390. payloadLength += mFragmentAccumulator;
  1391. avail += mFragmentAccumulator;
  1392. mFragmentAccumulator = 0;
  1393. opcode = mFragmentOpcode;
  1394. // reset to detect if next message illegally starts with continuation
  1395. mFragmentOpcode = nsIWebSocketFrame::OPCODE_CONTINUATION;
  1396. } else {
  1397. opcode = nsIWebSocketFrame::OPCODE_CONTINUATION;
  1398. mFragmentAccumulator += payloadLength;
  1399. }
  1400. } else if (mFragmentAccumulator != 0 && !(opcode & kControlFrameMask)) {
  1401. // This frame is not part of a fragment sequence but we
  1402. // have an open fragment.. it must be a control code or else
  1403. // we have a problem
  1404. LOG(("WebSocketChannel:: illegal fragment sequence\n"));
  1405. return NS_ERROR_ILLEGAL_VALUE;
  1406. }
  1407. if (mServerClosed) {
  1408. LOG(("WebSocketChannel:: ignoring read frame code %d after close\n",
  1409. opcode));
  1410. // nop
  1411. } else if (mStopped) {
  1412. LOG(("WebSocketChannel:: ignoring read frame code %d after completion\n",
  1413. opcode));
  1414. } else if (opcode == nsIWebSocketFrame::OPCODE_TEXT) {
  1415. bool isDeflated = mPMCECompressor && mPMCECompressor->IsMessageDeflated();
  1416. LOG(("WebSocketChannel:: %stext frame received\n",
  1417. isDeflated ? "deflated " : ""));
  1418. if (mListenerMT) {
  1419. nsCString utf8Data;
  1420. if (isDeflated) {
  1421. rv = mPMCECompressor->Inflate(payload, payloadLength, utf8Data);
  1422. if (NS_FAILED(rv)) {
  1423. return rv;
  1424. }
  1425. LOG(("WebSocketChannel:: message successfully inflated "
  1426. "[origLength=%d, newLength=%d]\n", payloadLength,
  1427. utf8Data.Length()));
  1428. } else {
  1429. if (!utf8Data.Assign((const char *)payload, payloadLength,
  1430. mozilla::fallible)) {
  1431. return NS_ERROR_OUT_OF_MEMORY;
  1432. }
  1433. }
  1434. // Section 8.1 says to fail connection if invalid utf-8 in text message
  1435. if (!IsUTF8(utf8Data, false)) {
  1436. LOG(("WebSocketChannel:: text frame invalid utf-8\n"));
  1437. return NS_ERROR_CANNOT_CONVERT_DATA;
  1438. }
  1439. RefPtr<WebSocketFrame> frame =
  1440. mService->CreateFrameIfNeeded(finBit, rsvBit1, rsvBit2, rsvBit3,
  1441. opcode, maskBit, mask, utf8Data);
  1442. if (frame) {
  1443. mService->FrameReceived(mSerial, mInnerWindowID, frame.forget());
  1444. }
  1445. mTargetThread->Dispatch(new CallOnMessageAvailable(this, utf8Data, -1),
  1446. NS_DISPATCH_NORMAL);
  1447. if (mConnectionLogService && !mPrivateBrowsing) {
  1448. mConnectionLogService->NewMsgReceived(mHost, mSerial, count);
  1449. LOG(("Added new msg received for %s", mHost.get()));
  1450. }
  1451. }
  1452. } else if (opcode & kControlFrameMask) {
  1453. // control frames
  1454. if (payloadLength > 125) {
  1455. LOG(("WebSocketChannel:: bad control frame code %d length %d\n",
  1456. opcode, payloadLength));
  1457. return NS_ERROR_ILLEGAL_VALUE;
  1458. }
  1459. RefPtr<WebSocketFrame> frame =
  1460. mService->CreateFrameIfNeeded(finBit, rsvBit1, rsvBit2, rsvBit3,
  1461. opcode, maskBit, mask, payload,
  1462. payloadLength);
  1463. if (opcode == nsIWebSocketFrame::OPCODE_CLOSE) {
  1464. LOG(("WebSocketChannel:: close received\n"));
  1465. mServerClosed = 1;
  1466. mServerCloseCode = CLOSE_NO_STATUS;
  1467. if (payloadLength >= 2) {
  1468. mServerCloseCode = NetworkEndian::readUint16(payload);
  1469. LOG(("WebSocketChannel:: close recvd code %u\n", mServerCloseCode));
  1470. uint16_t msglen = static_cast<uint16_t>(payloadLength - 2);
  1471. if (msglen > 0) {
  1472. mServerCloseReason.SetLength(msglen);
  1473. memcpy(mServerCloseReason.BeginWriting(),
  1474. (const char *)payload + 2, msglen);
  1475. // section 8.1 says to replace received non utf-8 sequences
  1476. // (which are non-conformant to send) with u+fffd,
  1477. // but secteam feels that silently rewriting messages is
  1478. // inappropriate - so we will fail the connection instead.
  1479. if (!IsUTF8(mServerCloseReason, false)) {
  1480. LOG(("WebSocketChannel:: close frame invalid utf-8\n"));
  1481. return NS_ERROR_CANNOT_CONVERT_DATA;
  1482. }
  1483. LOG(("WebSocketChannel:: close msg %s\n",
  1484. mServerCloseReason.get()));
  1485. }
  1486. }
  1487. if (mCloseTimer) {
  1488. mCloseTimer->Cancel();
  1489. mCloseTimer = nullptr;
  1490. }
  1491. if (frame) {
  1492. // We send the frame immediately becuase we want to have it dispatched
  1493. // before the CallOnServerClose.
  1494. mService->FrameReceived(mSerial, mInnerWindowID, frame.forget());
  1495. frame = nullptr;
  1496. }
  1497. if (mListenerMT) {
  1498. mTargetThread->Dispatch(new CallOnServerClose(this, mServerCloseCode,
  1499. mServerCloseReason),
  1500. NS_DISPATCH_NORMAL);
  1501. }
  1502. if (mClientClosed)
  1503. ReleaseSession();
  1504. } else if (opcode == nsIWebSocketFrame::OPCODE_PING) {
  1505. LOG(("WebSocketChannel:: ping received\n"));
  1506. GeneratePong(payload, payloadLength);
  1507. } else if (opcode == nsIWebSocketFrame::OPCODE_PONG) {
  1508. // opcode OPCODE_PONG: the mere act of receiving the packet is all we
  1509. // need to do for the pong to trigger the activity timers
  1510. LOG(("WebSocketChannel:: pong received\n"));
  1511. } else {
  1512. /* unknown control frame opcode */
  1513. LOG(("WebSocketChannel:: unknown control op code %d\n", opcode));
  1514. return NS_ERROR_ILLEGAL_VALUE;
  1515. }
  1516. if (mFragmentAccumulator) {
  1517. // Remove the control frame from the stream so we have a contiguous
  1518. // data buffer of reassembled fragments
  1519. LOG(("WebSocketChannel:: Removing Control From Read buffer\n"));
  1520. MOZ_ASSERT(mFramePtr + framingLength == payload,
  1521. "payload offset from frameptr wrong");
  1522. ::memmove(mFramePtr, payload + payloadLength, avail - payloadLength);
  1523. payload = mFramePtr;
  1524. avail -= payloadLength;
  1525. if (mBuffered)
  1526. mBuffered -= framingLength + payloadLength;
  1527. payloadLength = 0;
  1528. }
  1529. if (frame) {
  1530. mService->FrameReceived(mSerial, mInnerWindowID, frame.forget());
  1531. }
  1532. } else if (opcode == nsIWebSocketFrame::OPCODE_BINARY) {
  1533. bool isDeflated = mPMCECompressor && mPMCECompressor->IsMessageDeflated();
  1534. LOG(("WebSocketChannel:: %sbinary frame received\n",
  1535. isDeflated ? "deflated " : ""));
  1536. if (mListenerMT) {
  1537. nsCString binaryData;
  1538. if (isDeflated) {
  1539. rv = mPMCECompressor->Inflate(payload, payloadLength, binaryData);
  1540. if (NS_FAILED(rv)) {
  1541. return rv;
  1542. }
  1543. LOG(("WebSocketChannel:: message successfully inflated "
  1544. "[origLength=%d, newLength=%d]\n", payloadLength,
  1545. binaryData.Length()));
  1546. } else {
  1547. if (!binaryData.Assign((const char *)payload, payloadLength,
  1548. mozilla::fallible)) {
  1549. return NS_ERROR_OUT_OF_MEMORY;
  1550. }
  1551. }
  1552. RefPtr<WebSocketFrame> frame =
  1553. mService->CreateFrameIfNeeded(finBit, rsvBit1, rsvBit2, rsvBit3,
  1554. opcode, maskBit, mask, binaryData);
  1555. if (frame) {
  1556. mService->FrameReceived(mSerial, mInnerWindowID, frame.forget());
  1557. }
  1558. mTargetThread->Dispatch(
  1559. new CallOnMessageAvailable(this, binaryData, binaryData.Length()),
  1560. NS_DISPATCH_NORMAL);
  1561. // To add the header to 'Networking Dashboard' log
  1562. if (mConnectionLogService && !mPrivateBrowsing) {
  1563. mConnectionLogService->NewMsgReceived(mHost, mSerial, count);
  1564. LOG(("Added new received msg for %s", mHost.get()));
  1565. }
  1566. }
  1567. } else if (opcode != nsIWebSocketFrame::OPCODE_CONTINUATION) {
  1568. /* unknown opcode */
  1569. LOG(("WebSocketChannel:: unknown op code %d\n", opcode));
  1570. return NS_ERROR_ILLEGAL_VALUE;
  1571. }
  1572. mFramePtr = payload + payloadLength;
  1573. avail -= payloadLength;
  1574. totalAvail = avail;
  1575. }
  1576. // Adjust the stateful buffer. If we were operating off the stack and
  1577. // now have a partial message then transition to the buffer, or if
  1578. // we were working off the buffer but no longer have any active state
  1579. // then transition to the stack
  1580. if (!IsPersistentFramePtr()) {
  1581. mBuffered = 0;
  1582. if (mFragmentAccumulator) {
  1583. LOG(("WebSocketChannel:: Setup Buffer due to fragment"));
  1584. if (!UpdateReadBuffer(mFramePtr - mFragmentAccumulator,
  1585. totalAvail + mFragmentAccumulator, 0, nullptr)) {
  1586. return NS_ERROR_FILE_TOO_BIG;
  1587. }
  1588. // UpdateReadBuffer will reset the frameptr to the beginning
  1589. // of new saved state, so we need to skip past processed framgents
  1590. mFramePtr += mFragmentAccumulator;
  1591. } else if (totalAvail) {
  1592. LOG(("WebSocketChannel:: Setup Buffer due to partial frame"));
  1593. if (!UpdateReadBuffer(mFramePtr, totalAvail, 0, nullptr)) {
  1594. return NS_ERROR_FILE_TOO_BIG;
  1595. }
  1596. }
  1597. } else if (!mFragmentAccumulator && !totalAvail) {
  1598. // If we were working off a saved buffer state and there is no partial
  1599. // frame or fragment in process, then revert to stack behavior
  1600. LOG(("WebSocketChannel:: Internal buffering not needed anymore"));
  1601. mBuffered = 0;
  1602. // release memory if we've been processing a large message
  1603. if (mBufferSize > kIncomingBufferStableSize) {
  1604. mBufferSize = kIncomingBufferStableSize;
  1605. free(mBuffer);
  1606. mBuffer = (uint8_t *)moz_xmalloc(mBufferSize);
  1607. }
  1608. }
  1609. return NS_OK;
  1610. }
  1611. /* static */ void
  1612. WebSocketChannel::ApplyMask(uint32_t mask, uint8_t *data, uint64_t len)
  1613. {
  1614. if (!data || len == 0)
  1615. return;
  1616. // Optimally we want to apply the mask 32 bits at a time,
  1617. // but the buffer might not be alligned. So we first deal with
  1618. // 0 to 3 bytes of preamble individually
  1619. while (len && (reinterpret_cast<uintptr_t>(data) & 3)) {
  1620. *data ^= mask >> 24;
  1621. mask = RotateLeft(mask, 8);
  1622. data++;
  1623. len--;
  1624. }
  1625. // perform mask on full words of data
  1626. uint32_t *iData = (uint32_t *) data;
  1627. uint32_t *end = iData + (len / 4);
  1628. NetworkEndian::writeUint32(&mask, mask);
  1629. for (; iData < end; iData++)
  1630. *iData ^= mask;
  1631. mask = NetworkEndian::readUint32(&mask);
  1632. data = (uint8_t *)iData;
  1633. len = len % 4;
  1634. // There maybe up to 3 trailing bytes that need to be dealt with
  1635. // individually
  1636. while (len) {
  1637. *data ^= mask >> 24;
  1638. mask = RotateLeft(mask, 8);
  1639. data++;
  1640. len--;
  1641. }
  1642. }
  1643. void
  1644. WebSocketChannel::GeneratePing()
  1645. {
  1646. nsCString *buf = new nsCString();
  1647. buf->AssignLiteral("PING");
  1648. EnqueueOutgoingMessage(mOutgoingPingMessages,
  1649. new OutboundMessage(kMsgTypePing, buf));
  1650. }
  1651. void
  1652. WebSocketChannel::GeneratePong(uint8_t *payload, uint32_t len)
  1653. {
  1654. nsCString *buf = new nsCString();
  1655. buf->SetLength(len);
  1656. if (buf->Length() < len) {
  1657. LOG(("WebSocketChannel::GeneratePong Allocation Failure\n"));
  1658. delete buf;
  1659. return;
  1660. }
  1661. memcpy(buf->BeginWriting(), payload, len);
  1662. EnqueueOutgoingMessage(mOutgoingPongMessages,
  1663. new OutboundMessage(kMsgTypePong, buf));
  1664. }
  1665. void
  1666. WebSocketChannel::EnqueueOutgoingMessage(nsDeque &aQueue,
  1667. OutboundMessage *aMsg)
  1668. {
  1669. MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "not socket thread");
  1670. LOG(("WebSocketChannel::EnqueueOutgoingMessage %p "
  1671. "queueing msg %p [type=%s len=%d]\n",
  1672. this, aMsg, msgNames[aMsg->GetMsgType()], aMsg->Length()));
  1673. aQueue.Push(aMsg);
  1674. OnOutputStreamReady(mSocketOut);
  1675. }
  1676. uint16_t
  1677. WebSocketChannel::ResultToCloseCode(nsresult resultCode)
  1678. {
  1679. if (NS_SUCCEEDED(resultCode))
  1680. return CLOSE_NORMAL;
  1681. switch (resultCode) {
  1682. case NS_ERROR_FILE_TOO_BIG:
  1683. case NS_ERROR_OUT_OF_MEMORY:
  1684. return CLOSE_TOO_LARGE;
  1685. case NS_ERROR_CANNOT_CONVERT_DATA:
  1686. return CLOSE_INVALID_PAYLOAD;
  1687. case NS_ERROR_UNEXPECTED:
  1688. return CLOSE_INTERNAL_ERROR;
  1689. default:
  1690. return CLOSE_PROTOCOL_ERROR;
  1691. }
  1692. }
  1693. void
  1694. WebSocketChannel::PrimeNewOutgoingMessage()
  1695. {
  1696. LOG(("WebSocketChannel::PrimeNewOutgoingMessage() %p\n", this));
  1697. MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "not socket thread");
  1698. MOZ_ASSERT(!mCurrentOut, "Current message in progress");
  1699. nsresult rv = NS_OK;
  1700. mCurrentOut = (OutboundMessage *)mOutgoingPongMessages.PopFront();
  1701. if (mCurrentOut) {
  1702. MOZ_ASSERT(mCurrentOut->GetMsgType() == kMsgTypePong,
  1703. "Not pong message!");
  1704. } else {
  1705. mCurrentOut = (OutboundMessage *)mOutgoingPingMessages.PopFront();
  1706. if (mCurrentOut)
  1707. MOZ_ASSERT(mCurrentOut->GetMsgType() == kMsgTypePing,
  1708. "Not ping message!");
  1709. else
  1710. mCurrentOut = (OutboundMessage *)mOutgoingMessages.PopFront();
  1711. }
  1712. if (!mCurrentOut)
  1713. return;
  1714. WsMsgType msgType = mCurrentOut->GetMsgType();
  1715. LOG(("WebSocketChannel::PrimeNewOutgoingMessage "
  1716. "%p found queued msg %p [type=%s len=%d]\n",
  1717. this, mCurrentOut, msgNames[msgType], mCurrentOut->Length()));
  1718. mCurrentOutSent = 0;
  1719. mHdrOut = mOutHeader;
  1720. uint8_t maskBit = mIsServerSide ? 0 : kMaskBit;
  1721. uint8_t maskSize = mIsServerSide ? 0 : 4;
  1722. uint8_t *payload = nullptr;
  1723. if (msgType == kMsgTypeFin) {
  1724. // This is a demand to create a close message
  1725. if (mClientClosed) {
  1726. DeleteCurrentOutGoingMessage();
  1727. PrimeNewOutgoingMessage();
  1728. return;
  1729. }
  1730. mClientClosed = 1;
  1731. mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_CLOSE;
  1732. mOutHeader[1] = maskBit;
  1733. // payload is offset 2 plus size of the mask
  1734. payload = mOutHeader + 2 + maskSize;
  1735. // The close reason code sits in the first 2 bytes of payload
  1736. // If the channel user provided a code and reason during Close()
  1737. // and there isn't an internal error, use that.
  1738. if (NS_SUCCEEDED(mStopOnClose)) {
  1739. if (mScriptCloseCode) {
  1740. NetworkEndian::writeUint16(payload, mScriptCloseCode);
  1741. mOutHeader[1] += 2;
  1742. mHdrOutToSend = 4 + maskSize;
  1743. if (!mScriptCloseReason.IsEmpty()) {
  1744. MOZ_ASSERT(mScriptCloseReason.Length() <= 123,
  1745. "Close Reason Too Long");
  1746. mOutHeader[1] += mScriptCloseReason.Length();
  1747. mHdrOutToSend += mScriptCloseReason.Length();
  1748. memcpy (payload + 2,
  1749. mScriptCloseReason.BeginReading(),
  1750. mScriptCloseReason.Length());
  1751. }
  1752. } else {
  1753. // No close code/reason, so payload length = 0. We must still send mask
  1754. // even though it's not used. Keep payload offset so we write mask
  1755. // below.
  1756. mHdrOutToSend = 2 + maskSize;
  1757. }
  1758. } else {
  1759. NetworkEndian::writeUint16(payload, ResultToCloseCode(mStopOnClose));
  1760. mOutHeader[1] += 2;
  1761. mHdrOutToSend = 4 + maskSize;
  1762. }
  1763. if (mServerClosed) {
  1764. /* bidi close complete */
  1765. mReleaseOnTransmit = 1;
  1766. } else if (NS_FAILED(mStopOnClose)) {
  1767. /* result of abort session - give up */
  1768. StopSession(mStopOnClose);
  1769. } else {
  1770. /* wait for reciprocal close from server */
  1771. mCloseTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
  1772. if (NS_SUCCEEDED(rv)) {
  1773. mCloseTimer->InitWithCallback(this, mCloseTimeout,
  1774. nsITimer::TYPE_ONE_SHOT);
  1775. } else {
  1776. StopSession(rv);
  1777. }
  1778. }
  1779. } else {
  1780. switch (msgType) {
  1781. case kMsgTypePong:
  1782. mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_PONG;
  1783. break;
  1784. case kMsgTypePing:
  1785. mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_PING;
  1786. break;
  1787. case kMsgTypeString:
  1788. mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_TEXT;
  1789. break;
  1790. case kMsgTypeStream:
  1791. // HACK ALERT: read in entire stream into string.
  1792. // Will block socket transport thread if file is blocking.
  1793. // TODO: bug 704447: don't block socket thread!
  1794. rv = mCurrentOut->ConvertStreamToString();
  1795. if (NS_FAILED(rv)) {
  1796. AbortSession(NS_ERROR_FILE_TOO_BIG);
  1797. return;
  1798. }
  1799. // Now we're a binary string
  1800. msgType = kMsgTypeBinaryString;
  1801. // no break: fall down into binary string case
  1802. MOZ_FALLTHROUGH;
  1803. case kMsgTypeBinaryString:
  1804. mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_BINARY;
  1805. break;
  1806. case kMsgTypeFin:
  1807. MOZ_ASSERT(false, "unreachable"); // avoid compiler warning
  1808. break;
  1809. }
  1810. // deflate the payload if PMCE is negotiated
  1811. if (mPMCECompressor &&
  1812. (msgType == kMsgTypeString || msgType == kMsgTypeBinaryString)) {
  1813. if (mCurrentOut->DeflatePayload(mPMCECompressor)) {
  1814. // The payload was deflated successfully, set RSV1 bit
  1815. mOutHeader[0] |= kRsv1Bit;
  1816. LOG(("WebSocketChannel::PrimeNewOutgoingMessage %p current msg %p was "
  1817. "deflated [origLength=%d, newLength=%d].\n", this, mCurrentOut,
  1818. mCurrentOut->OrigLength(), mCurrentOut->Length()));
  1819. }
  1820. }
  1821. if (mCurrentOut->Length() < 126) {
  1822. mOutHeader[1] = mCurrentOut->Length() | maskBit;
  1823. mHdrOutToSend = 2 + maskSize;
  1824. } else if (mCurrentOut->Length() <= 0xffff) {
  1825. mOutHeader[1] = 126 | maskBit;
  1826. NetworkEndian::writeUint16(mOutHeader + sizeof(uint16_t),
  1827. mCurrentOut->Length());
  1828. mHdrOutToSend = 4 + maskSize;
  1829. } else {
  1830. mOutHeader[1] = 127 | maskBit;
  1831. NetworkEndian::writeUint64(mOutHeader + 2, mCurrentOut->Length());
  1832. mHdrOutToSend = 10 + maskSize;
  1833. }
  1834. payload = mOutHeader + mHdrOutToSend;
  1835. }
  1836. MOZ_ASSERT(payload, "payload offset not found");
  1837. uint32_t mask = 0;
  1838. if (!mIsServerSide) {
  1839. // Perform the sending mask. Never use a zero mask
  1840. do {
  1841. uint8_t *buffer;
  1842. static_assert(4 == sizeof(mask), "Size of the mask should be equal to 4");
  1843. nsresult rv = mRandomGenerator->GenerateRandomBytes(sizeof(mask),
  1844. &buffer);
  1845. if (NS_FAILED(rv)) {
  1846. LOG(("WebSocketChannel::PrimeNewOutgoingMessage(): "
  1847. "GenerateRandomBytes failure %x\n", rv));
  1848. StopSession(rv);
  1849. return;
  1850. }
  1851. memcpy(&mask, buffer, sizeof(mask));
  1852. free(buffer);
  1853. } while (!mask);
  1854. NetworkEndian::writeUint32(payload - sizeof(uint32_t), mask);
  1855. }
  1856. LOG(("WebSocketChannel::PrimeNewOutgoingMessage() using mask %08x\n", mask));
  1857. // We don't mask the framing, but occasionally we stick a little payload
  1858. // data in the buffer used for the framing. Close frames are the current
  1859. // example. This data needs to be masked, but it is never more than a
  1860. // handful of bytes and might rotate the mask, so we can just do it locally.
  1861. // For real data frames we ship the bulk of the payload off to ApplyMask()
  1862. RefPtr<WebSocketFrame> frame =
  1863. mService->CreateFrameIfNeeded(
  1864. mOutHeader[0] & WebSocketChannel::kFinalFragBit,
  1865. mOutHeader[0] & WebSocketChannel::kRsv1Bit,
  1866. mOutHeader[0] & WebSocketChannel::kRsv2Bit,
  1867. mOutHeader[0] & WebSocketChannel::kRsv3Bit,
  1868. mOutHeader[0] & WebSocketChannel::kOpcodeBitsMask,
  1869. mOutHeader[1] & WebSocketChannel::kMaskBit,
  1870. mask,
  1871. payload, mHdrOutToSend - (payload - mOutHeader),
  1872. mCurrentOut->BeginOrigReading(),
  1873. mCurrentOut->OrigLength());
  1874. if (frame) {
  1875. mService->FrameSent(mSerial, mInnerWindowID, frame.forget());
  1876. }
  1877. if (mask) {
  1878. while (payload < (mOutHeader + mHdrOutToSend)) {
  1879. *payload ^= mask >> 24;
  1880. mask = RotateLeft(mask, 8);
  1881. payload++;
  1882. }
  1883. // Mask the real message payloads
  1884. ApplyMask(mask, mCurrentOut->BeginWriting(), mCurrentOut->Length());
  1885. }
  1886. int32_t len = mCurrentOut->Length();
  1887. // for small frames, copy it all together for a contiguous write
  1888. if (len && len <= kCopyBreak) {
  1889. memcpy(mOutHeader + mHdrOutToSend, mCurrentOut->BeginWriting(), len);
  1890. mHdrOutToSend += len;
  1891. mCurrentOutSent = len;
  1892. }
  1893. // Transmitting begins - mHdrOutToSend bytes from mOutHeader and
  1894. // mCurrentOut->Length() bytes from mCurrentOut. The latter may be
  1895. // coaleseced into the former for small messages or as the result of the
  1896. // compression process.
  1897. }
  1898. void
  1899. WebSocketChannel::DeleteCurrentOutGoingMessage()
  1900. {
  1901. delete mCurrentOut;
  1902. mCurrentOut = nullptr;
  1903. mCurrentOutSent = 0;
  1904. }
  1905. void
  1906. WebSocketChannel::EnsureHdrOut(uint32_t size)
  1907. {
  1908. LOG(("WebSocketChannel::EnsureHdrOut() %p [%d]\n", this, size));
  1909. if (mDynamicOutputSize < size) {
  1910. mDynamicOutputSize = size;
  1911. mDynamicOutput =
  1912. (uint8_t *) moz_xrealloc(mDynamicOutput, mDynamicOutputSize);
  1913. }
  1914. mHdrOut = mDynamicOutput;
  1915. }
  1916. namespace {
  1917. class RemoveObserverRunnable : public Runnable
  1918. {
  1919. RefPtr<WebSocketChannel> mChannel;
  1920. public:
  1921. explicit RemoveObserverRunnable(WebSocketChannel* aChannel)
  1922. : mChannel(aChannel)
  1923. {}
  1924. NS_IMETHOD Run() override
  1925. {
  1926. nsCOMPtr<nsIObserverService> observerService =
  1927. mozilla::services::GetObserverService();
  1928. if (!observerService) {
  1929. NS_WARNING("failed to get observer service");
  1930. return NS_OK;
  1931. }
  1932. observerService->RemoveObserver(mChannel, NS_NETWORK_LINK_TOPIC);
  1933. return NS_OK;
  1934. }
  1935. };
  1936. } // namespace
  1937. void
  1938. WebSocketChannel::CleanupConnection()
  1939. {
  1940. LOG(("WebSocketChannel::CleanupConnection() %p", this));
  1941. if (mLingeringCloseTimer) {
  1942. mLingeringCloseTimer->Cancel();
  1943. mLingeringCloseTimer = nullptr;
  1944. }
  1945. if (mSocketIn) {
  1946. mSocketIn->AsyncWait(nullptr, 0, 0, nullptr);
  1947. mSocketIn = nullptr;
  1948. }
  1949. if (mSocketOut) {
  1950. mSocketOut->AsyncWait(nullptr, 0, 0, nullptr);
  1951. mSocketOut = nullptr;
  1952. }
  1953. if (mTransport) {
  1954. mTransport->SetSecurityCallbacks(nullptr);
  1955. mTransport->SetEventSink(nullptr, nullptr);
  1956. mTransport->Close(NS_BASE_STREAM_CLOSED);
  1957. mTransport = nullptr;
  1958. }
  1959. if (mConnectionLogService && !mPrivateBrowsing) {
  1960. mConnectionLogService->RemoveHost(mHost, mSerial);
  1961. }
  1962. // This method can run in any thread, but the observer has to be removed on
  1963. // the main-thread.
  1964. NS_DispatchToMainThread(new RemoveObserverRunnable(this));
  1965. DecrementSessionCount();
  1966. }
  1967. void
  1968. WebSocketChannel::StopSession(nsresult reason)
  1969. {
  1970. LOG(("WebSocketChannel::StopSession() %p [%x]\n", this, reason));
  1971. // normally this should be called on socket thread, but it is ok to call it
  1972. // from OnStartRequest before the socket thread machine has gotten underway
  1973. mStopped = 1;
  1974. if (!mOpenedHttpChannel) {
  1975. // The HTTP channel information will never be used in this case
  1976. NS_ReleaseOnMainThread(mChannel.forget());
  1977. NS_ReleaseOnMainThread(mHttpChannel.forget());
  1978. NS_ReleaseOnMainThread(mLoadGroup.forget());
  1979. NS_ReleaseOnMainThread(mCallbacks.forget());
  1980. }
  1981. if (mCloseTimer) {
  1982. mCloseTimer->Cancel();
  1983. mCloseTimer = nullptr;
  1984. }
  1985. if (mOpenTimer) {
  1986. mOpenTimer->Cancel();
  1987. mOpenTimer = nullptr;
  1988. }
  1989. if (mReconnectDelayTimer) {
  1990. mReconnectDelayTimer->Cancel();
  1991. mReconnectDelayTimer = nullptr;
  1992. }
  1993. if (mPingTimer) {
  1994. mPingTimer->Cancel();
  1995. mPingTimer = nullptr;
  1996. }
  1997. if (mSocketIn && !mTCPClosed) {
  1998. // Drain, within reason, this socket. if we leave any data
  1999. // unconsumed (including the tcp fin) a RST will be generated
  2000. // The right thing to do here is shutdown(SHUT_WR) and then wait
  2001. // a little while to see if any data comes in.. but there is no
  2002. // reason to delay things for that when the websocket handshake
  2003. // is supposed to guarantee a quiet connection except for that fin.
  2004. char buffer[512];
  2005. uint32_t count = 0;
  2006. uint32_t total = 0;
  2007. nsresult rv;
  2008. do {
  2009. total += count;
  2010. rv = mSocketIn->Read(buffer, 512, &count);
  2011. if (rv != NS_BASE_STREAM_WOULD_BLOCK &&
  2012. (NS_FAILED(rv) || count == 0))
  2013. mTCPClosed = true;
  2014. } while (NS_SUCCEEDED(rv) && count > 0 && total < 32000);
  2015. }
  2016. int32_t sessionCount = kLingeringCloseThreshold;
  2017. nsWSAdmissionManager::GetSessionCount(sessionCount);
  2018. if (!mTCPClosed && mTransport && sessionCount < kLingeringCloseThreshold) {
  2019. // 7.1.1 says that the client SHOULD wait for the server to close the TCP
  2020. // connection. This is so we can reuse port numbers before 2 MSL expires,
  2021. // which is not really as much of a concern for us as the amount of state
  2022. // that might be accrued by keeping this channel object around waiting for
  2023. // the server. We handle the SHOULD by waiting a short time in the common
  2024. // case, but not waiting in the case of high concurrency.
  2025. //
  2026. // Normally this will be taken care of in AbortSession() after mTCPClosed
  2027. // is set when the server close arrives without waiting for the timeout to
  2028. // expire.
  2029. LOG(("WebSocketChannel::StopSession: Wait for Server TCP close"));
  2030. nsresult rv;
  2031. mLingeringCloseTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
  2032. if (NS_SUCCEEDED(rv))
  2033. mLingeringCloseTimer->InitWithCallback(this, kLingeringCloseTimeout,
  2034. nsITimer::TYPE_ONE_SHOT);
  2035. else
  2036. CleanupConnection();
  2037. } else {
  2038. CleanupConnection();
  2039. }
  2040. if (mCancelable) {
  2041. mCancelable->Cancel(NS_ERROR_UNEXPECTED);
  2042. mCancelable = nullptr;
  2043. }
  2044. mPMCECompressor = nullptr;
  2045. if (!mCalledOnStop) {
  2046. mCalledOnStop = 1;
  2047. nsWSAdmissionManager::OnStopSession(this, reason);
  2048. RefPtr<CallOnStop> runnable = new CallOnStop(this, reason);
  2049. mTargetThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
  2050. }
  2051. }
  2052. void
  2053. WebSocketChannel::AbortSession(nsresult reason)
  2054. {
  2055. LOG(("WebSocketChannel::AbortSession() %p [reason %x] stopped = %d\n",
  2056. this, reason, !!mStopped));
  2057. // normally this should be called on socket thread, but it is ok to call it
  2058. // from the main thread before StartWebsocketData() has completed
  2059. // When we are failing we need to close the TCP connection immediately
  2060. // as per 7.1.1
  2061. mTCPClosed = true;
  2062. if (mLingeringCloseTimer) {
  2063. MOZ_ASSERT(mStopped, "Lingering without Stop");
  2064. LOG(("WebSocketChannel:: Cleanup connection based on TCP Close"));
  2065. CleanupConnection();
  2066. return;
  2067. }
  2068. if (mStopped)
  2069. return;
  2070. mStopped = 1;
  2071. if (mTransport && reason != NS_BASE_STREAM_CLOSED && !mRequestedClose &&
  2072. !mClientClosed && !mServerClosed && mConnecting == NOT_CONNECTING) {
  2073. mRequestedClose = 1;
  2074. mStopOnClose = reason;
  2075. mSocketThread->Dispatch(
  2076. new OutboundEnqueuer(this, new OutboundMessage(kMsgTypeFin, nullptr)),
  2077. nsIEventTarget::DISPATCH_NORMAL);
  2078. } else {
  2079. StopSession(reason);
  2080. }
  2081. }
  2082. // ReleaseSession is called on orderly shutdown
  2083. void
  2084. WebSocketChannel::ReleaseSession()
  2085. {
  2086. LOG(("WebSocketChannel::ReleaseSession() %p stopped = %d\n",
  2087. this, !!mStopped));
  2088. MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "not socket thread");
  2089. if (mStopped)
  2090. return;
  2091. StopSession(NS_OK);
  2092. }
  2093. void
  2094. WebSocketChannel::IncrementSessionCount()
  2095. {
  2096. if (!mIncrementedSessionCount) {
  2097. nsWSAdmissionManager::IncrementSessionCount();
  2098. mIncrementedSessionCount = 1;
  2099. }
  2100. }
  2101. void
  2102. WebSocketChannel::DecrementSessionCount()
  2103. {
  2104. // Make sure we decrement session count only once, and only if we incremented it.
  2105. // This code is thread-safe: sWebSocketAdmissions->DecrementSessionCount is
  2106. // atomic, and mIncrementedSessionCount/mDecrementedSessionCount are set at
  2107. // times when they'll never be a race condition for checking/setting them.
  2108. if (mIncrementedSessionCount && !mDecrementedSessionCount) {
  2109. nsWSAdmissionManager::DecrementSessionCount();
  2110. mDecrementedSessionCount = 1;
  2111. }
  2112. }
  2113. namespace {
  2114. enum ExtensionParseMode { eParseServerSide, eParseClientSide };
  2115. }
  2116. static nsresult
  2117. ParseWebSocketExtension(const nsACString& aExtension,
  2118. ExtensionParseMode aMode,
  2119. bool& aClientNoContextTakeover,
  2120. bool& aServerNoContextTakeover,
  2121. int32_t& aClientMaxWindowBits,
  2122. int32_t& aServerMaxWindowBits)
  2123. {
  2124. nsCCharSeparatedTokenizer tokens(aExtension, ';');
  2125. if (!tokens.hasMoreTokens() ||
  2126. !tokens.nextToken().Equals(NS_LITERAL_CSTRING("permessage-deflate"))) {
  2127. LOG(("WebSocketChannel::ParseWebSocketExtension: "
  2128. "HTTP Sec-WebSocket-Extensions negotiated unknown value %s\n",
  2129. PromiseFlatCString(aExtension).get()));
  2130. return NS_ERROR_ILLEGAL_VALUE;
  2131. }
  2132. aClientNoContextTakeover = aServerNoContextTakeover = false;
  2133. aClientMaxWindowBits = aServerMaxWindowBits = -1;
  2134. while (tokens.hasMoreTokens()) {
  2135. auto token = tokens.nextToken();
  2136. int32_t nameEnd, valueStart;
  2137. int32_t delimPos = token.FindChar('=');
  2138. if (delimPos == kNotFound) {
  2139. nameEnd = token.Length();
  2140. valueStart = token.Length();
  2141. } else {
  2142. nameEnd = delimPos;
  2143. valueStart = delimPos + 1;
  2144. }
  2145. auto paramName = Substring(token, 0, nameEnd);
  2146. auto paramValue = Substring(token, valueStart);
  2147. if (paramName.EqualsLiteral("client_no_context_takeover")) {
  2148. if (!paramValue.IsEmpty()) {
  2149. LOG(("WebSocketChannel::ParseWebSocketExtension: parameter "
  2150. "client_no_context_takeover must not have value, found %s\n",
  2151. PromiseFlatCString(paramValue).get()));
  2152. return NS_ERROR_ILLEGAL_VALUE;
  2153. }
  2154. if (aClientNoContextTakeover) {
  2155. LOG(("WebSocketChannel::ParseWebSocketExtension: found multiple "
  2156. "parameters client_no_context_takeover\n"));
  2157. return NS_ERROR_ILLEGAL_VALUE;
  2158. }
  2159. aClientNoContextTakeover = true;
  2160. } else if (paramName.EqualsLiteral("server_no_context_takeover")) {
  2161. if (!paramValue.IsEmpty()) {
  2162. LOG(("WebSocketChannel::ParseWebSocketExtension: parameter "
  2163. "server_no_context_takeover must not have value, found %s\n",
  2164. PromiseFlatCString(paramValue).get()));
  2165. return NS_ERROR_ILLEGAL_VALUE;
  2166. }
  2167. if (aServerNoContextTakeover) {
  2168. LOG(("WebSocketChannel::ParseWebSocketExtension: found multiple "
  2169. "parameters server_no_context_takeover\n"));
  2170. return NS_ERROR_ILLEGAL_VALUE;
  2171. }
  2172. aServerNoContextTakeover = true;
  2173. } else if (paramName.EqualsLiteral("client_max_window_bits")) {
  2174. if (aClientMaxWindowBits != -1) {
  2175. LOG(("WebSocketChannel::ParseWebSocketExtension: found multiple "
  2176. "parameters client_max_window_bits\n"));
  2177. return NS_ERROR_ILLEGAL_VALUE;
  2178. }
  2179. if (aMode == eParseServerSide && paramValue.IsEmpty()) {
  2180. // Use -2 to indicate that "client_max_window_bits" has been parsed,
  2181. // but had no value.
  2182. aClientMaxWindowBits = -2;
  2183. }
  2184. else {
  2185. nsresult errcode;
  2186. aClientMaxWindowBits =
  2187. PromiseFlatCString(paramValue).ToInteger(&errcode);
  2188. if (NS_FAILED(errcode) || aClientMaxWindowBits < 8 ||
  2189. aClientMaxWindowBits > 15) {
  2190. LOG(("WebSocketChannel::ParseWebSocketExtension: found invalid "
  2191. "parameter client_max_window_bits %s\n",
  2192. PromiseFlatCString(paramValue).get()));
  2193. return NS_ERROR_ILLEGAL_VALUE;
  2194. }
  2195. }
  2196. } else if (paramName.EqualsLiteral("server_max_window_bits")) {
  2197. if (aServerMaxWindowBits != -1) {
  2198. LOG(("WebSocketChannel::ParseWebSocketExtension: found multiple "
  2199. "parameters server_max_window_bits\n"));
  2200. return NS_ERROR_ILLEGAL_VALUE;
  2201. }
  2202. nsresult errcode;
  2203. aServerMaxWindowBits =
  2204. PromiseFlatCString(paramValue).ToInteger(&errcode);
  2205. if (NS_FAILED(errcode) || aServerMaxWindowBits < 8 ||
  2206. aServerMaxWindowBits > 15) {
  2207. LOG(("WebSocketChannel::ParseWebSocketExtension: found invalid "
  2208. "parameter server_max_window_bits %s\n",
  2209. PromiseFlatCString(paramValue).get()));
  2210. return NS_ERROR_ILLEGAL_VALUE;
  2211. }
  2212. } else {
  2213. LOG(("WebSocketChannel::ParseWebSocketExtension: found unknown "
  2214. "parameter %s\n", PromiseFlatCString(paramName).get()));
  2215. return NS_ERROR_ILLEGAL_VALUE;
  2216. }
  2217. }
  2218. if (aClientMaxWindowBits == -2) {
  2219. aClientMaxWindowBits = -1;
  2220. }
  2221. return NS_OK;
  2222. }
  2223. nsresult
  2224. WebSocketChannel::HandleExtensions()
  2225. {
  2226. LOG(("WebSocketChannel::HandleExtensions() %p\n", this));
  2227. nsresult rv;
  2228. nsAutoCString extensions;
  2229. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  2230. rv = mHttpChannel->GetResponseHeader(
  2231. NS_LITERAL_CSTRING("Sec-WebSocket-Extensions"), extensions);
  2232. extensions.CompressWhitespace();
  2233. if (extensions.IsEmpty()) {
  2234. return NS_OK;
  2235. }
  2236. LOG(("WebSocketChannel::HandleExtensions: received "
  2237. "Sec-WebSocket-Extensions header: %s\n", extensions.get()));
  2238. bool clientNoContextTakeover;
  2239. bool serverNoContextTakeover;
  2240. int32_t clientMaxWindowBits;
  2241. int32_t serverMaxWindowBits;
  2242. rv = ParseWebSocketExtension(extensions,
  2243. eParseClientSide,
  2244. clientNoContextTakeover,
  2245. serverNoContextTakeover,
  2246. clientMaxWindowBits,
  2247. serverMaxWindowBits);
  2248. if (NS_FAILED(rv)) {
  2249. AbortSession(rv);
  2250. return rv;
  2251. }
  2252. if (!mAllowPMCE) {
  2253. LOG(("WebSocketChannel::HandleExtensions: "
  2254. "Recvd permessage-deflate which wasn't offered\n"));
  2255. AbortSession(NS_ERROR_ILLEGAL_VALUE);
  2256. return NS_ERROR_ILLEGAL_VALUE;
  2257. }
  2258. if (clientMaxWindowBits == -1) {
  2259. clientMaxWindowBits = 15;
  2260. }
  2261. if (serverMaxWindowBits == -1) {
  2262. serverMaxWindowBits = 15;
  2263. }
  2264. mPMCECompressor = new PMCECompression(clientNoContextTakeover,
  2265. clientMaxWindowBits,
  2266. serverMaxWindowBits);
  2267. if (mPMCECompressor->Active()) {
  2268. LOG(("WebSocketChannel::HandleExtensions: PMCE negotiated, %susing "
  2269. "context takeover, clientMaxWindowBits=%d, "
  2270. "serverMaxWindowBits=%d\n",
  2271. clientNoContextTakeover ? "NOT " : "", clientMaxWindowBits,
  2272. serverMaxWindowBits));
  2273. mNegotiatedExtensions = "permessage-deflate";
  2274. } else {
  2275. LOG(("WebSocketChannel::HandleExtensions: Cannot init PMCE "
  2276. "compression object\n"));
  2277. mPMCECompressor = nullptr;
  2278. AbortSession(NS_ERROR_UNEXPECTED);
  2279. return NS_ERROR_UNEXPECTED;
  2280. }
  2281. return NS_OK;
  2282. }
  2283. void
  2284. ProcessServerWebSocketExtensions(const nsACString& aExtensions,
  2285. nsACString& aNegotiatedExtensions)
  2286. {
  2287. aNegotiatedExtensions.Truncate();
  2288. nsCOMPtr<nsIPrefBranch> prefService =
  2289. do_GetService(NS_PREFSERVICE_CONTRACTID);
  2290. if (prefService) {
  2291. bool boolpref;
  2292. nsresult rv = prefService->
  2293. GetBoolPref("network.websocket.extensions.permessage-deflate", &boolpref);
  2294. if (NS_SUCCEEDED(rv) && !boolpref) {
  2295. return;
  2296. }
  2297. }
  2298. nsCCharSeparatedTokenizer extList(aExtensions, ',');
  2299. while (extList.hasMoreTokens()) {
  2300. bool clientNoContextTakeover;
  2301. bool serverNoContextTakeover;
  2302. int32_t clientMaxWindowBits;
  2303. int32_t serverMaxWindowBits;
  2304. nsresult rv = ParseWebSocketExtension(extList.nextToken(),
  2305. eParseServerSide,
  2306. clientNoContextTakeover,
  2307. serverNoContextTakeover,
  2308. clientMaxWindowBits,
  2309. serverMaxWindowBits);
  2310. if (NS_FAILED(rv)) {
  2311. // Ignore extensions that we can't parse
  2312. continue;
  2313. }
  2314. aNegotiatedExtensions.AssignLiteral("permessage-deflate");
  2315. if (clientNoContextTakeover) {
  2316. aNegotiatedExtensions.AppendLiteral(";client_no_context_takeover");
  2317. }
  2318. if (serverNoContextTakeover) {
  2319. aNegotiatedExtensions.AppendLiteral(";server_no_context_takeover");
  2320. }
  2321. if (clientMaxWindowBits != -1) {
  2322. aNegotiatedExtensions.AppendLiteral(";client_max_window_bits=");
  2323. aNegotiatedExtensions.AppendInt(clientMaxWindowBits);
  2324. }
  2325. if (serverMaxWindowBits != -1) {
  2326. aNegotiatedExtensions.AppendLiteral(";server_max_window_bits=");
  2327. aNegotiatedExtensions.AppendInt(serverMaxWindowBits);
  2328. }
  2329. return;
  2330. }
  2331. }
  2332. nsresult
  2333. CalculateWebSocketHashedSecret(const nsACString& aKey, nsACString& aHash)
  2334. {
  2335. nsresult rv;
  2336. nsCString key =
  2337. aKey + NS_LITERAL_CSTRING("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
  2338. nsCOMPtr<nsICryptoHash> hasher =
  2339. do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID, &rv);
  2340. NS_ENSURE_SUCCESS(rv, rv);
  2341. rv = hasher->Init(nsICryptoHash::SHA1);
  2342. NS_ENSURE_SUCCESS(rv, rv);
  2343. rv = hasher->Update((const uint8_t *)key.BeginWriting(), key.Length());
  2344. NS_ENSURE_SUCCESS(rv, rv);
  2345. return hasher->Finish(true, aHash);
  2346. }
  2347. nsresult
  2348. WebSocketChannel::SetupRequest()
  2349. {
  2350. LOG(("WebSocketChannel::SetupRequest() %p\n", this));
  2351. nsresult rv;
  2352. if (mLoadGroup) {
  2353. rv = mHttpChannel->SetLoadGroup(mLoadGroup);
  2354. NS_ENSURE_SUCCESS(rv, rv);
  2355. }
  2356. rv = mHttpChannel->SetLoadFlags(nsIRequest::LOAD_BACKGROUND |
  2357. nsIRequest::INHIBIT_CACHING |
  2358. nsIRequest::LOAD_BYPASS_CACHE |
  2359. nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
  2360. NS_ENSURE_SUCCESS(rv, rv);
  2361. // we never let websockets be blocked by head CSS/JS loads to avoid
  2362. // potential deadlock where server generation of CSS/JS requires
  2363. // an XHR signal.
  2364. nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(mChannel));
  2365. if (cos) {
  2366. cos->AddClassFlags(nsIClassOfService::Unblocked);
  2367. }
  2368. // draft-ietf-hybi-thewebsocketprotocol-07 illustrates Upgrade: websocket
  2369. // in lower case, so go with that. It is technically case insensitive.
  2370. rv = mChannel->HTTPUpgrade(NS_LITERAL_CSTRING("websocket"), this);
  2371. NS_ENSURE_SUCCESS(rv, rv);
  2372. mHttpChannel->SetRequestHeader(
  2373. NS_LITERAL_CSTRING("Sec-WebSocket-Version"),
  2374. NS_LITERAL_CSTRING(SEC_WEBSOCKET_VERSION), false);
  2375. if (!mOrigin.IsEmpty())
  2376. mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Origin"), mOrigin,
  2377. false);
  2378. if (!mProtocol.IsEmpty())
  2379. mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Sec-WebSocket-Protocol"),
  2380. mProtocol, true);
  2381. if (mAllowPMCE)
  2382. mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Sec-WebSocket-Extensions"),
  2383. NS_LITERAL_CSTRING("permessage-deflate"),
  2384. false);
  2385. uint8_t *secKey;
  2386. nsAutoCString secKeyString;
  2387. rv = mRandomGenerator->GenerateRandomBytes(16, &secKey);
  2388. NS_ENSURE_SUCCESS(rv, rv);
  2389. char* b64 = PL_Base64Encode((const char *)secKey, 16, nullptr);
  2390. free(secKey);
  2391. if (!b64)
  2392. return NS_ERROR_OUT_OF_MEMORY;
  2393. secKeyString.Assign(b64);
  2394. PR_Free(b64);
  2395. mHttpChannel->SetRequestHeader(NS_LITERAL_CSTRING("Sec-WebSocket-Key"),
  2396. secKeyString, false);
  2397. LOG(("WebSocketChannel::SetupRequest: client key %s\n", secKeyString.get()));
  2398. // prepare the value we expect to see in
  2399. // the sec-websocket-accept response header
  2400. rv = CalculateWebSocketHashedSecret(secKeyString, mHashedSecret);
  2401. NS_ENSURE_SUCCESS(rv, rv);
  2402. LOG(("WebSocketChannel::SetupRequest: expected server key %s\n",
  2403. mHashedSecret.get()));
  2404. return NS_OK;
  2405. }
  2406. nsresult
  2407. WebSocketChannel::DoAdmissionDNS()
  2408. {
  2409. nsresult rv;
  2410. nsCString hostName;
  2411. rv = mURI->GetHost(hostName);
  2412. NS_ENSURE_SUCCESS(rv, rv);
  2413. mAddress = hostName;
  2414. rv = mURI->GetPort(&mPort);
  2415. NS_ENSURE_SUCCESS(rv, rv);
  2416. if (mPort == -1)
  2417. mPort = (mEncrypted ? kDefaultWSSPort : kDefaultWSPort);
  2418. nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID, &rv);
  2419. NS_ENSURE_SUCCESS(rv, rv);
  2420. nsCOMPtr<nsIThread> mainThread;
  2421. NS_GetMainThread(getter_AddRefs(mainThread));
  2422. MOZ_ASSERT(!mCancelable);
  2423. return dns->AsyncResolve(hostName, 0, this, mainThread, getter_AddRefs(mCancelable));
  2424. }
  2425. nsresult
  2426. WebSocketChannel::ApplyForAdmission()
  2427. {
  2428. LOG(("WebSocketChannel::ApplyForAdmission() %p\n", this));
  2429. // Websockets has a policy of 1 session at a time being allowed in the
  2430. // CONNECTING state per server IP address (not hostname)
  2431. // Check to see if a proxy is being used before making DNS call
  2432. nsCOMPtr<nsIProtocolProxyService> pps =
  2433. do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID);
  2434. if (!pps) {
  2435. // go straight to DNS
  2436. // expect the callback in ::OnLookupComplete
  2437. LOG(("WebSocketChannel::ApplyForAdmission: checking for concurrent open\n"));
  2438. return DoAdmissionDNS();
  2439. }
  2440. MOZ_ASSERT(!mCancelable);
  2441. nsresult rv;
  2442. rv = pps->AsyncResolve(mHttpChannel,
  2443. nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
  2444. nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL,
  2445. this, getter_AddRefs(mCancelable));
  2446. NS_ASSERTION(NS_FAILED(rv) || mCancelable,
  2447. "nsIProtocolProxyService::AsyncResolve succeeded but didn't "
  2448. "return a cancelable object!");
  2449. return rv;
  2450. }
  2451. // Called after both OnStartRequest and OnTransportAvailable have
  2452. // executed. This essentially ends the handshake and starts the websockets
  2453. // protocol state machine.
  2454. nsresult
  2455. WebSocketChannel::StartWebsocketData()
  2456. {
  2457. nsresult rv;
  2458. if (!IsOnTargetThread()) {
  2459. return mTargetThread->Dispatch(
  2460. NewRunnableMethod(this, &WebSocketChannel::StartWebsocketData),
  2461. NS_DISPATCH_NORMAL);
  2462. }
  2463. LOG(("WebSocketChannel::StartWebsocketData() %p", this));
  2464. MOZ_ASSERT(!mDataStarted, "StartWebsocketData twice");
  2465. mDataStarted = 1;
  2466. rv = mSocketIn->AsyncWait(this, 0, 0, mSocketThread);
  2467. if (NS_FAILED(rv)) {
  2468. LOG(("WebSocketChannel::StartWebsocketData mSocketIn->AsyncWait() failed "
  2469. "with error 0x%08x", rv));
  2470. return mSocketThread->Dispatch(
  2471. NewRunnableMethod<nsresult>(this,
  2472. &WebSocketChannel::AbortSession,
  2473. rv),
  2474. NS_DISPATCH_NORMAL);
  2475. }
  2476. if (mPingInterval) {
  2477. rv = mSocketThread->Dispatch(
  2478. NewRunnableMethod(this, &WebSocketChannel::StartPinging),
  2479. NS_DISPATCH_NORMAL);
  2480. if (NS_FAILED(rv)) {
  2481. LOG(("WebSocketChannel::StartWebsocketData Could not start pinging, "
  2482. "rv=0x%08x", rv));
  2483. return rv;
  2484. }
  2485. }
  2486. LOG(("WebSocketChannel::StartWebsocketData Notifying Listener %p",
  2487. mListenerMT ? mListenerMT->mListener.get() : nullptr));
  2488. if (mListenerMT) {
  2489. mListenerMT->mListener->OnStart(mListenerMT->mContext);
  2490. }
  2491. return NS_OK;
  2492. }
  2493. nsresult
  2494. WebSocketChannel::StartPinging()
  2495. {
  2496. LOG(("WebSocketChannel::StartPinging() %p", this));
  2497. MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "not socket thread");
  2498. MOZ_ASSERT(mPingInterval);
  2499. MOZ_ASSERT(!mPingTimer);
  2500. nsresult rv;
  2501. mPingTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
  2502. if (NS_FAILED(rv)) {
  2503. NS_WARNING("unable to create ping timer. Carrying on.");
  2504. } else {
  2505. LOG(("WebSocketChannel will generate ping after %d ms of receive silence\n",
  2506. mPingInterval));
  2507. mPingTimer->InitWithCallback(this, mPingInterval, nsITimer::TYPE_ONE_SHOT);
  2508. }
  2509. return NS_OK;
  2510. }
  2511. void
  2512. WebSocketChannel::ReportConnectionTelemetry()
  2513. {
  2514. // 3 bits are used. high bit is for wss, middle bit for failed,
  2515. // and low bit for proxy..
  2516. // 0 - 7 : ws-ok-plain, ws-ok-proxy, ws-failed-plain, ws-failed-proxy,
  2517. // wss-ok-plain, wss-ok-proxy, wss-failed-plain, wss-failed-proxy
  2518. bool didProxy = false;
  2519. nsCOMPtr<nsIProxyInfo> pi;
  2520. nsCOMPtr<nsIProxiedChannel> pc = do_QueryInterface(mChannel);
  2521. if (pc)
  2522. pc->GetProxyInfo(getter_AddRefs(pi));
  2523. if (pi) {
  2524. nsAutoCString proxyType;
  2525. pi->GetType(proxyType);
  2526. if (!proxyType.IsEmpty() &&
  2527. !proxyType.EqualsLiteral("direct"))
  2528. didProxy = true;
  2529. }
  2530. uint8_t value = (mEncrypted ? (1 << 2) : 0) |
  2531. (!mGotUpgradeOK ? (1 << 1) : 0) |
  2532. (didProxy ? (1 << 0) : 0);
  2533. LOG(("WebSocketChannel::ReportConnectionTelemetry() %p %d", this, value));
  2534. }
  2535. // nsIDNSListener
  2536. NS_IMETHODIMP
  2537. WebSocketChannel::OnLookupComplete(nsICancelable *aRequest,
  2538. nsIDNSRecord *aRecord,
  2539. nsresult aStatus)
  2540. {
  2541. LOG(("WebSocketChannel::OnLookupComplete() %p [%p %p %x]\n",
  2542. this, aRequest, aRecord, aStatus));
  2543. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  2544. if (mStopped) {
  2545. LOG(("WebSocketChannel::OnLookupComplete: Request Already Stopped\n"));
  2546. mCancelable = nullptr;
  2547. return NS_OK;
  2548. }
  2549. mCancelable = nullptr;
  2550. // These failures are not fatal - we just use the hostname as the key
  2551. if (NS_FAILED(aStatus)) {
  2552. LOG(("WebSocketChannel::OnLookupComplete: No DNS Response\n"));
  2553. // set host in case we got here without calling DoAdmissionDNS()
  2554. mURI->GetHost(mAddress);
  2555. } else {
  2556. nsresult rv = aRecord->GetNextAddrAsString(mAddress);
  2557. if (NS_FAILED(rv))
  2558. LOG(("WebSocketChannel::OnLookupComplete: Failed GetNextAddr\n"));
  2559. }
  2560. LOG(("WebSocket OnLookupComplete: Proceeding to ConditionallyConnect\n"));
  2561. nsWSAdmissionManager::ConditionallyConnect(this);
  2562. return NS_OK;
  2563. }
  2564. // nsIProtocolProxyCallback
  2565. NS_IMETHODIMP
  2566. WebSocketChannel::OnProxyAvailable(nsICancelable *aRequest, nsIChannel *aChannel,
  2567. nsIProxyInfo *pi, nsresult status)
  2568. {
  2569. if (mStopped) {
  2570. LOG(("WebSocketChannel::OnProxyAvailable: [%p] Request Already Stopped\n", this));
  2571. mCancelable = nullptr;
  2572. return NS_OK;
  2573. }
  2574. MOZ_ASSERT(!mCancelable || (aRequest == mCancelable));
  2575. mCancelable = nullptr;
  2576. nsAutoCString type;
  2577. if (NS_SUCCEEDED(status) && pi &&
  2578. NS_SUCCEEDED(pi->GetType(type)) &&
  2579. !type.EqualsLiteral("direct")) {
  2580. LOG(("WebSocket OnProxyAvailable [%p] Proxy found skip DNS lookup\n", this));
  2581. // call DNS callback directly without DNS resolver
  2582. OnLookupComplete(nullptr, nullptr, NS_ERROR_FAILURE);
  2583. } else {
  2584. LOG(("WebSocketChannel::OnProxyAvailable[%p] checking DNS resolution\n", this));
  2585. nsresult rv = DoAdmissionDNS();
  2586. if (NS_FAILED(rv)) {
  2587. LOG(("WebSocket OnProxyAvailable [%p] DNS lookup failed\n", this));
  2588. // call DNS callback directly without DNS resolver
  2589. OnLookupComplete(nullptr, nullptr, NS_ERROR_FAILURE);
  2590. }
  2591. }
  2592. return NS_OK;
  2593. }
  2594. // nsIInterfaceRequestor
  2595. NS_IMETHODIMP
  2596. WebSocketChannel::GetInterface(const nsIID & iid, void **result)
  2597. {
  2598. LOG(("WebSocketChannel::GetInterface() %p\n", this));
  2599. if (iid.Equals(NS_GET_IID(nsIChannelEventSink)))
  2600. return QueryInterface(iid, result);
  2601. if (mCallbacks)
  2602. return mCallbacks->GetInterface(iid, result);
  2603. return NS_ERROR_FAILURE;
  2604. }
  2605. // nsIChannelEventSink
  2606. NS_IMETHODIMP
  2607. WebSocketChannel::AsyncOnChannelRedirect(
  2608. nsIChannel *oldChannel,
  2609. nsIChannel *newChannel,
  2610. uint32_t flags,
  2611. nsIAsyncVerifyRedirectCallback *callback)
  2612. {
  2613. LOG(("WebSocketChannel::AsyncOnChannelRedirect() %p\n", this));
  2614. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  2615. nsresult rv;
  2616. nsCOMPtr<nsIURI> newuri;
  2617. rv = newChannel->GetURI(getter_AddRefs(newuri));
  2618. NS_ENSURE_SUCCESS(rv, rv);
  2619. // newuri is expected to be http or https
  2620. bool newuriIsHttps = false;
  2621. rv = newuri->SchemeIs("https", &newuriIsHttps);
  2622. NS_ENSURE_SUCCESS(rv, rv);
  2623. if (!mAutoFollowRedirects) {
  2624. // Even if redirects configured off, still allow them for HTTP Strict
  2625. // Transport Security (from ws://FOO to https://FOO (mapped to wss://FOO)
  2626. if (!(flags & (nsIChannelEventSink::REDIRECT_INTERNAL |
  2627. nsIChannelEventSink::REDIRECT_STS_UPGRADE))) {
  2628. nsAutoCString newSpec;
  2629. rv = newuri->GetSpec(newSpec);
  2630. NS_ENSURE_SUCCESS(rv, rv);
  2631. LOG(("WebSocketChannel: Redirect to %s denied by configuration\n",
  2632. newSpec.get()));
  2633. return NS_ERROR_FAILURE;
  2634. }
  2635. }
  2636. if (mEncrypted && !newuriIsHttps) {
  2637. nsAutoCString spec;
  2638. if (NS_SUCCEEDED(newuri->GetSpec(spec)))
  2639. LOG(("WebSocketChannel: Redirect to %s violates encryption rule\n",
  2640. spec.get()));
  2641. return NS_ERROR_FAILURE;
  2642. }
  2643. nsCOMPtr<nsIHttpChannel> newHttpChannel = do_QueryInterface(newChannel, &rv);
  2644. if (NS_FAILED(rv)) {
  2645. LOG(("WebSocketChannel: Redirect could not QI to HTTP\n"));
  2646. return rv;
  2647. }
  2648. nsCOMPtr<nsIHttpChannelInternal> newUpgradeChannel =
  2649. do_QueryInterface(newChannel, &rv);
  2650. if (NS_FAILED(rv)) {
  2651. LOG(("WebSocketChannel: Redirect could not QI to HTTP Upgrade\n"));
  2652. return rv;
  2653. }
  2654. // The redirect is likely OK
  2655. newChannel->SetNotificationCallbacks(this);
  2656. mEncrypted = newuriIsHttps;
  2657. newuri->Clone(getter_AddRefs(mURI));
  2658. if (mEncrypted)
  2659. rv = mURI->SetScheme(NS_LITERAL_CSTRING("wss"));
  2660. else
  2661. rv = mURI->SetScheme(NS_LITERAL_CSTRING("ws"));
  2662. mHttpChannel = newHttpChannel;
  2663. mChannel = newUpgradeChannel;
  2664. rv = SetupRequest();
  2665. if (NS_FAILED(rv)) {
  2666. LOG(("WebSocketChannel: Redirect could not SetupRequest()\n"));
  2667. return rv;
  2668. }
  2669. // Redirected-to URI may need to be delayed by 1-connecting-per-host and
  2670. // delay-after-fail algorithms. So hold off calling OnRedirectVerifyCallback
  2671. // until BeginOpen, when we know it's OK to proceed with new channel.
  2672. mRedirectCallback = callback;
  2673. // Mark old channel as successfully connected so we'll clear any FailDelay
  2674. // associated with the old URI. Note: no need to also call OnStopSession:
  2675. // it's a no-op for successful, already-connected channels.
  2676. nsWSAdmissionManager::OnConnected(this);
  2677. // ApplyForAdmission as if we were starting from fresh...
  2678. mAddress.Truncate();
  2679. mOpenedHttpChannel = 0;
  2680. rv = ApplyForAdmission();
  2681. if (NS_FAILED(rv)) {
  2682. LOG(("WebSocketChannel: Redirect failed due to DNS failure\n"));
  2683. mRedirectCallback = nullptr;
  2684. return rv;
  2685. }
  2686. return NS_OK;
  2687. }
  2688. // nsITimerCallback
  2689. NS_IMETHODIMP
  2690. WebSocketChannel::Notify(nsITimer *timer)
  2691. {
  2692. LOG(("WebSocketChannel::Notify() %p [%p]\n", this, timer));
  2693. if (timer == mCloseTimer) {
  2694. MOZ_ASSERT(mClientClosed, "Close Timeout without local close");
  2695. MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread,
  2696. "not socket thread");
  2697. mCloseTimer = nullptr;
  2698. if (mStopped || mServerClosed) /* no longer relevant */
  2699. return NS_OK;
  2700. LOG(("WebSocketChannel:: Expecting Server Close - Timed Out\n"));
  2701. AbortSession(NS_ERROR_NET_TIMEOUT);
  2702. } else if (timer == mOpenTimer) {
  2703. MOZ_ASSERT(!mGotUpgradeOK,
  2704. "Open Timer after open complete");
  2705. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  2706. mOpenTimer = nullptr;
  2707. LOG(("WebSocketChannel:: Connection Timed Out\n"));
  2708. if (mStopped || mServerClosed) /* no longer relevant */
  2709. return NS_OK;
  2710. AbortSession(NS_ERROR_NET_TIMEOUT);
  2711. } else if (timer == mReconnectDelayTimer) {
  2712. MOZ_ASSERT(mConnecting == CONNECTING_DELAYED,
  2713. "woke up from delay w/o being delayed?");
  2714. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  2715. mReconnectDelayTimer = nullptr;
  2716. LOG(("WebSocketChannel: connecting [this=%p] after reconnect delay", this));
  2717. BeginOpen(false);
  2718. } else if (timer == mPingTimer) {
  2719. MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread,
  2720. "not socket thread");
  2721. if (mClientClosed || mServerClosed || mRequestedClose) {
  2722. // no point in worrying about ping now
  2723. mPingTimer = nullptr;
  2724. return NS_OK;
  2725. }
  2726. if (!mPingOutstanding) {
  2727. // Ping interval must be non-null or PING was forced by OnNetworkChanged()
  2728. MOZ_ASSERT(mPingInterval || mPingForced);
  2729. LOG(("nsWebSocketChannel:: Generating Ping\n"));
  2730. mPingOutstanding = 1;
  2731. mPingForced = 0;
  2732. mPingTimer->InitWithCallback(this, mPingResponseTimeout,
  2733. nsITimer::TYPE_ONE_SHOT);
  2734. GeneratePing();
  2735. } else {
  2736. LOG(("nsWebSocketChannel:: Timed out Ping\n"));
  2737. mPingTimer = nullptr;
  2738. AbortSession(NS_ERROR_NET_TIMEOUT);
  2739. }
  2740. } else if (timer == mLingeringCloseTimer) {
  2741. LOG(("WebSocketChannel:: Lingering Close Timer"));
  2742. CleanupConnection();
  2743. } else {
  2744. MOZ_ASSERT(0, "Unknown Timer");
  2745. }
  2746. return NS_OK;
  2747. }
  2748. // nsIWebSocketChannel
  2749. NS_IMETHODIMP
  2750. WebSocketChannel::GetSecurityInfo(nsISupports **aSecurityInfo)
  2751. {
  2752. LOG(("WebSocketChannel::GetSecurityInfo() %p\n", this));
  2753. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  2754. if (mTransport) {
  2755. if (NS_FAILED(mTransport->GetSecurityInfo(aSecurityInfo)))
  2756. *aSecurityInfo = nullptr;
  2757. }
  2758. return NS_OK;
  2759. }
  2760. NS_IMETHODIMP
  2761. WebSocketChannel::AsyncOpen(nsIURI *aURI,
  2762. const nsACString &aOrigin,
  2763. uint64_t aInnerWindowID,
  2764. nsIWebSocketListener *aListener,
  2765. nsISupports *aContext)
  2766. {
  2767. LOG(("WebSocketChannel::AsyncOpen() %p\n", this));
  2768. if (!NS_IsMainThread()) {
  2769. MOZ_ASSERT(false, "not main thread");
  2770. LOG(("WebSocketChannel::AsyncOpen() called off the main thread"));
  2771. return NS_ERROR_UNEXPECTED;
  2772. }
  2773. if ((!aURI && !mIsServerSide) || !aListener) {
  2774. LOG(("WebSocketChannel::AsyncOpen() Uri or Listener null"));
  2775. return NS_ERROR_UNEXPECTED;
  2776. }
  2777. if (mListenerMT || mWasOpened)
  2778. return NS_ERROR_ALREADY_OPENED;
  2779. nsresult rv;
  2780. // Ensure target thread is set.
  2781. if (!mTargetThread) {
  2782. mTargetThread = do_GetMainThread();
  2783. }
  2784. mSocketThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
  2785. if (NS_FAILED(rv)) {
  2786. NS_WARNING("unable to continue without socket transport service");
  2787. return rv;
  2788. }
  2789. nsCOMPtr<nsIPrefBranch> prefService;
  2790. prefService = do_GetService(NS_PREFSERVICE_CONTRACTID);
  2791. if (prefService) {
  2792. int32_t intpref;
  2793. bool boolpref;
  2794. rv = prefService->GetIntPref("network.websocket.max-message-size",
  2795. &intpref);
  2796. if (NS_SUCCEEDED(rv)) {
  2797. mMaxMessageSize = clamped(intpref, 1024, INT32_MAX);
  2798. }
  2799. rv = prefService->GetIntPref("network.websocket.timeout.close", &intpref);
  2800. if (NS_SUCCEEDED(rv)) {
  2801. mCloseTimeout = clamped(intpref, 1, 1800) * 1000;
  2802. }
  2803. rv = prefService->GetIntPref("network.websocket.timeout.open", &intpref);
  2804. if (NS_SUCCEEDED(rv)) {
  2805. mOpenTimeout = clamped(intpref, 1, 1800) * 1000;
  2806. }
  2807. rv = prefService->GetIntPref("network.websocket.timeout.ping.request",
  2808. &intpref);
  2809. if (NS_SUCCEEDED(rv) && !mClientSetPingInterval) {
  2810. mPingInterval = clamped(intpref, 0, 86400) * 1000;
  2811. }
  2812. rv = prefService->GetIntPref("network.websocket.timeout.ping.response",
  2813. &intpref);
  2814. if (NS_SUCCEEDED(rv) && !mClientSetPingTimeout) {
  2815. mPingResponseTimeout = clamped(intpref, 1, 3600) * 1000;
  2816. }
  2817. rv = prefService->GetBoolPref("network.websocket.extensions.permessage-deflate",
  2818. &boolpref);
  2819. if (NS_SUCCEEDED(rv)) {
  2820. mAllowPMCE = boolpref ? 1 : 0;
  2821. }
  2822. rv = prefService->GetBoolPref("network.websocket.auto-follow-http-redirects",
  2823. &boolpref);
  2824. if (NS_SUCCEEDED(rv)) {
  2825. mAutoFollowRedirects = boolpref ? 1 : 0;
  2826. }
  2827. rv = prefService->GetIntPref
  2828. ("network.websocket.max-connections", &intpref);
  2829. if (NS_SUCCEEDED(rv)) {
  2830. mMaxConcurrentConnections = clamped(intpref, 1, 0xffff);
  2831. }
  2832. }
  2833. int32_t sessionCount = -1;
  2834. nsWSAdmissionManager::GetSessionCount(sessionCount);
  2835. if (sessionCount >= 0) {
  2836. LOG(("WebSocketChannel::AsyncOpen %p sessionCount=%d max=%d\n", this,
  2837. sessionCount, mMaxConcurrentConnections));
  2838. }
  2839. if (sessionCount >= mMaxConcurrentConnections) {
  2840. LOG(("WebSocketChannel: max concurrency %d exceeded (%d)",
  2841. mMaxConcurrentConnections,
  2842. sessionCount));
  2843. // WebSocket connections are expected to be long lived, so return
  2844. // an error here instead of queueing
  2845. return NS_ERROR_SOCKET_CREATE_FAILED;
  2846. }
  2847. mInnerWindowID = aInnerWindowID;
  2848. mOriginalURI = aURI;
  2849. mURI = mOriginalURI;
  2850. mOrigin = aOrigin;
  2851. if (mIsServerSide) {
  2852. //IncrementSessionCount();
  2853. mWasOpened = 1;
  2854. mListenerMT = new ListenerAndContextContainer(aListener, aContext);
  2855. mServerTransportProvider->SetListener(this);
  2856. mServerTransportProvider = nullptr;
  2857. return NS_OK;
  2858. }
  2859. mURI->GetHostPort(mHost);
  2860. mRandomGenerator =
  2861. do_GetService("@mozilla.org/security/random-generator;1", &rv);
  2862. if (NS_FAILED(rv)) {
  2863. NS_WARNING("unable to continue without random number generator");
  2864. return rv;
  2865. }
  2866. nsCOMPtr<nsIURI> localURI;
  2867. nsCOMPtr<nsIChannel> localChannel;
  2868. mURI->Clone(getter_AddRefs(localURI));
  2869. if (mEncrypted)
  2870. rv = localURI->SetScheme(NS_LITERAL_CSTRING("https"));
  2871. else
  2872. rv = localURI->SetScheme(NS_LITERAL_CSTRING("http"));
  2873. NS_ENSURE_SUCCESS(rv, rv);
  2874. nsCOMPtr<nsIIOService> ioService;
  2875. ioService = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
  2876. if (NS_FAILED(rv)) {
  2877. NS_WARNING("unable to continue without io service");
  2878. return rv;
  2879. }
  2880. nsCOMPtr<nsIIOService2> io2 = do_QueryInterface(ioService, &rv);
  2881. if (NS_FAILED(rv)) {
  2882. NS_WARNING("WebSocketChannel: unable to continue without ioservice2");
  2883. return rv;
  2884. }
  2885. // Ideally we'd call newChannelFromURIWithLoadInfo here, but that doesn't
  2886. // allow setting proxy uri/flags
  2887. rv = io2->NewChannelFromURIWithProxyFlags2(
  2888. localURI,
  2889. mURI,
  2890. nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
  2891. nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL,
  2892. mLoadInfo->LoadingNode() ?
  2893. mLoadInfo->LoadingNode()->AsDOMNode() : nullptr,
  2894. mLoadInfo->LoadingPrincipal(),
  2895. mLoadInfo->TriggeringPrincipal(),
  2896. mLoadInfo->GetSecurityFlags(),
  2897. mLoadInfo->InternalContentPolicyType(),
  2898. getter_AddRefs(localChannel));
  2899. NS_ENSURE_SUCCESS(rv, rv);
  2900. // Please note that we still call SetLoadInfo on the channel because
  2901. // we want the same instance of the loadInfo to be set on the channel.
  2902. rv = localChannel->SetLoadInfo(mLoadInfo);
  2903. NS_ENSURE_SUCCESS(rv, rv);
  2904. // Pass most GetInterface() requests through to our instantiator, but handle
  2905. // nsIChannelEventSink in this object in order to deal with redirects
  2906. localChannel->SetNotificationCallbacks(this);
  2907. class MOZ_STACK_CLASS CleanUpOnFailure
  2908. {
  2909. public:
  2910. explicit CleanUpOnFailure(WebSocketChannel* aWebSocketChannel)
  2911. : mWebSocketChannel(aWebSocketChannel)
  2912. {}
  2913. ~CleanUpOnFailure()
  2914. {
  2915. if (!mWebSocketChannel->mWasOpened) {
  2916. mWebSocketChannel->mChannel = nullptr;
  2917. mWebSocketChannel->mHttpChannel = nullptr;
  2918. }
  2919. }
  2920. WebSocketChannel *mWebSocketChannel;
  2921. };
  2922. CleanUpOnFailure cuof(this);
  2923. mChannel = do_QueryInterface(localChannel, &rv);
  2924. NS_ENSURE_SUCCESS(rv, rv);
  2925. mHttpChannel = do_QueryInterface(localChannel, &rv);
  2926. NS_ENSURE_SUCCESS(rv, rv);
  2927. rv = SetupRequest();
  2928. if (NS_FAILED(rv))
  2929. return rv;
  2930. mPrivateBrowsing = NS_UsePrivateBrowsing(localChannel);
  2931. if (mConnectionLogService && !mPrivateBrowsing) {
  2932. mConnectionLogService->AddHost(mHost, mSerial,
  2933. BaseWebSocketChannel::mEncrypted);
  2934. }
  2935. rv = ApplyForAdmission();
  2936. if (NS_FAILED(rv))
  2937. return rv;
  2938. // Register for prefs change notifications
  2939. nsCOMPtr<nsIObserverService> observerService =
  2940. mozilla::services::GetObserverService();
  2941. if (!observerService) {
  2942. NS_WARNING("failed to get observer service");
  2943. return NS_ERROR_FAILURE;
  2944. }
  2945. rv = observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC, false);
  2946. if (NS_WARN_IF(NS_FAILED(rv))) {
  2947. return rv;
  2948. }
  2949. // Only set these if the open was successful:
  2950. //
  2951. mWasOpened = 1;
  2952. mListenerMT = new ListenerAndContextContainer(aListener, aContext);
  2953. IncrementSessionCount();
  2954. return rv;
  2955. }
  2956. NS_IMETHODIMP
  2957. WebSocketChannel::Close(uint16_t code, const nsACString & reason)
  2958. {
  2959. LOG(("WebSocketChannel::Close() %p\n", this));
  2960. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  2961. // save the networkstats (bug 855949)
  2962. SaveNetworkStats(true);
  2963. if (mRequestedClose) {
  2964. return NS_OK;
  2965. }
  2966. // The API requires the UTF-8 string to be 123 or less bytes
  2967. if (reason.Length() > 123)
  2968. return NS_ERROR_ILLEGAL_VALUE;
  2969. mRequestedClose = 1;
  2970. mScriptCloseReason = reason;
  2971. mScriptCloseCode = code;
  2972. if (!mTransport || mConnecting != NOT_CONNECTING) {
  2973. nsresult rv;
  2974. if (code == CLOSE_GOING_AWAY) {
  2975. // Not an error: for example, tab has closed or navigated away
  2976. LOG(("WebSocketChannel::Close() GOING_AWAY without transport."));
  2977. rv = NS_OK;
  2978. } else {
  2979. LOG(("WebSocketChannel::Close() without transport - error."));
  2980. rv = NS_ERROR_NOT_CONNECTED;
  2981. }
  2982. StopSession(rv);
  2983. return rv;
  2984. }
  2985. return mSocketThread->Dispatch(
  2986. new OutboundEnqueuer(this, new OutboundMessage(kMsgTypeFin, nullptr)),
  2987. nsIEventTarget::DISPATCH_NORMAL);
  2988. }
  2989. NS_IMETHODIMP
  2990. WebSocketChannel::SendMsg(const nsACString &aMsg)
  2991. {
  2992. LOG(("WebSocketChannel::SendMsg() %p\n", this));
  2993. return SendMsgCommon(&aMsg, false, aMsg.Length());
  2994. }
  2995. NS_IMETHODIMP
  2996. WebSocketChannel::SendBinaryMsg(const nsACString &aMsg)
  2997. {
  2998. LOG(("WebSocketChannel::SendBinaryMsg() %p len=%d\n", this, aMsg.Length()));
  2999. return SendMsgCommon(&aMsg, true, aMsg.Length());
  3000. }
  3001. NS_IMETHODIMP
  3002. WebSocketChannel::SendBinaryStream(nsIInputStream *aStream, uint32_t aLength)
  3003. {
  3004. LOG(("WebSocketChannel::SendBinaryStream() %p\n", this));
  3005. return SendMsgCommon(nullptr, true, aLength, aStream);
  3006. }
  3007. nsresult
  3008. WebSocketChannel::SendMsgCommon(const nsACString *aMsg, bool aIsBinary,
  3009. uint32_t aLength, nsIInputStream *aStream)
  3010. {
  3011. MOZ_ASSERT(IsOnTargetThread(), "not target thread");
  3012. if (!mDataStarted) {
  3013. LOG(("WebSocketChannel:: Error: data not started yet\n"));
  3014. return NS_ERROR_UNEXPECTED;
  3015. }
  3016. if (mRequestedClose) {
  3017. LOG(("WebSocketChannel:: Error: send when closed\n"));
  3018. return NS_ERROR_UNEXPECTED;
  3019. }
  3020. if (mStopped) {
  3021. LOG(("WebSocketChannel:: Error: send when stopped\n"));
  3022. return NS_ERROR_NOT_CONNECTED;
  3023. }
  3024. MOZ_ASSERT(mMaxMessageSize >= 0, "max message size negative");
  3025. if (aLength > static_cast<uint32_t>(mMaxMessageSize)) {
  3026. LOG(("WebSocketChannel:: Error: message too big\n"));
  3027. return NS_ERROR_FILE_TOO_BIG;
  3028. }
  3029. if (mConnectionLogService && !mPrivateBrowsing) {
  3030. mConnectionLogService->NewMsgSent(mHost, mSerial, aLength);
  3031. LOG(("Added new msg sent for %s", mHost.get()));
  3032. }
  3033. return mSocketThread->Dispatch(
  3034. aStream ? new OutboundEnqueuer(this, new OutboundMessage(aStream, aLength))
  3035. : new OutboundEnqueuer(this,
  3036. new OutboundMessage(aIsBinary ? kMsgTypeBinaryString
  3037. : kMsgTypeString,
  3038. new nsCString(*aMsg))),
  3039. nsIEventTarget::DISPATCH_NORMAL);
  3040. }
  3041. // nsIHttpUpgradeListener
  3042. NS_IMETHODIMP
  3043. WebSocketChannel::OnTransportAvailable(nsISocketTransport *aTransport,
  3044. nsIAsyncInputStream *aSocketIn,
  3045. nsIAsyncOutputStream *aSocketOut)
  3046. {
  3047. if (!NS_IsMainThread()) {
  3048. return NS_DispatchToMainThread(new CallOnTransportAvailable(this,
  3049. aTransport,
  3050. aSocketIn,
  3051. aSocketOut));
  3052. }
  3053. LOG(("WebSocketChannel::OnTransportAvailable %p [%p %p %p] rcvdonstart=%d\n",
  3054. this, aTransport, aSocketIn, aSocketOut, mGotUpgradeOK));
  3055. if (mStopped) {
  3056. LOG(("WebSocketChannel::OnTransportAvailable: Already stopped"));
  3057. return NS_OK;
  3058. }
  3059. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  3060. MOZ_ASSERT(!mRecvdHttpUpgradeTransport, "OTA duplicated");
  3061. MOZ_ASSERT(aSocketIn, "OTA with invalid socketIn");
  3062. mTransport = aTransport;
  3063. mSocketIn = aSocketIn;
  3064. mSocketOut = aSocketOut;
  3065. nsresult rv;
  3066. rv = mTransport->SetEventSink(nullptr, nullptr);
  3067. if (NS_FAILED(rv)) return rv;
  3068. rv = mTransport->SetSecurityCallbacks(this);
  3069. if (NS_FAILED(rv)) return rv;
  3070. mRecvdHttpUpgradeTransport = 1;
  3071. if (mGotUpgradeOK) {
  3072. // We're now done CONNECTING, which means we can now open another,
  3073. // perhaps parallel, connection to the same host if one
  3074. // is pending
  3075. nsWSAdmissionManager::OnConnected(this);
  3076. return StartWebsocketData();
  3077. }
  3078. if (mIsServerSide) {
  3079. if (!mNegotiatedExtensions.IsEmpty()) {
  3080. bool clientNoContextTakeover;
  3081. bool serverNoContextTakeover;
  3082. int32_t clientMaxWindowBits;
  3083. int32_t serverMaxWindowBits;
  3084. rv = ParseWebSocketExtension(mNegotiatedExtensions,
  3085. eParseServerSide,
  3086. clientNoContextTakeover,
  3087. serverNoContextTakeover,
  3088. clientMaxWindowBits,
  3089. serverMaxWindowBits);
  3090. MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv), "illegal value provided by server");
  3091. if (clientMaxWindowBits == -1) {
  3092. clientMaxWindowBits = 15;
  3093. }
  3094. if (serverMaxWindowBits == -1) {
  3095. serverMaxWindowBits = 15;
  3096. }
  3097. mPMCECompressor = new PMCECompression(serverNoContextTakeover,
  3098. serverMaxWindowBits,
  3099. clientMaxWindowBits);
  3100. if (mPMCECompressor->Active()) {
  3101. LOG(("WebSocketChannel::OnTransportAvailable: PMCE negotiated, %susing "
  3102. "context takeover, serverMaxWindowBits=%d, "
  3103. "clientMaxWindowBits=%d\n",
  3104. serverNoContextTakeover ? "NOT " : "", serverMaxWindowBits,
  3105. clientMaxWindowBits));
  3106. mNegotiatedExtensions = "permessage-deflate";
  3107. } else {
  3108. LOG(("WebSocketChannel::OnTransportAvailable: Cannot init PMCE "
  3109. "compression object\n"));
  3110. mPMCECompressor = nullptr;
  3111. AbortSession(NS_ERROR_UNEXPECTED);
  3112. return NS_ERROR_UNEXPECTED;
  3113. }
  3114. }
  3115. return StartWebsocketData();
  3116. }
  3117. return NS_OK;
  3118. }
  3119. // nsIRequestObserver (from nsIStreamListener)
  3120. NS_IMETHODIMP
  3121. WebSocketChannel::OnStartRequest(nsIRequest *aRequest,
  3122. nsISupports *aContext)
  3123. {
  3124. LOG(("WebSocketChannel::OnStartRequest(): %p [%p %p] recvdhttpupgrade=%d\n",
  3125. this, aRequest, mHttpChannel.get(), mRecvdHttpUpgradeTransport));
  3126. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  3127. MOZ_ASSERT(!mGotUpgradeOK, "OTA duplicated");
  3128. if (mOpenTimer) {
  3129. mOpenTimer->Cancel();
  3130. mOpenTimer = nullptr;
  3131. }
  3132. if (mStopped) {
  3133. LOG(("WebSocketChannel::OnStartRequest: Channel Already Done\n"));
  3134. AbortSession(NS_ERROR_CONNECTION_REFUSED);
  3135. return NS_ERROR_CONNECTION_REFUSED;
  3136. }
  3137. nsresult rv;
  3138. uint32_t status;
  3139. char *val, *token;
  3140. rv = mHttpChannel->GetResponseStatus(&status);
  3141. if (NS_FAILED(rv)) {
  3142. LOG(("WebSocketChannel::OnStartRequest: No HTTP Response\n"));
  3143. AbortSession(NS_ERROR_CONNECTION_REFUSED);
  3144. return NS_ERROR_CONNECTION_REFUSED;
  3145. }
  3146. LOG(("WebSocketChannel::OnStartRequest: HTTP status %d\n", status));
  3147. if (status != 101) {
  3148. AbortSession(NS_ERROR_CONNECTION_REFUSED);
  3149. return NS_ERROR_CONNECTION_REFUSED;
  3150. }
  3151. nsAutoCString respUpgrade;
  3152. rv = mHttpChannel->GetResponseHeader(
  3153. NS_LITERAL_CSTRING("Upgrade"), respUpgrade);
  3154. if (NS_SUCCEEDED(rv)) {
  3155. rv = NS_ERROR_ILLEGAL_VALUE;
  3156. if (!respUpgrade.IsEmpty()) {
  3157. val = respUpgrade.BeginWriting();
  3158. while ((token = nsCRT::strtok(val, ", \t", &val))) {
  3159. if (PL_strcasecmp(token, "Websocket") == 0) {
  3160. rv = NS_OK;
  3161. break;
  3162. }
  3163. }
  3164. }
  3165. }
  3166. if (NS_FAILED(rv)) {
  3167. LOG(("WebSocketChannel::OnStartRequest: "
  3168. "HTTP response header Upgrade: websocket not found\n"));
  3169. AbortSession(NS_ERROR_ILLEGAL_VALUE);
  3170. return rv;
  3171. }
  3172. nsAutoCString respConnection;
  3173. rv = mHttpChannel->GetResponseHeader(
  3174. NS_LITERAL_CSTRING("Connection"), respConnection);
  3175. if (NS_SUCCEEDED(rv)) {
  3176. rv = NS_ERROR_ILLEGAL_VALUE;
  3177. if (!respConnection.IsEmpty()) {
  3178. val = respConnection.BeginWriting();
  3179. while ((token = nsCRT::strtok(val, ", \t", &val))) {
  3180. if (PL_strcasecmp(token, "Upgrade") == 0) {
  3181. rv = NS_OK;
  3182. break;
  3183. }
  3184. }
  3185. }
  3186. }
  3187. if (NS_FAILED(rv)) {
  3188. LOG(("WebSocketChannel::OnStartRequest: "
  3189. "HTTP response header 'Connection: Upgrade' not found\n"));
  3190. AbortSession(NS_ERROR_ILLEGAL_VALUE);
  3191. return rv;
  3192. }
  3193. nsAutoCString respAccept;
  3194. rv = mHttpChannel->GetResponseHeader(
  3195. NS_LITERAL_CSTRING("Sec-WebSocket-Accept"),
  3196. respAccept);
  3197. if (NS_FAILED(rv) ||
  3198. respAccept.IsEmpty() || !respAccept.Equals(mHashedSecret)) {
  3199. LOG(("WebSocketChannel::OnStartRequest: "
  3200. "HTTP response header Sec-WebSocket-Accept check failed\n"));
  3201. LOG(("WebSocketChannel::OnStartRequest: Expected %s received %s\n",
  3202. mHashedSecret.get(), respAccept.get()));
  3203. AbortSession(NS_ERROR_ILLEGAL_VALUE);
  3204. return NS_ERROR_ILLEGAL_VALUE;
  3205. }
  3206. // If we sent a sub protocol header, verify the response matches
  3207. // If it does not, set mProtocol to "" so the protocol attribute
  3208. // of the WebSocket JS object reflects that
  3209. if (!mProtocol.IsEmpty()) {
  3210. nsAutoCString respProtocol;
  3211. rv = mHttpChannel->GetResponseHeader(
  3212. NS_LITERAL_CSTRING("Sec-WebSocket-Protocol"),
  3213. respProtocol);
  3214. if (NS_SUCCEEDED(rv)) {
  3215. rv = NS_ERROR_ILLEGAL_VALUE;
  3216. val = mProtocol.BeginWriting();
  3217. while ((token = nsCRT::strtok(val, ", \t", &val))) {
  3218. if (PL_strcasecmp(token, respProtocol.get()) == 0) {
  3219. rv = NS_OK;
  3220. break;
  3221. }
  3222. }
  3223. if (NS_SUCCEEDED(rv)) {
  3224. LOG(("WebsocketChannel::OnStartRequest: subprotocol %s confirmed",
  3225. respProtocol.get()));
  3226. mProtocol = respProtocol;
  3227. } else {
  3228. LOG(("WebsocketChannel::OnStartRequest: "
  3229. "subprotocol [%s] not found - %s returned",
  3230. mProtocol.get(), respProtocol.get()));
  3231. mProtocol.Truncate();
  3232. }
  3233. } else {
  3234. LOG(("WebsocketChannel::OnStartRequest "
  3235. "subprotocol [%s] not found - none returned",
  3236. mProtocol.get()));
  3237. mProtocol.Truncate();
  3238. }
  3239. }
  3240. rv = HandleExtensions();
  3241. if (NS_FAILED(rv))
  3242. return rv;
  3243. // Update mEffectiveURL for off main thread URI access.
  3244. nsCOMPtr<nsIURI> uri = mURI ? mURI : mOriginalURI;
  3245. nsAutoCString spec;
  3246. rv = uri->GetSpec(spec);
  3247. MOZ_ASSERT(NS_SUCCEEDED(rv));
  3248. CopyUTF8toUTF16(spec, mEffectiveURL);
  3249. mGotUpgradeOK = 1;
  3250. if (mRecvdHttpUpgradeTransport) {
  3251. // We're now done CONNECTING, which means we can now open another,
  3252. // perhaps parallel, connection to the same host if one
  3253. // is pending
  3254. nsWSAdmissionManager::OnConnected(this);
  3255. return StartWebsocketData();
  3256. }
  3257. return NS_OK;
  3258. }
  3259. NS_IMETHODIMP
  3260. WebSocketChannel::OnStopRequest(nsIRequest *aRequest,
  3261. nsISupports *aContext,
  3262. nsresult aStatusCode)
  3263. {
  3264. LOG(("WebSocketChannel::OnStopRequest() %p [%p %p %x]\n",
  3265. this, aRequest, mHttpChannel.get(), aStatusCode));
  3266. MOZ_ASSERT(NS_IsMainThread(), "not main thread");
  3267. ReportConnectionTelemetry();
  3268. // This is the end of the HTTP upgrade transaction, the
  3269. // upgraded streams live on
  3270. mChannel = nullptr;
  3271. mHttpChannel = nullptr;
  3272. mLoadGroup = nullptr;
  3273. mCallbacks = nullptr;
  3274. return NS_OK;
  3275. }
  3276. // nsIInputStreamCallback
  3277. NS_IMETHODIMP
  3278. WebSocketChannel::OnInputStreamReady(nsIAsyncInputStream *aStream)
  3279. {
  3280. LOG(("WebSocketChannel::OnInputStreamReady() %p\n", this));
  3281. MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "not socket thread");
  3282. if (!mSocketIn) // did we we clean up the socket after scheduling InputReady?
  3283. return NS_OK;
  3284. // this is after the http upgrade - so we are speaking websockets
  3285. char buffer[2048];
  3286. uint32_t count;
  3287. nsresult rv;
  3288. do {
  3289. rv = mSocketIn->Read((char *)buffer, 2048, &count);
  3290. LOG(("WebSocketChannel::OnInputStreamReady: read %u rv %x\n", count, rv));
  3291. // accumulate received bytes
  3292. CountRecvBytes(count);
  3293. if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
  3294. mSocketIn->AsyncWait(this, 0, 0, mSocketThread);
  3295. return NS_OK;
  3296. }
  3297. if (NS_FAILED(rv)) {
  3298. mTCPClosed = true;
  3299. AbortSession(rv);
  3300. return rv;
  3301. }
  3302. if (count == 0) {
  3303. mTCPClosed = true;
  3304. AbortSession(NS_BASE_STREAM_CLOSED);
  3305. return NS_OK;
  3306. }
  3307. if (mStopped) {
  3308. continue;
  3309. }
  3310. rv = ProcessInput((uint8_t *)buffer, count);
  3311. if (NS_FAILED(rv)) {
  3312. AbortSession(rv);
  3313. return rv;
  3314. }
  3315. } while (NS_SUCCEEDED(rv) && mSocketIn);
  3316. return NS_OK;
  3317. }
  3318. // nsIOutputStreamCallback
  3319. NS_IMETHODIMP
  3320. WebSocketChannel::OnOutputStreamReady(nsIAsyncOutputStream *aStream)
  3321. {
  3322. LOG(("WebSocketChannel::OnOutputStreamReady() %p\n", this));
  3323. MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread, "not socket thread");
  3324. nsresult rv;
  3325. if (!mCurrentOut)
  3326. PrimeNewOutgoingMessage();
  3327. while (mCurrentOut && mSocketOut) {
  3328. const char *sndBuf;
  3329. uint32_t toSend;
  3330. uint32_t amtSent;
  3331. if (mHdrOut) {
  3332. sndBuf = (const char *)mHdrOut;
  3333. toSend = mHdrOutToSend;
  3334. LOG(("WebSocketChannel::OnOutputStreamReady: "
  3335. "Try to send %u of hdr/copybreak\n", toSend));
  3336. } else {
  3337. sndBuf = (char *) mCurrentOut->BeginReading() + mCurrentOutSent;
  3338. toSend = mCurrentOut->Length() - mCurrentOutSent;
  3339. if (toSend > 0) {
  3340. LOG(("WebSocketChannel::OnOutputStreamReady: "
  3341. "Try to send %u of data\n", toSend));
  3342. }
  3343. }
  3344. if (toSend == 0) {
  3345. amtSent = 0;
  3346. } else {
  3347. rv = mSocketOut->Write(sndBuf, toSend, &amtSent);
  3348. LOG(("WebSocketChannel::OnOutputStreamReady: write %u rv %x\n",
  3349. amtSent, rv));
  3350. // accumulate sent bytes
  3351. CountSentBytes(amtSent);
  3352. if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
  3353. mSocketOut->AsyncWait(this, 0, 0, mSocketThread);
  3354. return NS_OK;
  3355. }
  3356. if (NS_FAILED(rv)) {
  3357. AbortSession(rv);
  3358. return NS_OK;
  3359. }
  3360. }
  3361. if (mHdrOut) {
  3362. if (amtSent == toSend) {
  3363. mHdrOut = nullptr;
  3364. mHdrOutToSend = 0;
  3365. } else {
  3366. mHdrOut += amtSent;
  3367. mHdrOutToSend -= amtSent;
  3368. mSocketOut->AsyncWait(this, 0, 0, mSocketThread);
  3369. }
  3370. } else {
  3371. if (amtSent == toSend) {
  3372. if (!mStopped) {
  3373. mTargetThread->Dispatch(
  3374. new CallAcknowledge(this, mCurrentOut->OrigLength()),
  3375. NS_DISPATCH_NORMAL);
  3376. }
  3377. DeleteCurrentOutGoingMessage();
  3378. PrimeNewOutgoingMessage();
  3379. } else {
  3380. mCurrentOutSent += amtSent;
  3381. mSocketOut->AsyncWait(this, 0, 0, mSocketThread);
  3382. }
  3383. }
  3384. }
  3385. if (mReleaseOnTransmit)
  3386. ReleaseSession();
  3387. return NS_OK;
  3388. }
  3389. // nsIStreamListener
  3390. NS_IMETHODIMP
  3391. WebSocketChannel::OnDataAvailable(nsIRequest *aRequest,
  3392. nsISupports *aContext,
  3393. nsIInputStream *aInputStream,
  3394. uint64_t aOffset,
  3395. uint32_t aCount)
  3396. {
  3397. LOG(("WebSocketChannel::OnDataAvailable() %p [%p %p %p %llu %u]\n",
  3398. this, aRequest, mHttpChannel.get(), aInputStream, aOffset, aCount));
  3399. // This is the HTTP OnDataAvailable Method, which means this is http data in
  3400. // response to the upgrade request and there should be no http response body
  3401. // if the upgrade succeeded. This generally should be caught by a non 101
  3402. // response code in OnStartRequest().. so we can ignore the data here
  3403. LOG(("WebSocketChannel::OnDataAvailable: HTTP data unexpected len>=%u\n",
  3404. aCount));
  3405. return NS_OK;
  3406. }
  3407. nsresult
  3408. WebSocketChannel::SaveNetworkStats(bool enforce)
  3409. {
  3410. return NS_ERROR_NOT_IMPLEMENTED;
  3411. }
  3412. } // namespace net
  3413. } // namespace mozilla
  3414. #undef CLOSE_GOING_AWAY