12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914 |
- // Copyright 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "net/http/http_network_transaction.h"
- #include <math.h> // ceil
- #include <stdarg.h>
- #include <stdint.h>
- #include <limits>
- #include <memory>
- #include <set>
- #include <string>
- #include <utility>
- #include <vector>
- #include "base/bind.h"
- #include "base/compiler_specific.h"
- #include "base/files/file_path.h"
- #include "base/files/file_util.h"
- #include "base/json/json_writer.h"
- #include "base/logging.h"
- #include "base/memory/ptr_util.h"
- #include "base/memory/raw_ptr.h"
- #include "base/memory/weak_ptr.h"
- #include "base/run_loop.h"
- #include "base/strings/string_piece.h"
- #include "base/strings/string_util.h"
- #include "base/strings/stringprintf.h"
- #include "base/strings/utf_string_conversions.h"
- #include "base/test/metrics/histogram_tester.h"
- #include "base/test/scoped_feature_list.h"
- #include "base/test/simple_test_clock.h"
- #include "base/test/simple_test_tick_clock.h"
- #include "base/test/task_environment.h"
- #include "base/test/test_file_util.h"
- #include "base/threading/thread_task_runner_handle.h"
- #include "base/time/time.h"
- #include "build/build_config.h"
- #include "net/base/auth.h"
- #include "net/base/chunked_upload_data_stream.h"
- #include "net/base/completion_once_callback.h"
- #include "net/base/elements_upload_data_stream.h"
- #include "net/base/features.h"
- #include "net/base/host_port_pair.h"
- #include "net/base/ip_address.h"
- #include "net/base/ip_endpoint.h"
- #include "net/base/load_timing_info.h"
- #include "net/base/load_timing_info_test_util.h"
- #include "net/base/net_errors.h"
- #include "net/base/privacy_mode.h"
- #include "net/base/proxy_delegate.h"
- #include "net/base/proxy_server.h"
- #include "net/base/proxy_string_util.h"
- #include "net/base/request_priority.h"
- #include "net/base/schemeful_site.h"
- #include "net/base/test_completion_callback.h"
- #include "net/base/test_proxy_delegate.h"
- #include "net/base/upload_bytes_element_reader.h"
- #include "net/base/upload_file_element_reader.h"
- #include "net/cert/cert_status_flags.h"
- #include "net/cert/mock_cert_verifier.h"
- #include "net/dns/mock_host_resolver.h"
- #include "net/dns/public/secure_dns_policy.h"
- #include "net/http/http_auth_challenge_tokenizer.h"
- #include "net/http/http_auth_handler_digest.h"
- #include "net/http/http_auth_handler_mock.h"
- #include "net/http/http_auth_handler_ntlm.h"
- #include "net/http/http_auth_ntlm_mechanism.h"
- #include "net/http/http_auth_scheme.h"
- #include "net/http/http_basic_stream.h"
- #include "net/http/http_network_session.h"
- #include "net/http/http_network_session_peer.h"
- #include "net/http/http_proxy_connect_job.h"
- #include "net/http/http_request_headers.h"
- #include "net/http/http_response_info.h"
- #include "net/http/http_server_properties.h"
- #include "net/http/http_stream.h"
- #include "net/http/http_stream_factory.h"
- #include "net/http/http_transaction_test_util.h"
- #include "net/log/net_log.h"
- #include "net/log/net_log_event_type.h"
- #include "net/log/net_log_source.h"
- #include "net/log/test_net_log.h"
- #include "net/log/test_net_log_util.h"
- #include "net/proxy_resolution/configured_proxy_resolution_service.h"
- #include "net/proxy_resolution/mock_proxy_resolver.h"
- #include "net/proxy_resolution/proxy_config_service_fixed.h"
- #include "net/proxy_resolution/proxy_info.h"
- #include "net/proxy_resolution/proxy_resolver.h"
- #include "net/proxy_resolution/proxy_resolver_factory.h"
- #include "net/socket/client_socket_factory.h"
- #include "net/socket/client_socket_pool.h"
- #include "net/socket/client_socket_pool_manager.h"
- #include "net/socket/connect_job.h"
- #include "net/socket/connection_attempts.h"
- #include "net/socket/mock_client_socket_pool_manager.h"
- #include "net/socket/next_proto.h"
- #include "net/socket/socket_tag.h"
- #include "net/socket/socket_test_util.h"
- #include "net/socket/socks_connect_job.h"
- #include "net/socket/ssl_client_socket.h"
- #include "net/spdy/spdy_session.h"
- #include "net/spdy/spdy_session_pool.h"
- #include "net/spdy/spdy_test_util_common.h"
- #include "net/ssl/client_cert_identity_test_util.h"
- #include "net/ssl/ssl_cert_request_info.h"
- #include "net/ssl/ssl_config.h"
- #include "net/ssl/ssl_config_service.h"
- #include "net/ssl/ssl_info.h"
- #include "net/ssl/ssl_private_key.h"
- #include "net/ssl/test_ssl_config_service.h"
- #include "net/test/cert_test_util.h"
- #include "net/test/gtest_util.h"
- #include "net/test/test_data_directory.h"
- #include "net/test/test_with_task_environment.h"
- #include "net/third_party/quiche/src/quiche/spdy/core/spdy_framer.h"
- #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
- #include "net/url_request/static_http_user_agent_settings.h"
- #include "net/websockets/websocket_handshake_stream_base.h"
- #include "net/websockets/websocket_test_util.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "testing/platform_test.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "url/gurl.h"
- #include "url/scheme_host_port.h"
- #include "url/url_constants.h"
- #if defined(NTLM_PORTABLE)
- #include "base/base64.h"
- #include "net/ntlm/ntlm_test_data.h"
- #endif
- #if BUILDFLAG(ENABLE_REPORTING)
- #include "net/network_error_logging/network_error_logging_service.h"
- #include "net/network_error_logging/network_error_logging_test_util.h"
- #include "net/reporting/reporting_cache.h"
- #include "net/reporting/reporting_endpoint.h"
- #include "net/reporting/reporting_header_parser.h"
- #include "net/reporting/reporting_service.h"
- #include "net/reporting/reporting_test_util.h"
- #endif // BUILDFLAG(ENABLE_REPORTING)
- using net::test::IsError;
- using net::test::IsOk;
- using base::ASCIIToUTF16;
- using testing::AnyOf;
- using testing::ElementsAre;
- using testing::IsEmpty;
- //-----------------------------------------------------------------------------
- namespace net {
- namespace {
- const std::u16string kBar(u"bar");
- const std::u16string kBar2(u"bar2");
- const std::u16string kBar3(u"bar3");
- const std::u16string kBaz(u"baz");
- const std::u16string kFirst(u"first");
- const std::u16string kFoo(u"foo");
- const std::u16string kFoo2(u"foo2");
- const std::u16string kFoo3(u"foo3");
- const std::u16string kFou(u"fou");
- const std::u16string kSecond(u"second");
- const std::u16string kWrongPassword(u"wrongpassword");
- const char kAlternativeServiceHttpHeader[] =
- "Alt-Svc: h2=\"mail.example.org:443\"\r\n";
- int GetIdleSocketCountInTransportSocketPool(HttpNetworkSession* session) {
- return session
- ->GetSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL,
- ProxyServer::Direct())
- ->IdleSocketCount();
- }
- bool IsTransportSocketPoolStalled(HttpNetworkSession* session) {
- return session
- ->GetSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL,
- ProxyServer::Direct())
- ->IsStalled();
- }
- // Takes in a Value created from a NetLogHttpResponseParameter, and returns
- // a JSONified list of headers as a single string. Uses single quotes instead
- // of double quotes for easier comparison.
- std::string GetHeaders(const base::Value& params) {
- if (!params.is_dict())
- return "";
- const base::Value::List* header_list = params.GetDict().FindList("headers");
- if (!header_list)
- return "";
- std::string headers;
- base::JSONWriter::Write(*header_list, &headers);
- base::ReplaceChars(headers, "\"", "'", &headers);
- return headers;
- }
- // Tests LoadTimingInfo in the case a socket is reused and no PAC script is
- // used.
- void TestLoadTimingReused(const LoadTimingInfo& load_timing_info) {
- EXPECT_TRUE(load_timing_info.socket_reused);
- EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
- EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null());
- EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null());
- ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
- EXPECT_FALSE(load_timing_info.send_start.is_null());
- EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end);
- // Set at a higher level.
- EXPECT_TRUE(load_timing_info.request_start_time.is_null());
- EXPECT_TRUE(load_timing_info.request_start.is_null());
- EXPECT_TRUE(load_timing_info.receive_headers_end.is_null());
- }
- // Tests LoadTimingInfo in the case a new socket is used and no PAC script is
- // used.
- void TestLoadTimingNotReused(const LoadTimingInfo& load_timing_info,
- int connect_timing_flags) {
- EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
- EXPECT_TRUE(load_timing_info.proxy_resolve_start.is_null());
- EXPECT_TRUE(load_timing_info.proxy_resolve_end.is_null());
- ExpectConnectTimingHasTimes(load_timing_info.connect_timing,
- connect_timing_flags);
- EXPECT_LE(load_timing_info.connect_timing.connect_end,
- load_timing_info.send_start);
- EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end);
- // Set at a higher level.
- EXPECT_TRUE(load_timing_info.request_start_time.is_null());
- EXPECT_TRUE(load_timing_info.request_start.is_null());
- EXPECT_TRUE(load_timing_info.receive_headers_end.is_null());
- }
- // Tests LoadTimingInfo in the case a socket is reused and a PAC script is
- // used.
- void TestLoadTimingReusedWithPac(const LoadTimingInfo& load_timing_info) {
- EXPECT_TRUE(load_timing_info.socket_reused);
- EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
- ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
- EXPECT_FALSE(load_timing_info.proxy_resolve_start.is_null());
- EXPECT_LE(load_timing_info.proxy_resolve_start,
- load_timing_info.proxy_resolve_end);
- EXPECT_LE(load_timing_info.proxy_resolve_end,
- load_timing_info.send_start);
- EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end);
- // Set at a higher level.
- EXPECT_TRUE(load_timing_info.request_start_time.is_null());
- EXPECT_TRUE(load_timing_info.request_start.is_null());
- EXPECT_TRUE(load_timing_info.receive_headers_end.is_null());
- }
- // Tests LoadTimingInfo in the case a new socket is used and a PAC script is
- // used.
- void TestLoadTimingNotReusedWithPac(const LoadTimingInfo& load_timing_info,
- int connect_timing_flags) {
- EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_NE(NetLogSource::kInvalidId, load_timing_info.socket_log_id);
- EXPECT_FALSE(load_timing_info.proxy_resolve_start.is_null());
- EXPECT_LE(load_timing_info.proxy_resolve_start,
- load_timing_info.proxy_resolve_end);
- EXPECT_LE(load_timing_info.proxy_resolve_end,
- load_timing_info.connect_timing.connect_start);
- ExpectConnectTimingHasTimes(load_timing_info.connect_timing,
- connect_timing_flags);
- EXPECT_LE(load_timing_info.connect_timing.connect_end,
- load_timing_info.send_start);
- EXPECT_LE(load_timing_info.send_start, load_timing_info.send_end);
- // Set at a higher level.
- EXPECT_TRUE(load_timing_info.request_start_time.is_null());
- EXPECT_TRUE(load_timing_info.request_start.is_null());
- EXPECT_TRUE(load_timing_info.receive_headers_end.is_null());
- }
- // ProxyResolver that records URLs passed to it, and that can be told what
- // result to return.
- class CapturingProxyResolver : public ProxyResolver {
- public:
- struct LookupInfo {
- GURL url;
- NetworkIsolationKey network_isolation_key;
- };
- CapturingProxyResolver()
- : proxy_server_(ProxyServer::SCHEME_HTTP, HostPortPair("myproxy", 80)) {}
- CapturingProxyResolver(const CapturingProxyResolver&) = delete;
- CapturingProxyResolver& operator=(const CapturingProxyResolver&) = delete;
- ~CapturingProxyResolver() override = default;
- int GetProxyForURL(const GURL& url,
- const NetworkIsolationKey& network_isolation_key,
- ProxyInfo* results,
- CompletionOnceCallback callback,
- std::unique_ptr<Request>* request,
- const NetLogWithSource& net_log) override {
- results->UseProxyServer(proxy_server_);
- lookup_info_.push_back(LookupInfo{url, network_isolation_key});
- return OK;
- }
- // Sets whether the resolver should use direct connections, instead of a
- // proxy.
- void set_proxy_server(ProxyServer proxy_server) {
- proxy_server_ = proxy_server;
- }
- const std::vector<LookupInfo>& lookup_info() const { return lookup_info_; }
- private:
- std::vector<LookupInfo> lookup_info_;
- ProxyServer proxy_server_;
- };
- class CapturingProxyResolverFactory : public ProxyResolverFactory {
- public:
- explicit CapturingProxyResolverFactory(CapturingProxyResolver* resolver)
- : ProxyResolverFactory(false), resolver_(resolver) {}
- int CreateProxyResolver(const scoped_refptr<PacFileData>& pac_script,
- std::unique_ptr<ProxyResolver>* resolver,
- CompletionOnceCallback callback,
- std::unique_ptr<Request>* request) override {
- *resolver = std::make_unique<ForwardingProxyResolver>(resolver_);
- return OK;
- }
- private:
- raw_ptr<ProxyResolver> resolver_;
- };
- std::unique_ptr<HttpNetworkSession> CreateSession(
- SpdySessionDependencies* session_deps) {
- return SpdySessionDependencies::SpdyCreateSession(session_deps);
- }
- class FailingProxyResolverFactory : public ProxyResolverFactory {
- public:
- FailingProxyResolverFactory() : ProxyResolverFactory(false) {}
- // ProxyResolverFactory override.
- int CreateProxyResolver(const scoped_refptr<PacFileData>& script_data,
- std::unique_ptr<ProxyResolver>* result,
- CompletionOnceCallback callback,
- std::unique_ptr<Request>* request) override {
- return ERR_PAC_SCRIPT_FAILED;
- }
- };
- class SingleProxyDelegate : public ProxyDelegate {
- public:
- void set_proxy(const ProxyServer& proxy_server) {
- proxy_server_ = proxy_server;
- }
- // ProxyDelegate implementation:
- void OnResolveProxy(const GURL& url,
- const std::string& method,
- const ProxyRetryInfoMap& proxy_retry_info,
- ProxyInfo* result) override {
- if (proxy_server_.is_valid())
- result->UseProxyServer(proxy_server_);
- }
- void OnFallback(const ProxyServer& bad_proxy, int net_error) override {}
- void OnBeforeTunnelRequest(const ProxyServer& proxy_server,
- HttpRequestHeaders* extra_headers) override {}
- Error OnTunnelHeadersReceived(
- const ProxyServer& proxy_server,
- const HttpResponseHeaders& response_headers) override {
- return OK;
- }
- private:
- ProxyServer proxy_server_;
- };
- // A default minimal HttpRequestInfo for use in tests, targeting HTTP.
- HttpRequestInfo DefaultRequestInfo() {
- HttpRequestInfo info;
- info.method = "GET";
- info.url = GURL("http://foo.test");
- info.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- return info;
- }
- // The default info for transports to the embedded HTTP server.
- TransportInfo EmbeddedHttpServerTransportInfo() {
- TransportInfo info;
- info.endpoint = IPEndPoint(IPAddress::IPv4Localhost(), 80);
- return info;
- }
- } // namespace
- class HttpNetworkTransactionTest : public PlatformTest,
- public WithTaskEnvironment {
- public:
- ~HttpNetworkTransactionTest() override {
- // Important to restore the per-pool limit first, since the pool limit must
- // always be greater than group limit, and the tests reduce both limits.
- ClientSocketPoolManager::set_max_sockets_per_pool(
- HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_pool_sockets_);
- ClientSocketPoolManager::set_max_sockets_per_group(
- HttpNetworkSession::NORMAL_SOCKET_POOL, old_max_group_sockets_);
- }
- protected:
- HttpNetworkTransactionTest()
- : WithTaskEnvironment(base::test::TaskEnvironment::TimeSource::MOCK_TIME),
- dummy_connect_job_params_(
- nullptr /* client_socket_factory */,
- nullptr /* host_resolver */,
- nullptr /* http_auth_cache */,
- nullptr /* http_auth_handler_factory */,
- nullptr /* spdy_session_pool */,
- nullptr /* quic_supported_versions */,
- nullptr /* quic_stream_factory */,
- nullptr /* proxy_delegate */,
- nullptr /* http_user_agent_settings */,
- nullptr /* ssl_client_context */,
- nullptr /* socket_performance_watcher_factory */,
- nullptr /* network_quality_estimator */,
- nullptr /* net_log */,
- nullptr /* websocket_endpoint_lock_manager */),
- ssl_(ASYNC, OK),
- old_max_group_sockets_(ClientSocketPoolManager::max_sockets_per_group(
- HttpNetworkSession::NORMAL_SOCKET_POOL)),
- old_max_pool_sockets_(ClientSocketPoolManager::max_sockets_per_pool(
- HttpNetworkSession::NORMAL_SOCKET_POOL)) {
- session_deps_.enable_http2_alternative_service = true;
- }
- struct SimpleGetHelperResult {
- int rv;
- std::string status_line;
- std::string response_data;
- int64_t total_received_bytes;
- int64_t total_sent_bytes;
- LoadTimingInfo load_timing_info;
- ConnectionAttempts connection_attempts;
- IPEndPoint remote_endpoint_after_start;
- };
- void SetUp() override {
- NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
- base::RunLoop().RunUntilIdle();
- // Set an initial delay to ensure that the first call to TimeTicks::Now()
- // before incrementing the counter does not return a null value.
- FastForwardBy(base::Seconds(1));
- }
- void TearDown() override {
- NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
- base::RunLoop().RunUntilIdle();
- // Empty the current queue.
- base::RunLoop().RunUntilIdle();
- PlatformTest::TearDown();
- NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
- base::RunLoop().RunUntilIdle();
- }
- void Check100ResponseTiming(bool use_spdy);
- // Either |write_failure| specifies a write failure or |read_failure|
- // specifies a read failure when using a reused socket. In either case, the
- // failure should cause the network transaction to resend the request, and the
- // other argument should be NULL.
- void KeepAliveConnectionResendRequestTest(const MockWrite* write_failure,
- const MockRead* read_failure);
- // Either |write_failure| specifies a write failure or |read_failure|
- // specifies a read failure when using a reused socket. In either case, the
- // failure should cause the network transaction to resend the request, and the
- // other argument should be NULL.
- void PreconnectErrorResendRequestTest(const MockWrite* write_failure,
- const MockRead* read_failure,
- bool use_spdy,
- bool upload = false);
- SimpleGetHelperResult SimpleGetHelperForData(
- base::span<StaticSocketDataProvider*> providers) {
- SimpleGetHelperResult out;
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- RecordingNetLogObserver net_log_observer;
- NetLogWithSource net_log_with_source =
- NetLogWithSource::Make(NetLogSourceType::NONE);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- for (auto* provider : providers) {
- session_deps_.socket_factory->AddSocketDataProvider(provider);
- }
- TestCompletionCallback callback;
- EXPECT_TRUE(net_log_with_source.IsCapturing());
- int rv = trans.Start(&request, callback.callback(), net_log_with_source);
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- out.rv = callback.WaitForResult();
- out.total_received_bytes = trans.GetTotalReceivedBytes();
- out.total_sent_bytes = trans.GetTotalSentBytes();
- // Even in the failure cases that use this function, connections are always
- // successfully established before the error.
- EXPECT_TRUE(trans.GetLoadTimingInfo(&out.load_timing_info));
- TestLoadTimingNotReused(out.load_timing_info, CONNECT_TIMING_HAS_DNS_TIMES);
- if (out.rv != OK)
- return out;
- const HttpResponseInfo* response = trans.GetResponseInfo();
- // Can't use ASSERT_* inside helper functions like this, so
- // return an error.
- if (!response || !response->headers) {
- out.rv = ERR_UNEXPECTED;
- return out;
- }
- out.status_line = response->headers->GetStatusLine();
- EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
- EXPECT_EQ(80, response->remote_endpoint.port());
- bool got_endpoint =
- trans.GetRemoteEndpoint(&out.remote_endpoint_after_start);
- EXPECT_EQ(got_endpoint,
- out.remote_endpoint_after_start.address().size() > 0);
- rv = ReadTransaction(&trans, &out.response_data);
- EXPECT_THAT(rv, IsOk());
- auto entries = net_log_observer.GetEntries();
- size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST_HEADERS,
- NetLogEventPhase::NONE);
- ExpectLogContainsSomewhere(
- entries, pos, NetLogEventType::HTTP_TRANSACTION_READ_RESPONSE_HEADERS,
- NetLogEventPhase::NONE);
- EXPECT_EQ("GET / HTTP/1.1\r\n",
- GetStringValueFromParams(entries[pos], "line"));
- EXPECT_EQ("['Host: www.example.org','Connection: keep-alive']",
- GetHeaders(entries[pos].params));
- out.total_received_bytes = trans.GetTotalReceivedBytes();
- // The total number of sent bytes should not have changed.
- EXPECT_EQ(out.total_sent_bytes, trans.GetTotalSentBytes());
- out.connection_attempts = trans.GetConnectionAttempts();
- return out;
- }
- SimpleGetHelperResult SimpleGetHelper(base::span<const MockRead> data_reads) {
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- StaticSocketDataProvider reads(data_reads, data_writes);
- StaticSocketDataProvider* data[] = {&reads};
- SimpleGetHelperResult out = SimpleGetHelperForData(data);
- EXPECT_EQ(CountWriteBytes(data_writes), out.total_sent_bytes);
- return out;
- }
- void AddSSLSocketData() {
- ssl_.next_proto = kProtoHTTP2;
- ssl_.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
- ASSERT_TRUE(ssl_.ssl_info.cert);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_);
- }
- void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
- int expected_status);
- void ConnectStatusHelper(const MockRead& status);
- void CheckErrorIsPassedBack(int error, IoMode mode);
- base::RepeatingClosure FastForwardByCallback(base::TimeDelta delta) {
- return base::BindRepeating(&HttpNetworkTransactionTest::FastForwardBy,
- base::Unretained(this), delta);
- }
- const CommonConnectJobParams dummy_connect_job_params_;
- const net::NetworkIsolationKey kNetworkIsolationKey =
- NetworkIsolationKey(SchemefulSite(GURL("https://foo.test/")),
- SchemefulSite(GURL("https://bar.test/")));
- // These clocks are defined here, even though they're only used in the
- // Reporting tests below, since they need to be destroyed after
- // |session_deps_|.
- base::SimpleTestClock clock_;
- base::SimpleTestTickClock tick_clock_;
- SpdyTestUtil spdy_util_;
- SpdySessionDependencies session_deps_;
- SSLSocketDataProvider ssl_;
- // Original socket limits. Some tests set these. Safest to always restore
- // them once each test has been run.
- int old_max_group_sockets_;
- int old_max_pool_sockets_;
- };
- namespace {
- // Fill |str| with a long header list that consumes >= |size| bytes.
- void FillLargeHeadersString(std::string* str, int size) {
- const char row[] =
- "SomeHeaderName: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n";
- const int sizeof_row = strlen(row);
- const int num_rows = static_cast<int>(
- ceil(static_cast<float>(size) / sizeof_row));
- const int sizeof_data = num_rows * sizeof_row;
- DCHECK(sizeof_data >= size);
- str->reserve(sizeof_data);
- for (int i = 0; i < num_rows; ++i)
- str->append(row, sizeof_row);
- }
- #if defined(NTLM_PORTABLE)
- uint64_t MockGetMSTime() {
- // Tue, 23 May 2017 20:13:07 +0000
- return 131400439870000000;
- }
- // Alternative functions that eliminate randomness and dependency on the local
- // host name so that the generated NTLM messages are reproducible.
- void MockGenerateRandom(uint8_t* output, size_t n) {
- // This is set to 0xaa because the client challenge for testing in
- // [MS-NLMP] Section 4.2.1 is 8 bytes of 0xaa.
- memset(output, 0xaa, n);
- }
- std::string MockGetHostName() {
- return ntlm::test::kHostnameAscii;
- }
- #endif // defined(NTLM_PORTABLE)
- class CaptureGroupIdTransportSocketPool : public TransportClientSocketPool {
- public:
- explicit CaptureGroupIdTransportSocketPool(
- const CommonConnectJobParams* common_connect_job_params)
- : TransportClientSocketPool(0,
- 0,
- base::TimeDelta(),
- ProxyServer::Direct(),
- false /* is_for_websockets */,
- common_connect_job_params) {}
- const ClientSocketPool::GroupId& last_group_id_received() const {
- return last_group_id_;
- }
- bool socket_requested() const { return socket_requested_; }
- int RequestSocket(
- const ClientSocketPool::GroupId& group_id,
- scoped_refptr<ClientSocketPool::SocketParams> socket_params,
- const absl::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
- RequestPriority priority,
- const SocketTag& socket_tag,
- ClientSocketPool::RespectLimits respect_limits,
- ClientSocketHandle* handle,
- CompletionOnceCallback callback,
- const ClientSocketPool::ProxyAuthCallback& proxy_auth_callback,
- const NetLogWithSource& net_log) override {
- last_group_id_ = group_id;
- socket_requested_ = true;
- return ERR_IO_PENDING;
- }
- void CancelRequest(const ClientSocketPool::GroupId& group_id,
- ClientSocketHandle* handle,
- bool cancel_connect_job) override {}
- void ReleaseSocket(const ClientSocketPool::GroupId& group_id,
- std::unique_ptr<StreamSocket> socket,
- int64_t generation) override {}
- void CloseIdleSockets(const char* net_log_reason_utf8) override {}
- void CloseIdleSocketsInGroup(const ClientSocketPool::GroupId& group_id,
- const char* net_log_reason_utf8) override {}
- int IdleSocketCount() const override { return 0; }
- size_t IdleSocketCountInGroup(
- const ClientSocketPool::GroupId& group_id) const override {
- return 0;
- }
- LoadState GetLoadState(const ClientSocketPool::GroupId& group_id,
- const ClientSocketHandle* handle) const override {
- return LOAD_STATE_IDLE;
- }
- private:
- ClientSocketPool::GroupId last_group_id_;
- bool socket_requested_ = false;
- };
- //-----------------------------------------------------------------------------
- // Helper functions for validating that AuthChallengeInfo's are correctly
- // configured for common cases.
- bool CheckBasicServerAuth(
- const absl::optional<AuthChallengeInfo>& auth_challenge) {
- if (!auth_challenge)
- return false;
- EXPECT_FALSE(auth_challenge->is_proxy);
- EXPECT_EQ("http://www.example.org", auth_challenge->challenger.Serialize());
- EXPECT_EQ("MyRealm1", auth_challenge->realm);
- EXPECT_EQ(kBasicAuthScheme, auth_challenge->scheme);
- return true;
- }
- bool CheckBasicSecureServerAuth(
- const absl::optional<AuthChallengeInfo>& auth_challenge) {
- if (!auth_challenge)
- return false;
- EXPECT_FALSE(auth_challenge->is_proxy);
- EXPECT_EQ("https://www.example.org", auth_challenge->challenger.Serialize());
- EXPECT_EQ("MyRealm1", auth_challenge->realm);
- EXPECT_EQ(kBasicAuthScheme, auth_challenge->scheme);
- return true;
- }
- bool CheckBasicProxyAuth(
- const absl::optional<AuthChallengeInfo>& auth_challenge) {
- if (!auth_challenge)
- return false;
- EXPECT_TRUE(auth_challenge->is_proxy);
- EXPECT_EQ("http://myproxy:70", auth_challenge->challenger.Serialize());
- EXPECT_EQ("MyRealm1", auth_challenge->realm);
- EXPECT_EQ(kBasicAuthScheme, auth_challenge->scheme);
- return true;
- }
- bool CheckBasicSecureProxyAuth(
- const absl::optional<AuthChallengeInfo>& auth_challenge) {
- if (!auth_challenge)
- return false;
- EXPECT_TRUE(auth_challenge->is_proxy);
- EXPECT_EQ("https://myproxy:70", auth_challenge->challenger.Serialize());
- EXPECT_EQ("MyRealm1", auth_challenge->realm);
- EXPECT_EQ(kBasicAuthScheme, auth_challenge->scheme);
- return true;
- }
- bool CheckDigestServerAuth(
- const absl::optional<AuthChallengeInfo>& auth_challenge) {
- if (!auth_challenge)
- return false;
- EXPECT_FALSE(auth_challenge->is_proxy);
- EXPECT_EQ("http://www.example.org", auth_challenge->challenger.Serialize());
- EXPECT_EQ("digestive", auth_challenge->realm);
- EXPECT_EQ(kDigestAuthScheme, auth_challenge->scheme);
- return true;
- }
- #if defined(NTLM_PORTABLE)
- bool CheckNTLMServerAuth(
- const absl::optional<AuthChallengeInfo>& auth_challenge) {
- if (!auth_challenge)
- return false;
- EXPECT_FALSE(auth_challenge->is_proxy);
- EXPECT_EQ("https://server", auth_challenge->challenger.Serialize());
- EXPECT_EQ(std::string(), auth_challenge->realm);
- EXPECT_EQ(kNtlmAuthScheme, auth_challenge->scheme);
- return true;
- }
- bool CheckNTLMProxyAuth(
- const absl::optional<AuthChallengeInfo>& auth_challenge) {
- if (!auth_challenge)
- return false;
- EXPECT_TRUE(auth_challenge->is_proxy);
- EXPECT_EQ("http://server", auth_challenge->challenger.Serialize());
- EXPECT_EQ(std::string(), auth_challenge->realm);
- EXPECT_EQ(kNtlmAuthScheme, auth_challenge->scheme);
- return true;
- }
- #endif // defined(NTLM_PORTABLE)
- } // namespace
- TEST_F(HttpNetworkTransactionTest, Basic) {
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- }
- TEST_F(HttpNetworkTransactionTest, SimpleGET) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
- EXPECT_EQ("hello world", out.response_data);
- int64_t reads_size = CountReadBytes(data_reads);
- EXPECT_EQ(reads_size, out.total_received_bytes);
- EXPECT_EQ(0u, out.connection_attempts.size());
- EXPECT_FALSE(out.remote_endpoint_after_start.address().empty());
- }
- // Response with no status line.
- TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeaders) {
- MockRead data_reads[] = {
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
- EXPECT_EQ("hello world", out.response_data);
- int64_t reads_size = CountReadBytes(data_reads);
- EXPECT_EQ(reads_size, out.total_received_bytes);
- }
- // Response with no status line, and a weird port. Should fail by default.
- TEST_F(HttpNetworkTransactionTest, SimpleGETNoHeadersWeirdPort) {
- MockRead data_reads[] = {
- MockRead("hello world"), MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpRequestInfo request;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- request.method = "GET";
- request.url = GURL("http://www.example.com:2000/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_INVALID_HTTP_RESPONSE));
- }
- // Tests that request info can be destroyed after the headers phase is complete.
- TEST_F(HttpNetworkTransactionTest, SimpleGETNoReadDestroyRequestInfo) {
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"), MockRead("Connection: keep-alive\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"), MockRead(SYNCHRONOUS, 0),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- {
- auto request = std::make_unique<HttpRequestInfo>();
- request->method = "GET";
- request->url = GURL("http://www.example.org/");
- request->traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- int rv =
- trans->Start(request.get(), callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- } // Let request info be destroyed.
- trans.reset();
- }
- // Test that a failure in resolving the hostname is retrievable.
- TEST_F(HttpNetworkTransactionTest, SimpleGETHostResolutionFailure) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto resolver = std::make_unique<MockHostResolver>();
- resolver->rules()->AddSimulatedTimeoutFailure("www.example.org");
- session_deps_.net_log = net::NetLog::Get();
- session_deps_.host_resolver = std::move(resolver);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NAME_NOT_RESOLVED));
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_THAT(response->resolve_error_info.error, IsError(ERR_DNS_TIMED_OUT));
- }
- // This test verifies that if the transaction fails before even connecting to a
- // remote endpoint, the ConnectedCallback is never called.
- TEST_F(HttpNetworkTransactionTest, ConnectedCallbackNeverCalled) {
- auto resolver = std::make_unique<MockHostResolver>();
- resolver->rules()->AddSimulatedTimeoutFailure("bar.test");
- session_deps_.host_resolver = std::move(resolver);
- ConnectedHandler connected_handler;
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- auto request = DefaultRequestInfo();
- request.url = GURL("http://bar.test");
- HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session.get());
- transaction.SetConnectedCallback(connected_handler.Callback());
- TestCompletionCallback callback;
- transaction.Start(&request, callback.callback(), NetLogWithSource());
- callback.WaitForResult();
- EXPECT_THAT(connected_handler.transports(), IsEmpty());
- }
- // This test verifies that if the ConnectedCallback returns an error, the
- // entire transaction fails with that error.
- TEST_F(HttpNetworkTransactionTest, ConnectedCallbackFailure) {
- // The exact error code does not matter, as long as it is the same one
- // returned by the transaction overall.
- ConnectedHandler connected_handler;
- connected_handler.set_result(ERR_NOT_IMPLEMENTED);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- auto request = DefaultRequestInfo();
- HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session.get());
- transaction.SetConnectedCallback(connected_handler.Callback());
- // We never get to writing any data, but we still need a socket.
- StaticSocketDataProvider data;
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- EXPECT_THAT(
- transaction.Start(&request, callback.callback(), NetLogWithSource()),
- IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NOT_IMPLEMENTED));
- EXPECT_THAT(connected_handler.transports(),
- ElementsAre(EmbeddedHttpServerTransportInfo()));
- }
- // This test verifies that if the ConnectedCallback returns an error, the
- // underlying socket is not closed and can be reused by the next transaction.
- TEST_F(HttpNetworkTransactionTest, ConnectedCallbackFailureAllowsSocketReuse) {
- ConnectedHandler connected_handler;
- connected_handler.set_result(ERR_NOT_IMPLEMENTED);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- auto request = DefaultRequestInfo();
- // A single socket should be opened and used for both transactions. Data
- // providers are matched to sockets at most once.
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("X-Test-Header: foo\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- {
- HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session.get());
- transaction.SetConnectedCallback(connected_handler.Callback());
- TestCompletionCallback callback;
- EXPECT_THAT(
- transaction.Start(&request, callback.callback(), NetLogWithSource()),
- IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NOT_IMPLEMENTED));
- }
- // The data provider should still be linked to a socket.
- EXPECT_TRUE(data.socket());
- auto* socket = data.socket();
- {
- HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- EXPECT_THAT(
- transaction.Start(&request, callback.callback(), NetLogWithSource()),
- IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- EXPECT_TRUE(transaction.GetResponseInfo()->headers->HasHeaderValue(
- "X-Test-Header", "foo"));
- // Still linked to the same socket.
- EXPECT_EQ(data.socket(), socket);
- }
- }
- // This test verifies that the ConnectedCallback is called once in the case of
- // simple requests.
- TEST_F(HttpNetworkTransactionTest, ConnectedCallbackCalledOnce) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- ConnectedHandler connected_handler;
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- auto request = DefaultRequestInfo();
- HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session.get());
- transaction.SetConnectedCallback(connected_handler.Callback());
- TestCompletionCallback callback;
- EXPECT_THAT(
- transaction.Start(&request, callback.callback(), NetLogWithSource()),
- IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- EXPECT_THAT(connected_handler.transports(),
- ElementsAre(EmbeddedHttpServerTransportInfo()));
- }
- // This test verifies that the ConnectedCallback is called once more per
- // authentication challenge.
- TEST_F(HttpNetworkTransactionTest, ConnectedCallbackCalledOnEachAuthChallenge) {
- ConnectedHandler connected_handler;
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- auto request = DefaultRequestInfo();
- HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session.get());
- transaction.SetConnectedCallback(connected_handler.Callback());
- // First request receives an auth challenge.
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- StaticSocketDataProvider data1(data_reads1, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- // Second request is allowed through.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 200 OK\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data2(data_reads2, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- // First request, connects once.
- TestCompletionCallback callback1;
- EXPECT_THAT(
- transaction.Start(&request, callback1.callback(), NetLogWithSource()),
- IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback1.WaitForResult(), IsOk());
- EXPECT_THAT(connected_handler.transports(),
- ElementsAre(EmbeddedHttpServerTransportInfo()));
- // Second request, connects again.
- TestCompletionCallback callback2;
- EXPECT_THAT(transaction.RestartWithAuth(AuthCredentials(kFoo, kBar),
- callback2.callback()),
- IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback2.WaitForResult(), IsOk());
- EXPECT_THAT(connected_handler.transports(),
- ElementsAre(EmbeddedHttpServerTransportInfo(),
- EmbeddedHttpServerTransportInfo()));
- }
- // This test verifies that the ConnectedCallback is called once more per retry.
- TEST_F(HttpNetworkTransactionTest, ConnectedCallbackCalledOnEachRetry) {
- ConnectedHandler connected_handler;
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- auto request = DefaultRequestInfo();
- HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session.get());
- transaction.SetConnectedCallback(connected_handler.Callback());
- // First request receives a retryable error.
- MockRead data_reads1[] = {
- MockRead(SYNCHRONOUS, ERR_HTTP2_SERVER_REFUSED_STREAM),
- };
- StaticSocketDataProvider data1(data_reads1, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- // Second request is allowed through.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 200 OK\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data2(data_reads2, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback1;
- EXPECT_THAT(
- transaction.Start(&request, callback1.callback(), NetLogWithSource()),
- IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback1.WaitForResult(), IsOk());
- EXPECT_THAT(connected_handler.transports(),
- ElementsAre(EmbeddedHttpServerTransportInfo(),
- EmbeddedHttpServerTransportInfo()));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectedCallbackCalledAsync) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- ConnectedHandler connected_handler;
- connected_handler.set_run_callback(true);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- auto request = DefaultRequestInfo();
- HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session.get());
- transaction.SetConnectedCallback(connected_handler.Callback());
- TestCompletionCallback callback;
- EXPECT_THAT(
- transaction.Start(&request, callback.callback(), NetLogWithSource()),
- IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- EXPECT_THAT(connected_handler.transports(),
- ElementsAre(EmbeddedHttpServerTransportInfo()));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectedCallbackCalledAsyncError) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- ConnectedHandler connected_handler;
- connected_handler.set_run_callback(true);
- connected_handler.set_result(ERR_FAILED);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- auto request = DefaultRequestInfo();
- HttpNetworkTransaction transaction(DEFAULT_PRIORITY, session.get());
- transaction.SetConnectedCallback(connected_handler.Callback());
- TestCompletionCallback callback;
- EXPECT_THAT(
- transaction.Start(&request, callback.callback(), NetLogWithSource()),
- IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsError(ERR_FAILED));
- EXPECT_THAT(connected_handler.transports(),
- ElementsAre(EmbeddedHttpServerTransportInfo()));
- }
- // Allow up to 4 bytes of junk to precede status line.
- TEST_F(HttpNetworkTransactionTest, StatusLineJunk3Bytes) {
- MockRead data_reads[] = {
- MockRead("xxxHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
- MockRead(SYNCHRONOUS, OK),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
- EXPECT_EQ("DATA", out.response_data);
- int64_t reads_size = CountReadBytes(data_reads);
- EXPECT_EQ(reads_size, out.total_received_bytes);
- }
- // Allow up to 4 bytes of junk to precede status line.
- TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes) {
- MockRead data_reads[] = {
- MockRead("\n\nQJHTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
- MockRead(SYNCHRONOUS, OK),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
- EXPECT_EQ("DATA", out.response_data);
- int64_t reads_size = CountReadBytes(data_reads);
- EXPECT_EQ(reads_size, out.total_received_bytes);
- }
- // Beyond 4 bytes of slop and it should fail to find a status line.
- TEST_F(HttpNetworkTransactionTest, StatusLineJunk5Bytes) {
- MockRead data_reads[] = {
- MockRead("xxxxxHTTP/1.1 404 Not Found\nServer: blah"),
- MockRead(SYNCHRONOUS, OK),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
- EXPECT_EQ("xxxxxHTTP/1.1 404 Not Found\nServer: blah", out.response_data);
- int64_t reads_size = CountReadBytes(data_reads);
- EXPECT_EQ(reads_size, out.total_received_bytes);
- }
- // Same as StatusLineJunk4Bytes, except the read chunks are smaller.
- TEST_F(HttpNetworkTransactionTest, StatusLineJunk4Bytes_Slow) {
- MockRead data_reads[] = {
- MockRead("\n"),
- MockRead("\n"),
- MockRead("Q"),
- MockRead("J"),
- MockRead("HTTP/1.0 404 Not Found\nServer: blah\n\nDATA"),
- MockRead(SYNCHRONOUS, OK),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/1.0 404 Not Found", out.status_line);
- EXPECT_EQ("DATA", out.response_data);
- int64_t reads_size = CountReadBytes(data_reads);
- EXPECT_EQ(reads_size, out.total_received_bytes);
- }
- // Close the connection before enough bytes to have a status line.
- TEST_F(HttpNetworkTransactionTest, StatusLinePartial) {
- MockRead data_reads[] = {
- MockRead("HTT"),
- MockRead(SYNCHRONOUS, OK),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/0.9 200 OK", out.status_line);
- EXPECT_EQ("HTT", out.response_data);
- int64_t reads_size = CountReadBytes(data_reads);
- EXPECT_EQ(reads_size, out.total_received_bytes);
- }
- // Simulate a 204 response, lacking a Content-Length header, sent over a
- // persistent connection. The response should still terminate since a 204
- // cannot have a response body.
- TEST_F(HttpNetworkTransactionTest, StopsReading204) {
- char junk[] = "junk";
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 204 No Content\r\n\r\n"),
- MockRead(junk), // Should not be read!!
- MockRead(SYNCHRONOUS, OK),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/1.1 204 No Content", out.status_line);
- EXPECT_EQ("", out.response_data);
- int64_t reads_size = CountReadBytes(data_reads);
- int64_t response_size = reads_size - strlen(junk);
- EXPECT_EQ(response_size, out.total_received_bytes);
- }
- // A simple request using chunked encoding with some extra data after.
- TEST_F(HttpNetworkTransactionTest, ChunkedEncoding) {
- std::string final_chunk = "0\r\n\r\n";
- std::string extra_data = "HTTP/1.1 200 OK\r\n";
- std::string last_read = final_chunk + extra_data;
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"),
- MockRead("5\r\nHello\r\n"),
- MockRead("1\r\n"),
- MockRead(" \r\n"),
- MockRead("5\r\nworld\r\n"),
- MockRead(last_read.data()),
- MockRead(SYNCHRONOUS, OK),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
- EXPECT_EQ("Hello world", out.response_data);
- int64_t reads_size = CountReadBytes(data_reads);
- int64_t response_size = reads_size - extra_data.size();
- EXPECT_EQ(response_size, out.total_received_bytes);
- }
- // Next tests deal with http://crbug.com/56344.
- TEST_F(HttpNetworkTransactionTest,
- MultipleContentLengthHeadersNoTransferEncoding) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 10\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsError(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH));
- }
- TEST_F(HttpNetworkTransactionTest,
- DuplicateContentLengthHeadersNoTransferEncoding) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 5\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead("Hello"),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
- EXPECT_EQ("Hello", out.response_data);
- }
- TEST_F(HttpNetworkTransactionTest,
- ComplexContentLengthHeadersNoTransferEncoding) {
- // More than 2 dupes.
- {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 5\r\n"),
- MockRead("Content-Length: 5\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead("Hello"),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
- EXPECT_EQ("Hello", out.response_data);
- }
- // HTTP/1.0
- {
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Length: 5\r\n"),
- MockRead("Content-Length: 5\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead("Hello"),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/1.0 200 OK", out.status_line);
- EXPECT_EQ("Hello", out.response_data);
- }
- // 2 dupes and one mismatched.
- {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 10\r\n"),
- MockRead("Content-Length: 10\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsError(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH));
- }
- }
- TEST_F(HttpNetworkTransactionTest,
- MultipleContentLengthHeadersTransferEncoding) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 666\r\n"),
- MockRead("Content-Length: 1337\r\n"),
- MockRead("Transfer-Encoding: chunked\r\n\r\n"),
- MockRead("5\r\nHello\r\n"),
- MockRead("1\r\n"),
- MockRead(" \r\n"),
- MockRead("5\r\nworld\r\n"),
- MockRead("0\r\n\r\nHTTP/1.1 200 OK\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
- EXPECT_EQ("Hello world", out.response_data);
- }
- // Next tests deal with http://crbug.com/98895.
- // Checks that a single Content-Disposition header results in no error.
- TEST_F(HttpNetworkTransactionTest, SingleContentDispositionHeader) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Disposition: attachment;filename=\"salutations.txt\"r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead("Hello"),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
- EXPECT_EQ("Hello", out.response_data);
- }
- // Checks that two identical Content-Disposition headers result in no error.
- TEST_F(HttpNetworkTransactionTest, TwoIdenticalContentDispositionHeaders) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"),
- MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead("Hello"),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsOk());
- EXPECT_EQ("HTTP/1.1 200 OK", out.status_line);
- EXPECT_EQ("Hello", out.response_data);
- }
- // Checks that two distinct Content-Disposition headers result in an error.
- TEST_F(HttpNetworkTransactionTest, TwoDistinctContentDispositionHeaders) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Disposition: attachment;filename=\"greetings.txt\"r\n"),
- MockRead("Content-Disposition: attachment;filename=\"hi.txt\"r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead("Hello"),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv,
- IsError(ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION));
- }
- // Checks that two identical Location headers result in no error.
- // Also tests Location header behavior.
- TEST_F(HttpNetworkTransactionTest, TwoIdenticalLocationHeaders) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 302 Redirect\r\n"),
- MockRead("Location: http://good.com/\r\n"),
- MockRead("Location: http://good.com/\r\n"),
- MockRead("Content-Length: 0\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://redirect.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 302 Redirect", response->headers->GetStatusLine());
- std::string url;
- EXPECT_TRUE(response->headers->IsRedirect(&url));
- EXPECT_EQ("http://good.com/", url);
- EXPECT_TRUE(response->proxy_server.is_direct());
- }
- // Checks that two distinct Location headers result in an error.
- TEST_F(HttpNetworkTransactionTest, TwoDistinctLocationHeaders) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 302 Redirect\r\n"),
- MockRead("Location: http://good.com/\r\n"),
- MockRead("Location: http://evil.com/\r\n"),
- MockRead("Content-Length: 0\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsError(ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION));
- }
- // Do a request using the HEAD method. Verify that we don't try to read the
- // message body (since HEAD has none).
- TEST_F(HttpNetworkTransactionTest, Head) {
- HttpRequestInfo request;
- request.method = "HEAD";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- ConnectedHandler connected_handler;
- trans.SetConnectedCallback(connected_handler.Callback());
- MockWrite data_writes1[] = {
- MockWrite("HEAD / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 404 Not Found\r\n"), MockRead("Server: Blah\r\n"),
- MockRead("Content-Length: 1234\r\n\r\n"),
- // No response body because the test stops reading here.
- MockRead(SYNCHRONOUS, ERR_UNEXPECTED),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- // Check that the headers got parsed.
- EXPECT_TRUE(response->headers);
- EXPECT_EQ(1234, response->headers->GetContentLength());
- EXPECT_EQ("HTTP/1.1 404 Not Found", response->headers->GetStatusLine());
- EXPECT_TRUE(response->proxy_server.is_direct());
- EXPECT_THAT(connected_handler.transports(),
- ElementsAre(EmbeddedHttpServerTransportInfo()));
- std::string server_header;
- size_t iter = 0;
- bool has_server_header = response->headers->EnumerateHeader(
- &iter, "Server", &server_header);
- EXPECT_TRUE(has_server_header);
- EXPECT_EQ("Blah", server_header);
- // Reading should give EOF right away, since there is no message body
- // (despite non-zero content-length).
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("", response_data);
- }
- TEST_F(HttpNetworkTransactionTest, ReuseConnection) {
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
- MockRead("hello"),
- MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
- MockRead("world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- const char* const kExpectedResponseData[] = {
- "hello", "world"
- };
- for (const auto* expected_response_data : kExpectedResponseData) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_TRUE(response->proxy_server.is_direct());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ(expected_response_data, response_data);
- }
- }
- TEST_F(HttpNetworkTransactionTest, Ignores100) {
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(
- std::make_unique<UploadBytesElementReader>("foo", 3));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.foo.com/");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Check the upload progress returned before initialization is correct.
- UploadProgress progress = request.upload_data_stream->GetUploadProgress();
- EXPECT_EQ(0u, progress.size());
- EXPECT_EQ(0u, progress.position());
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 100 Continue\r\n\r\n"),
- MockRead("HTTP/1.0 200 OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- }
- // This test is almost the same as Ignores100 above, but the response contains
- // a 102 instead of a 100. Also, instead of HTTP/1.0 the response is
- // HTTP/1.1 and the two status headers are read in one read.
- TEST_F(HttpNetworkTransactionTest, Ignores1xx) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.foo.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 102 Unspecified status code\r\n\r\n"
- "HTTP/1.1 200 OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- }
- TEST_F(HttpNetworkTransactionTest, LoadTimingMeasuresTimeToFirstByteForHttp) {
- static const base::TimeDelta kDelayAfterFirstByte = base::Milliseconds(10);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.foo.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::vector<MockWrite> data_writes = {
- MockWrite(ASYNC, 0,
- "GET / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- std::vector<MockRead> data_reads = {
- // Write one byte of the status line, followed by a pause.
- MockRead(ASYNC, 1, "H"),
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- MockRead(ASYNC, 3, "TTP/1.1 200 OK\r\n\r\n"),
- MockRead(ASYNC, 4, "hello world"),
- MockRead(SYNCHRONOUS, OK, 5),
- };
- SequencedSocketData data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- data.RunUntilPaused();
- ASSERT_TRUE(data.IsPaused());
- FastForwardBy(kDelayAfterFirstByte);
- data.Resume();
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- EXPECT_FALSE(load_timing_info.receive_headers_start.is_null());
- EXPECT_FALSE(load_timing_info.connect_timing.connect_end.is_null());
- // Ensure we didn't include the delay in the TTFB time.
- EXPECT_EQ(load_timing_info.receive_headers_start,
- load_timing_info.connect_timing.connect_end);
- // Ensure that the mock clock advanced at all.
- EXPECT_EQ(base::TimeTicks::Now() - load_timing_info.receive_headers_start,
- kDelayAfterFirstByte);
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- }
- // Tests that the time-to-first-byte reported in a transaction's load timing
- // info uses the first response, even if 1XX/informational.
- void HttpNetworkTransactionTest::Check100ResponseTiming(bool use_spdy) {
- static const base::TimeDelta kDelayAfter100Response = base::Milliseconds(10);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.foo.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::vector<MockWrite> data_writes;
- std::vector<MockRead> data_reads;
- spdy::SpdySerializedFrame spdy_req(
- spdy_util_.ConstructSpdyGet(request.url.spec().c_str(), 1, LOWEST));
- spdy::Http2HeaderBlock spdy_resp1_headers;
- spdy_resp1_headers[spdy::kHttp2StatusHeader] = "100";
- spdy::SpdySerializedFrame spdy_resp1(
- spdy_util_.ConstructSpdyReply(1, spdy_resp1_headers.Clone()));
- spdy::SpdySerializedFrame spdy_resp2(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame spdy_data(
- spdy_util_.ConstructSpdyDataFrame(1, "hello world", true));
- if (use_spdy) {
- ssl.next_proto = kProtoHTTP2;
- data_writes = {CreateMockWrite(spdy_req, 0)};
- data_reads = {
- CreateMockRead(spdy_resp1, 1), MockRead(ASYNC, ERR_IO_PENDING, 2),
- CreateMockRead(spdy_resp2, 3), CreateMockRead(spdy_data, 4),
- MockRead(SYNCHRONOUS, OK, 5),
- };
- } else {
- data_writes = {
- MockWrite(ASYNC, 0,
- "GET / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- data_reads = {
- MockRead(ASYNC, 1, "HTTP/1.1 100 Continue\r\n\r\n"),
- MockRead(ASYNC, ERR_IO_PENDING, 2),
- MockRead(ASYNC, 3, "HTTP/1.1 200 OK\r\n\r\n"),
- MockRead(ASYNC, 4, "hello world"),
- MockRead(SYNCHRONOUS, OK, 5),
- };
- }
- SequencedSocketData data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- data.RunUntilPaused();
- // We should now have parsed the 100 response and hit ERR_IO_PENDING. Insert
- // the delay before parsing the 200 response.
- ASSERT_TRUE(data.IsPaused());
- FastForwardBy(kDelayAfter100Response);
- data.Resume();
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- EXPECT_FALSE(load_timing_info.receive_headers_start.is_null());
- EXPECT_FALSE(load_timing_info.connect_timing.connect_end.is_null());
- // Ensure we didn't include the delay in the TTFB time.
- EXPECT_EQ(load_timing_info.receive_headers_start,
- load_timing_info.connect_timing.connect_end);
- // Ensure that the mock clock advanced at all.
- EXPECT_EQ(base::TimeTicks::Now() - load_timing_info.receive_headers_start,
- kDelayAfter100Response);
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- }
- TEST_F(HttpNetworkTransactionTest, MeasuresTimeToFirst100ResponseForHttp) {
- Check100ResponseTiming(false /* use_spdy */);
- }
- TEST_F(HttpNetworkTransactionTest, MeasuresTimeToFirst100ResponseForSpdy) {
- Check100ResponseTiming(true /* use_spdy */);
- }
- TEST_F(HttpNetworkTransactionTest, Incomplete100ThenEOF) {
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.foo.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockRead data_reads[] = {
- MockRead(SYNCHRONOUS, "HTTP/1.0 100 Continue\r\n"),
- MockRead(ASYNC, 0),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("", response_data);
- }
- TEST_F(HttpNetworkTransactionTest, EmptyResponse) {
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.foo.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockRead data_reads[] = {
- MockRead(ASYNC, 0),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_EMPTY_RESPONSE));
- }
- void HttpNetworkTransactionTest::KeepAliveConnectionResendRequestTest(
- const MockWrite* write_failure,
- const MockRead* read_failure) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.foo.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Written data for successfully sending both requests.
- MockWrite data1_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n\r\n")
- };
- // Read results for the first request.
- MockRead data1_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
- MockRead("hello"),
- MockRead(ASYNC, OK),
- };
- if (write_failure) {
- ASSERT_FALSE(read_failure);
- data1_writes[1] = *write_failure;
- } else {
- ASSERT_TRUE(read_failure);
- data1_reads[2] = *read_failure;
- }
- StaticSocketDataProvider data1(data1_reads, data1_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- MockRead data2_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
- MockRead("world"),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider data2(data2_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- const char* const kExpectedResponseData[] = {
- "hello", "world"
- };
- uint32_t first_socket_log_id = NetLogSource::kInvalidId;
- for (int i = 0; i < 2; ++i) {
- TestCompletionCallback callback;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_DNS_TIMES);
- if (i == 0) {
- first_socket_log_id = load_timing_info.socket_log_id;
- } else {
- // The second request should be using a new socket.
- EXPECT_NE(first_socket_log_id, load_timing_info.socket_log_id);
- }
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_TRUE(response->proxy_server.is_direct());
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ(kExpectedResponseData[i], response_data);
- }
- }
- void HttpNetworkTransactionTest::PreconnectErrorResendRequestTest(
- const MockWrite* write_failure,
- const MockRead* read_failure,
- bool use_spdy,
- bool chunked_upload) {
- SpdyTestUtil spdy_util;
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.foo.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- const char upload_data[] = "foobar";
- ChunkedUploadDataStream upload_data_stream(0);
- if (chunked_upload) {
- request.method = "POST";
- upload_data_stream.AppendData(upload_data, std::size(upload_data) - 1,
- true);
- request.upload_data_stream = &upload_data_stream;
- }
- session_deps_.net_log = net::NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- SSLSocketDataProvider ssl1(ASYNC, OK);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- if (use_spdy) {
- ssl1.next_proto = kProtoHTTP2;
- ssl2.next_proto = kProtoHTTP2;
- }
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- // SPDY versions of the request and response.
- spdy::Http2HeaderBlock spdy_post_header_block;
- spdy_post_header_block[spdy::kHttp2MethodHeader] = "POST";
- spdy_util.AddUrlToHeaderBlock(request.url.spec(), &spdy_post_header_block);
- spdy::SpdySerializedFrame spdy_request(
- chunked_upload
- ? spdy_util.ConstructSpdyHeaders(1, std::move(spdy_post_header_block),
- DEFAULT_PRIORITY, false)
- : spdy_util.ConstructSpdyGet(request.url.spec().c_str(), 1,
- DEFAULT_PRIORITY));
- spdy::SpdySerializedFrame spdy_request_body(
- spdy_util.ConstructSpdyDataFrame(1, "foobar", true));
- spdy::SpdySerializedFrame spdy_response(
- spdy_util.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame spdy_data(
- spdy_util.ConstructSpdyDataFrame(1, "hello", true));
- // HTTP/1.1 versions of the request and response.
- const std::string http_request =
- std::string(chunked_upload ? "POST" : "GET") +
- " / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n" +
- (chunked_upload ? "Transfer-Encoding: chunked\r\n\r\n" : "\r\n");
- const char* kHttpRequest = http_request.c_str();
- const char kHttpResponse[] = "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n";
- const char kHttpData[] = "hello";
- std::vector<MockRead> data1_reads;
- std::vector<MockWrite> data1_writes;
- if (write_failure) {
- ASSERT_FALSE(read_failure);
- data1_writes.push_back(*write_failure);
- data1_reads.emplace_back(ASYNC, OK);
- } else {
- ASSERT_TRUE(read_failure);
- if (use_spdy) {
- data1_writes.push_back(CreateMockWrite(spdy_request));
- if (chunked_upload)
- data1_writes.push_back(CreateMockWrite(spdy_request_body));
- } else {
- data1_writes.emplace_back(kHttpRequest);
- if (chunked_upload) {
- data1_writes.emplace_back("6\r\nfoobar\r\n");
- data1_writes.emplace_back("0\r\n\r\n");
- }
- }
- data1_reads.push_back(*read_failure);
- }
- StaticSocketDataProvider data1(data1_reads, data1_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- std::vector<MockRead> data2_reads;
- std::vector<MockWrite> data2_writes;
- if (use_spdy) {
- int seq = 0;
- data2_writes.push_back(CreateMockWrite(spdy_request, seq++, ASYNC));
- if (chunked_upload)
- data2_writes.push_back(CreateMockWrite(spdy_request_body, seq++, ASYNC));
- data2_reads.push_back(CreateMockRead(spdy_response, seq++, ASYNC));
- data2_reads.push_back(CreateMockRead(spdy_data, seq++, ASYNC));
- data2_reads.emplace_back(ASYNC, OK, seq++);
- } else {
- int seq = 0;
- data2_writes.emplace_back(ASYNC, kHttpRequest, strlen(kHttpRequest), seq++);
- if (chunked_upload) {
- data2_writes.emplace_back(ASYNC, "6\r\nfoobar\r\n", 11, seq++);
- data2_writes.emplace_back(ASYNC, "0\r\n\r\n", 5, seq++);
- }
- data2_reads.emplace_back(ASYNC, kHttpResponse, strlen(kHttpResponse),
- seq++);
- data2_reads.emplace_back(ASYNC, kHttpData, strlen(kHttpData), seq++);
- data2_reads.emplace_back(ASYNC, OK, seq++);
- }
- SequencedSocketData data2(data2_reads, data2_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- // Preconnect a socket.
- session->http_stream_factory()->PreconnectStreams(1, request);
- // Wait for the preconnect to complete.
- // TODO(davidben): Some way to wait for an idle socket count might be handy.
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- // Make the request.
- TestCompletionCallback callback;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(
- load_timing_info,
- CONNECT_TIMING_HAS_DNS_TIMES|CONNECT_TIMING_HAS_SSL_TIMES);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- if (response->was_fetched_via_spdy) {
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- } else {
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- }
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ(kHttpData, response_data);
- }
- // Test that we do not retry indefinitely when a server sends an error like
- // ERR_HTTP2_PING_FAILED, ERR_HTTP2_SERVER_REFUSED_STREAM,
- // ERR_QUIC_HANDSHAKE_FAILED or ERR_QUIC_PROTOCOL_ERROR.
- TEST_F(HttpNetworkTransactionTest, FiniteRetriesOnIOError) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.foo.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Check whether we give up after the third try.
- // Construct an HTTP2 request and a "Go away" response.
- spdy::SpdySerializedFrame spdy_request(spdy_util_.ConstructSpdyGet(
- request.url.spec().c_str(), 1, DEFAULT_PRIORITY));
- spdy::SpdySerializedFrame spdy_response_go_away(
- spdy_util_.ConstructSpdyGoAway(0));
- MockRead data_read1[] = {CreateMockRead(spdy_response_go_away)};
- MockWrite data_write[] = {CreateMockWrite(spdy_request, 0)};
- // Three go away responses.
- StaticSocketDataProvider data1(data_read1, data_write);
- StaticSocketDataProvider data2(data_read1, data_write);
- StaticSocketDataProvider data3(data_read1, data_write);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- AddSSLSocketData();
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- AddSSLSocketData();
- session_deps_.socket_factory->AddSocketDataProvider(&data3);
- AddSSLSocketData();
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_HTTP2_SERVER_REFUSED_STREAM));
- }
- TEST_F(HttpNetworkTransactionTest, RetryTwiceOnIOError) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.foo.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Check whether we try atleast thrice before giving up.
- // Construct an HTTP2 request and a "Go away" response.
- spdy::SpdySerializedFrame spdy_request(spdy_util_.ConstructSpdyGet(
- request.url.spec().c_str(), 1, DEFAULT_PRIORITY));
- spdy::SpdySerializedFrame spdy_response_go_away(
- spdy_util_.ConstructSpdyGoAway(0));
- MockRead data_read1[] = {CreateMockRead(spdy_response_go_away)};
- MockWrite data_write[] = {CreateMockWrite(spdy_request, 0)};
- // Construct a non error HTTP2 response.
- spdy::SpdySerializedFrame spdy_response_no_error(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame spdy_data(
- spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead data_read2[] = {CreateMockRead(spdy_response_no_error, 1),
- CreateMockRead(spdy_data, 2)};
- // Two error responses.
- StaticSocketDataProvider data1(data_read1, data_write);
- StaticSocketDataProvider data2(data_read1, data_write);
- // Followed by a success response.
- SequencedSocketData data3(data_read2, data_write);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- AddSSLSocketData();
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- AddSSLSocketData();
- session_deps_.socket_factory->AddSocketDataProvider(&data3);
- AddSSLSocketData();
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- }
- TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionNotConnectedOnWrite) {
- MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED);
- KeepAliveConnectionResendRequestTest(&write_failure, nullptr);
- }
- TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionReset) {
- MockRead read_failure(ASYNC, ERR_CONNECTION_RESET);
- KeepAliveConnectionResendRequestTest(nullptr, &read_failure);
- }
- TEST_F(HttpNetworkTransactionTest, KeepAliveConnectionEOF) {
- MockRead read_failure(SYNCHRONOUS, OK); // EOF
- KeepAliveConnectionResendRequestTest(nullptr, &read_failure);
- }
- // Make sure that on a 408 response (Request Timeout), the request is retried,
- // if the socket was a reused keep alive socket.
- TEST_F(HttpNetworkTransactionTest, KeepAlive408) {
- MockRead read_failure(SYNCHRONOUS,
- "HTTP/1.1 408 Request Timeout\r\n"
- "Connection: Keep-Alive\r\n"
- "Content-Length: 6\r\n\r\n"
- "Pickle");
- KeepAliveConnectionResendRequestTest(nullptr, &read_failure);
- }
- TEST_F(HttpNetworkTransactionTest, PreconnectErrorNotConnectedOnWrite) {
- MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED);
- PreconnectErrorResendRequestTest(&write_failure, nullptr,
- false /* use_spdy */);
- PreconnectErrorResendRequestTest(
- &write_failure, nullptr, false /* use_spdy */, true /* chunked_upload */);
- }
- TEST_F(HttpNetworkTransactionTest, PreconnectErrorReset) {
- MockRead read_failure(ASYNC, ERR_CONNECTION_RESET);
- PreconnectErrorResendRequestTest(nullptr, &read_failure,
- false /* use_spdy */);
- PreconnectErrorResendRequestTest(nullptr, &read_failure, false /* use_spdy */,
- true /* chunked_upload */);
- }
- TEST_F(HttpNetworkTransactionTest, PreconnectErrorEOF) {
- MockRead read_failure(SYNCHRONOUS, OK); // EOF
- PreconnectErrorResendRequestTest(nullptr, &read_failure,
- false /* use_spdy */);
- PreconnectErrorResendRequestTest(nullptr, &read_failure, false /* use_spdy */,
- true /* chunked_upload */);
- }
- TEST_F(HttpNetworkTransactionTest, PreconnectErrorAsyncEOF) {
- MockRead read_failure(ASYNC, OK); // EOF
- PreconnectErrorResendRequestTest(nullptr, &read_failure,
- false /* use_spdy */);
- PreconnectErrorResendRequestTest(nullptr, &read_failure, false /* use_spdy */,
- true /* chunked_upload */);
- }
- // Make sure that on a 408 response (Request Timeout), the request is retried,
- // if the socket was a preconnected (UNUSED_IDLE) socket.
- TEST_F(HttpNetworkTransactionTest, RetryOnIdle408) {
- MockRead read_failure(SYNCHRONOUS,
- "HTTP/1.1 408 Request Timeout\r\n"
- "Connection: Keep-Alive\r\n"
- "Content-Length: 6\r\n\r\n"
- "Pickle");
- KeepAliveConnectionResendRequestTest(nullptr, &read_failure);
- PreconnectErrorResendRequestTest(nullptr, &read_failure,
- false /* use_spdy */);
- PreconnectErrorResendRequestTest(nullptr, &read_failure, false /* use_spdy */,
- true /* chunked_upload */);
- }
- TEST_F(HttpNetworkTransactionTest, SpdyPreconnectErrorNotConnectedOnWrite) {
- MockWrite write_failure(ASYNC, ERR_SOCKET_NOT_CONNECTED);
- PreconnectErrorResendRequestTest(&write_failure, nullptr,
- true /* use_spdy */);
- PreconnectErrorResendRequestTest(&write_failure, nullptr, true /* use_spdy */,
- true /* chunked_upload */);
- }
- TEST_F(HttpNetworkTransactionTest, SpdyPreconnectErrorReset) {
- MockRead read_failure(ASYNC, ERR_CONNECTION_RESET);
- PreconnectErrorResendRequestTest(nullptr, &read_failure, true /* use_spdy */);
- PreconnectErrorResendRequestTest(nullptr, &read_failure, true /* use_spdy */,
- true /* chunked_upload */);
- }
- TEST_F(HttpNetworkTransactionTest, SpdyPreconnectErrorEOF) {
- MockRead read_failure(SYNCHRONOUS, OK); // EOF
- PreconnectErrorResendRequestTest(nullptr, &read_failure, true /* use_spdy */);
- PreconnectErrorResendRequestTest(nullptr, &read_failure, true /* use_spdy */,
- true /* chunked_upload */);
- }
- TEST_F(HttpNetworkTransactionTest, SpdyPreconnectErrorAsyncEOF) {
- MockRead read_failure(ASYNC, OK); // EOF
- PreconnectErrorResendRequestTest(nullptr, &read_failure, true /* use_spdy */);
- PreconnectErrorResendRequestTest(nullptr, &read_failure, true /* use_spdy */,
- true /* chunked_upload */);
- }
- TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionReset) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockRead data_reads[] = {
- MockRead(ASYNC, ERR_CONNECTION_RESET),
- MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
- IPEndPoint endpoint;
- EXPECT_TRUE(trans.GetRemoteEndpoint(&endpoint));
- EXPECT_LT(0u, endpoint.address().size());
- }
- // What do various browsers do when the server closes a non-keepalive
- // connection without sending any response header or body?
- //
- // IE7: error page
- // Safari 3.1.2 (Windows): error page
- // Firefox 3.0.1: blank page
- // Opera 9.52: after five attempts, blank page
- // Us with WinHTTP: error page (ERR_INVALID_RESPONSE)
- // Us: error page (EMPTY_RESPONSE)
- TEST_F(HttpNetworkTransactionTest, NonKeepAliveConnectionEOF) {
- MockRead data_reads[] = {
- MockRead(SYNCHRONOUS, OK), // EOF
- MockRead("HTTP/1.0 200 OK\r\n\r\n"), // Should not be used
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- SimpleGetHelperResult out = SimpleGetHelper(data_reads);
- EXPECT_THAT(out.rv, IsError(ERR_EMPTY_RESPONSE));
- }
- // Next 2 cases (KeepAliveEarlyClose and KeepAliveEarlyClose2) are regression
- // tests. There was a bug causing HttpNetworkTransaction to hang in the
- // destructor in such situations.
- // See http://crbug.com/154712 and http://crbug.com/156609.
- TEST_F(HttpNetworkTransactionTest, KeepAliveEarlyClose) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Connection: keep-alive\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead("hello"),
- MockRead(SYNCHRONOUS, 0),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- scoped_refptr<IOBufferWithSize> io_buf =
- base::MakeRefCounted<IOBufferWithSize>(100);
- rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback());
- if (rv == ERR_IO_PENDING)
- rv = callback.WaitForResult();
- EXPECT_EQ(5, rv);
- rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback());
- EXPECT_THAT(rv, IsError(ERR_CONTENT_LENGTH_MISMATCH));
- trans.reset();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- TEST_F(HttpNetworkTransactionTest, KeepAliveEarlyClose2) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Connection: keep-alive\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, 0),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- scoped_refptr<IOBufferWithSize> io_buf(
- base::MakeRefCounted<IOBufferWithSize>(100));
- rv = trans->Read(io_buf.get(), io_buf->size(), callback.callback());
- if (rv == ERR_IO_PENDING)
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_CONTENT_LENGTH_MISMATCH));
- trans.reset();
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- // Test that we correctly reuse a keep-alive connection after not explicitly
- // reading the body.
- TEST_F(HttpNetworkTransactionTest, KeepAliveAfterUnreadBody) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.foo.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- const char* request_data =
- "GET / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n\r\n";
- MockWrite data_writes[] = {
- MockWrite(ASYNC, 0, request_data), MockWrite(ASYNC, 2, request_data),
- MockWrite(ASYNC, 4, request_data), MockWrite(ASYNC, 6, request_data),
- MockWrite(ASYNC, 8, request_data), MockWrite(ASYNC, 10, request_data),
- MockWrite(ASYNC, 12, request_data), MockWrite(ASYNC, 14, request_data),
- MockWrite(ASYNC, 17, request_data), MockWrite(ASYNC, 20, request_data),
- };
- // Note that because all these reads happen in the same
- // StaticSocketDataProvider, it shows that the same socket is being reused for
- // all transactions.
- MockRead data_reads[] = {
- MockRead(ASYNC, 1, "HTTP/1.1 204 No Content\r\n\r\n"),
- MockRead(ASYNC, 3, "HTTP/1.1 205 Reset Content\r\n\r\n"),
- MockRead(ASYNC, 5, "HTTP/1.1 304 Not Modified\r\n\r\n"),
- MockRead(ASYNC, 7,
- "HTTP/1.1 302 Found\r\n"
- "Content-Length: 0\r\n\r\n"),
- MockRead(ASYNC, 9,
- "HTTP/1.1 302 Found\r\n"
- "Content-Length: 5\r\n\r\n"
- "hello"),
- MockRead(ASYNC, 11,
- "HTTP/1.1 301 Moved Permanently\r\n"
- "Content-Length: 0\r\n\r\n"),
- MockRead(ASYNC, 13,
- "HTTP/1.1 301 Moved Permanently\r\n"
- "Content-Length: 5\r\n\r\n"
- "hello"),
- // In the next two rounds, IsConnectedAndIdle returns false, due to
- // the set_busy_before_sync_reads(true) call, while the
- // HttpNetworkTransaction is being shut down, but the socket is still
- // reuseable. See http://crbug.com/544255.
- MockRead(ASYNC, 15,
- "HTTP/1.1 200 Hunky-Dory\r\n"
- "Content-Length: 5\r\n\r\n"),
- MockRead(SYNCHRONOUS, 16, "hello"),
- MockRead(ASYNC, 18,
- "HTTP/1.1 200 Hunky-Dory\r\n"
- "Content-Length: 5\r\n\r\n"
- "he"),
- MockRead(SYNCHRONOUS, 19, "llo"),
- // The body of the final request is actually read.
- MockRead(ASYNC, 21, "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
- MockRead(ASYNC, 22, "hello"),
- };
- SequencedSocketData data(data_reads, data_writes);
- data.set_busy_before_sync_reads(true);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- const int kNumUnreadBodies = std::size(data_writes) - 1;
- std::string response_lines[kNumUnreadBodies];
- uint32_t first_socket_log_id = NetLogSource::kInvalidId;
- for (size_t i = 0; i < kNumUnreadBodies; ++i) {
- TestCompletionCallback callback;
- auto trans = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
- session.get());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
- if (i == 0) {
- TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_DNS_TIMES);
- first_socket_log_id = load_timing_info.socket_log_id;
- } else {
- TestLoadTimingReused(load_timing_info);
- EXPECT_EQ(first_socket_log_id, load_timing_info.socket_log_id);
- }
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- response_lines[i] = response->headers->GetStatusLine();
- // Delete the transaction without reading the response bodies. Then spin
- // the message loop, so the response bodies are drained.
- trans.reset();
- base::RunLoop().RunUntilIdle();
- }
- const char* const kStatusLines[] = {
- "HTTP/1.1 204 No Content",
- "HTTP/1.1 205 Reset Content",
- "HTTP/1.1 304 Not Modified",
- "HTTP/1.1 302 Found",
- "HTTP/1.1 302 Found",
- "HTTP/1.1 301 Moved Permanently",
- "HTTP/1.1 301 Moved Permanently",
- "HTTP/1.1 200 Hunky-Dory",
- "HTTP/1.1 200 Hunky-Dory",
- };
- static_assert(kNumUnreadBodies == std::size(kStatusLines),
- "forgot to update kStatusLines");
- for (int i = 0; i < kNumUnreadBodies; ++i)
- EXPECT_EQ(kStatusLines[i], response_lines[i]);
- TestCompletionCallback callback;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello", response_data);
- }
- // Sockets that receive extra data after a response is complete should not be
- // reused.
- TEST_F(HttpNetworkTransactionTest, KeepAliveWithUnusedData1) {
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockWrite data_writes1[] = {
- MockWrite("HEAD / HTTP/1.1\r\n"
- "Host: www.borked.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 22\r\n\r\n"
- "This server is borked."),
- };
- MockWrite data_writes2[] = {
- MockWrite("GET /foo HTTP/1.1\r\n"
- "Host: www.borked.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Content-Length: 3\r\n\r\n"
- "foo"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback;
- HttpRequestInfo request1;
- request1.method = "HEAD";
- request1.url = GURL("http://www.borked.com/");
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto trans1 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
- ASSERT_TRUE(response1);
- ASSERT_TRUE(response1->headers);
- EXPECT_EQ(200, response1->headers->response_code());
- EXPECT_TRUE(response1->headers->IsKeepAlive());
- std::string response_data1;
- EXPECT_THAT(ReadTransaction(trans1.get(), &response_data1), IsOk());
- EXPECT_EQ("", response_data1);
- // Deleting the transaction attempts to release the socket back into the
- // socket pool.
- trans1.reset();
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("http://www.borked.com/foo");
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto trans2 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response2 = trans2->GetResponseInfo();
- ASSERT_TRUE(response2);
- ASSERT_TRUE(response2->headers);
- EXPECT_EQ(200, response2->headers->response_code());
- std::string response_data2;
- EXPECT_THAT(ReadTransaction(trans2.get(), &response_data2), IsOk());
- EXPECT_EQ("foo", response_data2);
- }
- TEST_F(HttpNetworkTransactionTest, KeepAliveWithUnusedData2) {
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockWrite data_writes1[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.borked.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 22\r\n\r\n"
- "This server is borked."
- "Bonus data!"),
- };
- MockWrite data_writes2[] = {
- MockWrite("GET /foo HTTP/1.1\r\n"
- "Host: www.borked.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Content-Length: 3\r\n\r\n"
- "foo"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback;
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("http://www.borked.com/");
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto trans1 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
- ASSERT_TRUE(response1);
- ASSERT_TRUE(response1->headers);
- EXPECT_EQ(200, response1->headers->response_code());
- EXPECT_TRUE(response1->headers->IsKeepAlive());
- std::string response_data1;
- EXPECT_THAT(ReadTransaction(trans1.get(), &response_data1), IsOk());
- EXPECT_EQ("This server is borked.", response_data1);
- // Deleting the transaction attempts to release the socket back into the
- // socket pool.
- trans1.reset();
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("http://www.borked.com/foo");
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto trans2 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response2 = trans2->GetResponseInfo();
- ASSERT_TRUE(response2);
- ASSERT_TRUE(response2->headers);
- EXPECT_EQ(200, response2->headers->response_code());
- std::string response_data2;
- EXPECT_THAT(ReadTransaction(trans2.get(), &response_data2), IsOk());
- EXPECT_EQ("foo", response_data2);
- }
- TEST_F(HttpNetworkTransactionTest, KeepAliveWithUnusedData3) {
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockWrite data_writes1[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.borked.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Transfer-Encoding: chunked\r\n\r\n"),
- MockRead("16\r\nThis server is borked.\r\n"),
- MockRead("0\r\n\r\nBonus data!"),
- };
- MockWrite data_writes2[] = {
- MockWrite("GET /foo HTTP/1.1\r\n"
- "Host: www.borked.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Content-Length: 3\r\n\r\n"
- "foo"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback;
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("http://www.borked.com/");
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto trans1 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
- ASSERT_TRUE(response1);
- ASSERT_TRUE(response1->headers);
- EXPECT_EQ(200, response1->headers->response_code());
- EXPECT_TRUE(response1->headers->IsKeepAlive());
- std::string response_data1;
- EXPECT_THAT(ReadTransaction(trans1.get(), &response_data1), IsOk());
- EXPECT_EQ("This server is borked.", response_data1);
- // Deleting the transaction attempts to release the socket back into the
- // socket pool.
- trans1.reset();
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("http://www.borked.com/foo");
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto trans2 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response2 = trans2->GetResponseInfo();
- ASSERT_TRUE(response2);
- ASSERT_TRUE(response2->headers);
- EXPECT_EQ(200, response2->headers->response_code());
- std::string response_data2;
- EXPECT_THAT(ReadTransaction(trans2.get(), &response_data2), IsOk());
- EXPECT_EQ("foo", response_data2);
- }
- // This is a little different from the others - it tests the case that the
- // HttpStreamParser doesn't know if there's extra data on a socket or not when
- // the HttpNetworkTransaction is torn down, because the response body hasn't
- // been read from yet, but the request goes through the HttpResponseBodyDrainer.
- TEST_F(HttpNetworkTransactionTest, KeepAliveWithUnusedData4) {
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockWrite data_writes1[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.borked.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Transfer-Encoding: chunked\r\n\r\n"),
- MockRead("16\r\nThis server is borked.\r\n"),
- MockRead("0\r\n\r\nBonus data!"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- TestCompletionCallback callback;
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("http://www.borked.com/");
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response1 = trans->GetResponseInfo();
- ASSERT_TRUE(response1);
- ASSERT_TRUE(response1->headers);
- EXPECT_EQ(200, response1->headers->response_code());
- EXPECT_TRUE(response1->headers->IsKeepAlive());
- // Deleting the transaction creates an HttpResponseBodyDrainer to read the
- // response body.
- trans.reset();
- // Let the HttpResponseBodyDrainer drain the socket. It should determine the
- // socket can't be reused, rather than returning it to the socket pool.
- base::RunLoop().RunUntilIdle();
- // There should be no idle sockets in the pool.
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- // Test the request-challenge-retry sequence for basic auth.
- // (basic auth is the easiest to mock, because it has no randomness).
- TEST_F(HttpNetworkTransactionTest, BasicAuth) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes1[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- // Give a couple authenticate options (only the middle one is actually
- // supported).
- MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed.
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- // Large content-length -- won't matter, as connection will be reset.
- MockRead("Content-Length: 10000\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- // After calling trans->RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite data_writes2[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info1;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info1));
- TestLoadTimingNotReused(load_timing_info1, CONNECT_TIMING_HAS_DNS_TIMES);
- int64_t writes_size1 = CountWriteBytes(data_writes1);
- EXPECT_EQ(writes_size1, trans.GetTotalSentBytes());
- int64_t reads_size1 = CountReadBytes(data_reads1);
- EXPECT_EQ(reads_size1, trans.GetTotalReceivedBytes());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info2));
- TestLoadTimingNotReused(load_timing_info2, CONNECT_TIMING_HAS_DNS_TIMES);
- // The load timing after restart should have a new socket ID, and times after
- // those of the first load timing.
- EXPECT_LE(load_timing_info1.receive_headers_end,
- load_timing_info2.connect_timing.connect_start);
- EXPECT_NE(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
- int64_t writes_size2 = CountWriteBytes(data_writes2);
- EXPECT_EQ(writes_size1 + writes_size2, trans.GetTotalSentBytes());
- int64_t reads_size2 = CountReadBytes(data_reads2);
- EXPECT_EQ(reads_size1 + reads_size2, trans.GetTotalReceivedBytes());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(100, response->headers->GetContentLength());
- }
- // Test the request-challenge-retry sequence for basic auth.
- // (basic auth is the easiest to mock, because it has no randomness).
- TEST_F(HttpNetworkTransactionTest, BasicAuthWithAddressChange) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto resolver = std::make_unique<MockHostResolver>();
- auto* resolver_ptr = resolver.get();
- session_deps_.net_log = net::NetLog::Get();
- session_deps_.host_resolver = std::move(resolver);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- resolver_ptr->rules()->ClearRules();
- resolver_ptr->rules()->AddRule("www.example.org", "127.0.0.1");
- MockWrite data_writes1[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- // Give a couple authenticate options (only the middle one is actually
- // supported).
- MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed.
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- // Large content-length -- won't matter, as connection will be reset.
- MockRead("Content-Length: 10000\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- // After calling trans->RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite data_writes2[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"), MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback1;
- EXPECT_EQ(OK, callback1.GetResult(trans.Start(&request, callback1.callback(),
- NetLogWithSource())));
- LoadTimingInfo load_timing_info1;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info1));
- TestLoadTimingNotReused(load_timing_info1, CONNECT_TIMING_HAS_DNS_TIMES);
- int64_t writes_size1 = CountWriteBytes(data_writes1);
- EXPECT_EQ(writes_size1, trans.GetTotalSentBytes());
- int64_t reads_size1 = CountReadBytes(data_reads1);
- EXPECT_EQ(reads_size1, trans.GetTotalReceivedBytes());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge));
- IPEndPoint endpoint;
- EXPECT_TRUE(trans.GetRemoteEndpoint(&endpoint));
- ASSERT_FALSE(endpoint.address().empty());
- EXPECT_EQ("127.0.0.1:80", endpoint.ToString());
- resolver_ptr->rules()->ClearRules();
- resolver_ptr->rules()->AddRule("www.example.org", "127.0.0.2");
- TestCompletionCallback callback2;
- EXPECT_EQ(OK, callback2.GetResult(trans.RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback2.callback())));
- LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info2));
- TestLoadTimingNotReused(load_timing_info2, CONNECT_TIMING_HAS_DNS_TIMES);
- // The load timing after restart should have a new socket ID, and times after
- // those of the first load timing.
- EXPECT_LE(load_timing_info1.receive_headers_end,
- load_timing_info2.connect_timing.connect_start);
- EXPECT_NE(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
- int64_t writes_size2 = CountWriteBytes(data_writes2);
- EXPECT_EQ(writes_size1 + writes_size2, trans.GetTotalSentBytes());
- int64_t reads_size2 = CountReadBytes(data_reads2);
- EXPECT_EQ(reads_size1 + reads_size2, trans.GetTotalReceivedBytes());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(100, response->headers->GetContentLength());
- EXPECT_TRUE(trans.GetRemoteEndpoint(&endpoint));
- ASSERT_FALSE(endpoint.address().empty());
- EXPECT_EQ("127.0.0.2:80", endpoint.ToString());
- }
- // Test that, if the server requests auth indefinitely, HttpNetworkTransaction
- // will eventually give up.
- TEST_F(HttpNetworkTransactionTest, BasicAuthForever) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- // Give a couple authenticate options (only the middle one is actually
- // supported).
- MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed.
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- // Large content-length -- won't matter, as connection will be reset.
- MockRead("Content-Length: 10000\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- // After calling trans->RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite data_writes_restart[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = callback.GetResult(
- trans.Start(&request, callback.callback(), NetLogWithSource()));
- std::vector<std::unique_ptr<StaticSocketDataProvider>> data_restarts;
- for (int i = 0; i < 32; i++) {
- // Check the previous response was a 401.
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge));
- data_restarts.push_back(std::make_unique<StaticSocketDataProvider>(
- data_reads, data_writes_restart));
- session_deps_.socket_factory->AddSocketDataProvider(
- data_restarts.back().get());
- rv = callback.GetResult(trans.RestartWithAuth(AuthCredentials(kFoo, kBar),
- callback.callback()));
- }
- // After too many tries, the transaction should have given up.
- EXPECT_THAT(rv, IsError(ERR_TOO_MANY_RETRIES));
- }
- TEST_F(HttpNetworkTransactionTest, DoNotSendAuth) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.privacy_mode = PRIVACY_MODE_ENABLED;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- // Large content-length -- won't matter, as connection will be reset.
- MockRead("Content-Length: 10000\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_EQ(0, rv);
- int64_t writes_size = CountWriteBytes(data_writes);
- EXPECT_EQ(writes_size, trans.GetTotalSentBytes());
- int64_t reads_size = CountReadBytes(data_reads);
- EXPECT_EQ(reads_size, trans.GetTotalReceivedBytes());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- }
- // Test the request-challenge-retry sequence for basic auth, over a keep-alive
- // connection.
- TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAlive) {
- // On the second pass, the body read of the auth challenge is synchronous, so
- // IsConnectedAndIdle returns false. The socket should still be drained and
- // reused. See http://crbug.com/544255.
- for (int i = 0; i < 2; ++i) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockWrite data_writes[] = {
- MockWrite(ASYNC, 0,
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- // After calling trans.RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite(ASYNC, 6,
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead(ASYNC, 1, "HTTP/1.1 401 Unauthorized\r\n"),
- MockRead(ASYNC, 2, "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead(ASYNC, 3, "Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead(ASYNC, 4, "Content-Length: 14\r\n\r\n"),
- MockRead(i == 0 ? ASYNC : SYNCHRONOUS, 5, "Unauthorized\r\n"),
- // Lastly, the server responds with the actual content.
- MockRead(ASYNC, 7, "HTTP/1.1 200 OK\r\n"),
- MockRead(ASYNC, 8, "Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead(ASYNC, 9, "Content-Length: 5\r\n\r\n"),
- MockRead(ASYNC, 10, "Hello"),
- };
- SequencedSocketData data(data_reads, data_writes);
- data.set_busy_before_sync_reads(true);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- ASSERT_THAT(callback1.GetResult(rv), IsOk());
- LoadTimingInfo load_timing_info1;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info1));
- TestLoadTimingNotReused(load_timing_info1, CONNECT_TIMING_HAS_DNS_TIMES);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar),
- callback2.callback());
- ASSERT_THAT(callback2.GetResult(rv), IsOk());
- LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info2));
- TestLoadTimingReused(load_timing_info2);
- // The load timing after restart should have the same socket ID, and times
- // those of the first load timing.
- EXPECT_LE(load_timing_info1.receive_headers_end,
- load_timing_info2.send_start);
- EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(5, response->headers->GetContentLength());
- std::string response_data;
- EXPECT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- int64_t writes_size = CountWriteBytes(data_writes);
- EXPECT_EQ(writes_size, trans.GetTotalSentBytes());
- int64_t reads_size = CountReadBytes(data_reads);
- EXPECT_EQ(reads_size, trans.GetTotalReceivedBytes());
- }
- }
- // Test the request-challenge-retry sequence for basic auth, over a keep-alive
- // connection and with no response body to drain.
- TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveNoBody) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockWrite data_writes1[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- // After calling trans.RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Length: 0\r\n\r\n"), // No response body.
- // Lastly, the server responds with the actual content.
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead("hello"),
- };
- // An incorrect reconnect would cause this to be read.
- MockRead data_reads2[] = {
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(5, response->headers->GetContentLength());
- }
- // Test the request-challenge-retry sequence for basic auth, over a keep-alive
- // connection and with a large response body to drain.
- TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveLargeBody) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockWrite data_writes1[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- // After calling trans.RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- // Respond with 5 kb of response body.
- std::string large_body_string("Unauthorized");
- large_body_string.append(5 * 1024, ' ');
- large_body_string.append("\r\n");
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- // 5134 = 12 + 5 * 1024 + 2
- MockRead("Content-Length: 5134\r\n\r\n"),
- MockRead(ASYNC, large_body_string.data(), large_body_string.size()),
- // Lastly, the server responds with the actual content.
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead("hello"),
- };
- // An incorrect reconnect would cause this to be read.
- MockRead data_reads2[] = {
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(5, response->headers->GetContentLength());
- }
- // Test the request-challenge-retry sequence for basic auth, over a keep-alive
- // connection, but the server gets impatient and closes the connection.
- TEST_F(HttpNetworkTransactionTest, BasicAuthKeepAliveImpatientServer) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockWrite data_writes1[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- // This simulates the seemingly successful write to a closed connection
- // if the bug is not fixed.
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 14\r\n\r\n"),
- // Tell MockTCPClientSocket to simulate the server closing the connection.
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead("Unauthorized\r\n"),
- MockRead(SYNCHRONOUS, OK), // The server closes the connection.
- };
- // After calling trans.RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite data_writes2[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead("hello"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(5, response->headers->GetContentLength());
- }
- // Test the request-challenge-retry sequence for basic auth, over a connection
- // that requires a restart when setting up an SSL tunnel.
- TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAliveHttp10) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- // when the no authentication data flag is set.
- request.privacy_mode = PRIVACY_MODE_ENABLED;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- RecordingNetLogObserver net_log_observer;
- NetLogWithSource net_log_with_source =
- NetLogWithSource::Make(NetLogSourceType::NONE);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407, using a non-persistent
- // connection.
- MockRead data_reads1[] = {
- // No credentials.
- MockRead("HTTP/1.0 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n"),
- };
- // Since the first connection couldn't be reused, need to establish another
- // once given credentials.
- MockWrite data_writes2[] = {
- // After calling trans->RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 200 Connection Established\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead(SYNCHRONOUS, "hello"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback1;
- ConnectedHandler connected_handler;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- trans->SetConnectedCallback(connected_handler.Callback());
- int rv = trans->Start(&request, callback1.callback(), net_log_with_source);
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- auto entries = net_log_observer.GetEntries();
- size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLogEventPhase::NONE);
- ExpectLogContainsSomewhere(
- entries, pos,
- NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLogEventPhase::NONE);
- // TODO(crbug.com/986744): Fix handling of OnConnected() when proxy
- // authentication is required. We should notify the callback that a connection
- // was established, even though the stream might not be ready for us to send
- // data through it.
- EXPECT_THAT(connected_handler.transports(), IsEmpty());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->headers->IsKeepAlive());
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 0) == response->headers->GetHttpVersion());
- EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge));
- LoadTimingInfo load_timing_info;
- // CONNECT requests and responses are handled at the connect job level, so
- // the transaction does not yet have a connection.
- EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info));
- TestCompletionCallback callback2;
- rv =
- trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(5, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- TransportInfo expected_transport;
- expected_transport.type = TransportType::kProxied;
- expected_transport.endpoint = IPEndPoint(IPAddress::IPv4Localhost(), 70);
- EXPECT_THAT(connected_handler.transports(), ElementsAre(expected_transport));
- // Check that credentials were successfully cached, with the right target.
- HttpAuthCache::Entry* entry = session->http_auth_cache()->Lookup(
- url::SchemeHostPort(url::SchemeHostPort(GURL("http://myproxy:70"))),
- HttpAuth::AUTH_PROXY, "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC,
- NetworkIsolationKey());
- ASSERT_TRUE(entry);
- ASSERT_EQ(kFoo, entry->credentials().username());
- ASSERT_EQ(kBar, entry->credentials().password());
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_SSL_TIMES);
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Test the request-challenge-retry sequence for basic auth, over a connection
- // that requires a restart when setting up an SSL tunnel.
- TEST_F(HttpNetworkTransactionTest, BasicAuthProxyNoKeepAliveHttp11) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- // when the no authentication data flag is set.
- request.privacy_mode = PRIVACY_MODE_ENABLED;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- RecordingNetLogObserver net_log_observer;
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407, using a non-persistent
- // connection.
- MockRead data_reads1[] = {
- // No credentials.
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Proxy-Connection: close\r\n\r\n"),
- };
- MockWrite data_writes2[] = {
- // After calling trans->RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead(SYNCHRONOUS, "hello"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- ConnectedHandler connected_handler;
- TestCompletionCallback callback1;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- trans->SetConnectedCallback(connected_handler.Callback());
- int rv = trans->Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- auto entries = net_log_observer.GetEntries();
- size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLogEventPhase::NONE);
- ExpectLogContainsSomewhere(
- entries, pos,
- NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLogEventPhase::NONE);
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->headers->IsKeepAlive());
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge));
- EXPECT_EQ(PacResultElementToProxyServer("PROXY myproxy:70"),
- response->proxy_server);
- // TODO(crbug.com/986744): Fix handling of OnConnected() when proxy
- // authentication is required. We should notify the callback that a connection
- // was established, even though the stream might not be ready for us to send
- // data through it.
- EXPECT_THAT(connected_handler.transports(), IsEmpty());
- LoadTimingInfo load_timing_info;
- // CONNECT requests and responses are handled at the connect job level, so
- // the transaction does not yet have a connection.
- EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info));
- TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(5, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_EQ(PacResultElementToProxyServer("PROXY myproxy:70"),
- response->proxy_server);
- TransportInfo expected_transport;
- expected_transport.type = TransportType::kProxied;
- expected_transport.endpoint = IPEndPoint(IPAddress::IPv4Localhost(), 70);
- EXPECT_THAT(connected_handler.transports(), ElementsAre(expected_transport));
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_SSL_TIMES);
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Test the request-challenge-retry sequence for basic auth, over a keep-alive
- // proxy connection with HTTP/1.0 responses, when setting up an SSL tunnel.
- TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp10) {
- // On the second pass, the body read of the auth challenge is synchronous, so
- // IsConnectedAndIdle returns false. The socket should still be drained and
- // reused. See http://crbug.com/544255.
- for (int i = 0; i < 2; ++i) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- // Ensure that proxy authentication is attempted even
- // when the no authentication data flag is set.
- request.privacy_mode = PRIVACY_MODE_ENABLED;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- RecordingNetLogObserver net_log_observer;
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite(ASYNC, 0,
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- // After calling trans.RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite(ASYNC, 3,
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407, using a persistent
- // connection. (Since it's HTTP/1.0, keep-alive has to be explicit.)
- MockRead data_reads1[] = {
- // No credentials.
- MockRead(ASYNC, 1,
- "HTTP/1.0 407 Proxy Authentication Required\r\n"
- "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Content-Length: 10\r\n\r\n"),
- MockRead(i == 0 ? ASYNC : SYNCHRONOUS, 2, "0123456789"),
- // Wrong credentials (wrong password).
- MockRead(ASYNC, 4,
- "HTTP/1.0 407 Proxy Authentication Required\r\n"
- "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Content-Length: 10\r\n\r\n"),
- // No response body because the test stops reading here.
- MockRead(SYNCHRONOUS, ERR_UNEXPECTED, 5),
- };
- SequencedSocketData data1(data_reads1, data_writes1);
- data1.set_busy_before_sync_reads(true);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(callback1.GetResult(rv), IsOk());
- auto entries = net_log_observer.GetEntries();
- size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLogEventPhase::NONE);
- ExpectLogContainsSomewhere(
- entries, pos,
- NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLogEventPhase::NONE);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_EQ(10, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 0) == response->headers->GetHttpVersion());
- EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- // Wrong password (should be "bar").
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBaz),
- callback2.callback());
- EXPECT_THAT(callback2.GetResult(rv), IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_EQ(10, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 0) == response->headers->GetHttpVersion());
- EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge));
- // Flush the idle socket before the NetLog and HttpNetworkTransaction go
- // out of scope.
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- }
- // Test the request-challenge-retry sequence for basic auth, over a keep-alive
- // proxy connection with HTTP/1.1 responses, when setting up an SSL tunnel.
- TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHttp11) {
- // On the second pass, the body read of the auth challenge is synchronous, so
- // IsConnectedAndIdle returns false. The socket should still be drained and
- // reused. See http://crbug.com/544255.
- for (int i = 0; i < 2; ++i) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- // Ensure that proxy authentication is attempted even
- // when the no authentication data flag is set.
- request.privacy_mode = PRIVACY_MODE_ENABLED;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- RecordingNetLogObserver net_log_observer;
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite(ASYNC, 0,
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- // After calling trans.RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite(ASYNC, 3,
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407, using a persistent
- // connection. (Since it's HTTP/1.0, keep-alive has to be explicit.)
- MockRead data_reads1[] = {
- // No credentials.
- MockRead(ASYNC, 1,
- "HTTP/1.1 407 Proxy Authentication Required\r\n"
- "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Content-Length: 10\r\n\r\n"),
- MockRead(i == 0 ? ASYNC : SYNCHRONOUS, 2, "0123456789"),
- // Wrong credentials (wrong password).
- MockRead(ASYNC, 4,
- "HTTP/1.1 407 Proxy Authentication Required\r\n"
- "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Content-Length: 10\r\n\r\n"),
- // No response body because the test stops reading here.
- MockRead(SYNCHRONOUS, ERR_UNEXPECTED, 5),
- };
- SequencedSocketData data1(data_reads1, data_writes1);
- data1.set_busy_before_sync_reads(true);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(callback1.GetResult(rv), IsOk());
- auto entries = net_log_observer.GetEntries();
- size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLogEventPhase::NONE);
- ExpectLogContainsSomewhere(
- entries, pos,
- NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLogEventPhase::NONE);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_EQ(10, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge));
- EXPECT_FALSE(response->did_use_http_auth);
- EXPECT_EQ(PacResultElementToProxyServer("PROXY myproxy:70"),
- response->proxy_server);
- TestCompletionCallback callback2;
- // Wrong password (should be "bar").
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBaz),
- callback2.callback());
- EXPECT_THAT(callback2.GetResult(rv), IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_EQ(10, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge));
- EXPECT_TRUE(response->did_use_http_auth);
- EXPECT_EQ(PacResultElementToProxyServer("PROXY myproxy:70"),
- response->proxy_server);
- // Flush the idle socket before the NetLog and HttpNetworkTransaction go
- // out of scope.
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- }
- // Test the request-challenge-retry sequence for basic auth, over a keep-alive
- // proxy connection with HTTP/1.1 responses, when setting up an SSL tunnel, in
- // the case the server sends extra data on the original socket, so it can't be
- // reused.
- TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveExtraData) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- // when the no authentication data flag is set.
- request.privacy_mode = PRIVACY_MODE_ENABLED;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- RecordingNetLogObserver net_log_observer;
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite(ASYNC, 0,
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407, using a persistent, but sends
- // extra data, so the socket cannot be reused.
- MockRead data_reads1[] = {
- // No credentials.
- MockRead(ASYNC, 1,
- "HTTP/1.1 407 Proxy Authentication Required\r\n"
- "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Content-Length: 10\r\n\r\n"),
- MockRead(SYNCHRONOUS, 2, "0123456789"),
- MockRead(SYNCHRONOUS, 3, "I'm broken!"),
- };
- MockWrite data_writes2[] = {
- // After calling trans->RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite(ASYNC, 0,
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- MockWrite(ASYNC, 2,
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead(ASYNC, 1, "HTTP/1.1 200 Connection Established\r\n\r\n"),
- MockRead(ASYNC, 3,
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/html; charset=iso-8859-1\r\n"
- "Content-Length: 5\r\n\r\n"),
- // No response body because the test stops reading here.
- MockRead(SYNCHRONOUS, ERR_UNEXPECTED, 4),
- };
- SequencedSocketData data1(data_reads1, data_writes1);
- data1.set_busy_before_sync_reads(true);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SequencedSocketData data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback1;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(callback1.GetResult(rv), IsOk());
- auto entries = net_log_observer.GetEntries();
- size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLogEventPhase::NONE);
- ExpectLogContainsSomewhere(
- entries, pos,
- NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLogEventPhase::NONE);
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge));
- LoadTimingInfo load_timing_info;
- // CONNECT requests and responses are handled at the connect job level, so
- // the transaction does not yet have a connection.
- EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info));
- TestCompletionCallback callback2;
- rv =
- trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(callback2.GetResult(rv), IsOk());
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(5, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_SSL_TIMES);
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Test the case a proxy closes a socket while the challenge body is being
- // drained.
- TEST_F(HttpNetworkTransactionTest, BasicAuthProxyKeepAliveHangupDuringBody) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- // Ensure that proxy authentication is attempted even
- // when the no authentication data flag is set.
- request.privacy_mode = PRIVACY_MODE_ENABLED;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407, using a persistent
- // connection.
- MockRead data_reads1[] = {
- // No credentials.
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Length: 10\r\n\r\n"), MockRead("spam!"),
- // Server hands up in the middle of the body.
- MockRead(ASYNC, ERR_CONNECTION_CLOSED),
- };
- MockWrite data_writes2[] = {
- // After calling trans.RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead(SYNCHRONOUS, "hello"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge));
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- std::string body;
- EXPECT_THAT(ReadTransaction(&trans, &body), IsOk());
- EXPECT_EQ("hello", body);
- }
- // Test that we don't read the response body when we fail to establish a tunnel,
- // even if the user cancels the proxy's auth attempt.
- TEST_F(HttpNetworkTransactionTest, BasicAuthProxyCancelTunnel) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407.
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Length: 10\r\n\r\n"),
- MockRead("0123456789"),
- MockRead(SYNCHRONOUS, ERR_UNEXPECTED),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
- // Flush the idle socket before the HttpNetworkTransaction goes out of scope.
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Test the no-tunnel HTTP auth case where proxy and server origins and realms
- // are the same, but the user/passwords are different. Serves to verify
- // credentials are correctly separated based on HttpAuth::Target.
- TEST_F(HttpNetworkTransactionTest, BasicAuthProxyMatchesServerAuthNoTunnel) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://myproxy:70/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Proxy matches request URL.
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- NetLogWithSource net_log_with_source =
- NetLogWithSource::Make(NetLogSourceType::NONE);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockWrite data_writes[] = {
- // Initial request gets a proxy auth challenge.
- MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- // Retry with proxy auth credentials, which will result in a server auth
- // challenge.
- MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- // Retry with proxy and server auth credentials, which gets a response.
- MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
- "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
- // A second request should preemptively send the correct proxy and server
- // auth headers.
- MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
- "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
- };
- MockRead data_reads[] = {
- // Proxy auth challenge.
- MockRead("HTTP/1.0 407 Proxy Authentication Required\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Content-Length: 0\r\n\r\n"),
- // Server auth challenge.
- MockRead("HTTP/1.0 401 Authentication Required\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Content-Length: 0\r\n\r\n"),
- // Response.
- MockRead("HTTP/1.1 200 OK\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Content-Length: 5\r\n\r\n"
- "hello"),
- // Response to second request.
- MockRead("HTTP/1.1 200 OK\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Content-Length: 2\r\n\r\n"
- "hi"),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), net_log_with_source);
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge));
- rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(401, response->headers->response_code());
- EXPECT_FALSE(response->auth_challenge->is_proxy);
- EXPECT_EQ("http://myproxy:70",
- response->auth_challenge->challenger.Serialize());
- EXPECT_EQ("MyRealm1", response->auth_challenge->realm);
- EXPECT_EQ(kBasicAuthScheme, response->auth_challenge->scheme);
- rv = trans->RestartWithAuth(AuthCredentials(kFoo2, kBar2),
- callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(200, response->headers->response_code());
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- std::string response_data;
- EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello", response_data);
- // Check that the credentials were cached correctly.
- HttpAuthCache::Entry* entry = session->http_auth_cache()->Lookup(
- url::SchemeHostPort(url::SchemeHostPort(GURL("http://myproxy:70"))),
- HttpAuth::AUTH_PROXY, "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC,
- NetworkIsolationKey());
- ASSERT_TRUE(entry);
- ASSERT_EQ(kFoo, entry->credentials().username());
- ASSERT_EQ(kBar, entry->credentials().password());
- entry = session->http_auth_cache()->Lookup(
- url::SchemeHostPort(url::SchemeHostPort(GURL("http://myproxy:70"))),
- HttpAuth::AUTH_SERVER, "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC,
- NetworkIsolationKey());
- ASSERT_TRUE(entry);
- ASSERT_EQ(kFoo2, entry->credentials().username());
- ASSERT_EQ(kBar2, entry->credentials().password());
- // Make another request, which should automatically send the correct proxy and
- // server auth credentials and get another response.
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans->Start(&request, callback.callback(), net_log_with_source);
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(200, response->headers->response_code());
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hi", response_data);
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Test the no-tunnel HTTP auth case where proxy and server origins and realms
- // are the same, but the user/passwords are different, and with different
- // NetworkIsolationKeys. Sends one request with a NIK, response to both proxy
- // and auth challenges, sends another request with another NIK, expecting only
- // the proxy credentials to be cached, and thus sees only a server auth
- // challenge. Then sends a request with the original NIK, expecting cached proxy
- // and auth credentials that match the ones used in the first request.
- //
- // Serves to verify credentials are correctly separated based on
- // HttpAuth::Target and NetworkIsolationKeys, but NetworkIsolationKey only
- // affects server credentials, not proxy credentials.
- TEST_F(HttpNetworkTransactionTest,
- BasicAuthProxyMatchesServerAuthWithNetworkIsolationKeyNoTunnel) {
- const SchemefulSite kSite1(GURL("https://foo.test/"));
- const net::NetworkIsolationKey kNetworkIsolationKey1(kSite1, kSite1);
- const SchemefulSite kSite2(GURL("https://bar.test/"));
- const net::NetworkIsolationKey kNetworkIsolationKey2(kSite2, kSite2);
- // This test would need to use a single socket without this option enabled.
- // Best to use this option when it would affect a test, as it will eventually
- // become the default behavior.
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(
- features::kPartitionConnectionsByNetworkIsolationKey);
- // Proxy matches request URL.
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- NetLogWithSource net_log_with_source =
- NetLogWithSource::Make(NetLogSourceType::NONE);
- session_deps_.net_log = NetLog::Get();
- session_deps_.key_auth_cache_server_entries_by_network_isolation_key = true;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockWrite data_writes[] = {
- // Initial request gets a proxy auth challenge.
- MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- // Retry with proxy auth credentials, which will result in a server auth
- // challenge.
- MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- // Retry with proxy and server auth credentials, which gets a response.
- MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
- "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
- // Another request to the same server and using the same NIK should
- // preemptively send the correct cached proxy and server
- // auth headers.
- MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
- "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
- };
- MockRead data_reads[] = {
- // Proxy auth challenge.
- MockRead("HTTP/1.0 407 Proxy Authentication Required\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Content-Length: 0\r\n\r\n"),
- // Server auth challenge.
- MockRead("HTTP/1.0 401 Authentication Required\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Content-Length: 0\r\n\r\n"),
- // Response.
- MockRead("HTTP/1.1 200 OK\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Content-Length: 5\r\n\r\n"
- "hello"),
- // Response to second request.
- MockRead("HTTP/1.1 200 OK\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Content-Length: 2\r\n\r\n"
- "hi"),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- MockWrite data_writes2[] = {
- // Initial request using a different NetworkIsolationKey includes the
- // cached proxy credentials, but not server credentials.
- MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- // Retry with proxy and new server auth credentials, which gets a
- // response.
- MockWrite("GET http://myproxy:70/ HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
- "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- // Server auth challenge.
- MockRead("HTTP/1.0 401 Authentication Required\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Content-Length: 0\r\n\r\n"),
- // Response.
- MockRead("HTTP/1.1 200 OK\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Content-Length: 9\r\n\r\n"
- "greetings"),
- };
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback;
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://myproxy:70/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request.network_isolation_key = kNetworkIsolationKey1;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), net_log_with_source);
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge));
- rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(401, response->headers->response_code());
- EXPECT_FALSE(response->auth_challenge->is_proxy);
- EXPECT_EQ("http://myproxy:70",
- response->auth_challenge->challenger.Serialize());
- EXPECT_EQ("MyRealm1", response->auth_challenge->realm);
- EXPECT_EQ(kBasicAuthScheme, response->auth_challenge->scheme);
- rv = trans->RestartWithAuth(AuthCredentials(kFoo2, kBar2),
- callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(200, response->headers->response_code());
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- std::string response_data;
- EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello", response_data);
- // Check that the proxy credentials were cached correctly. The should be
- // accessible with any NetworkIsolationKey.
- HttpAuthCache::Entry* entry = session->http_auth_cache()->Lookup(
- url::SchemeHostPort(url::SchemeHostPort(GURL("http://myproxy:70"))),
- HttpAuth::AUTH_PROXY, "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC,
- kNetworkIsolationKey1);
- ASSERT_TRUE(entry);
- ASSERT_EQ(kFoo, entry->credentials().username());
- ASSERT_EQ(kBar, entry->credentials().password());
- EXPECT_EQ(entry, session->http_auth_cache()->Lookup(
- url::SchemeHostPort(GURL("http://myproxy:70")),
- HttpAuth::AUTH_PROXY, "MyRealm1",
- HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2));
- // Check that the server credentials were cached correctly. The should be
- // accessible with only kNetworkIsolationKey1.
- entry = session->http_auth_cache()->Lookup(
- url::SchemeHostPort(GURL("http://myproxy:70")), HttpAuth::AUTH_SERVER,
- "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1);
- ASSERT_TRUE(entry);
- ASSERT_EQ(kFoo2, entry->credentials().username());
- ASSERT_EQ(kBar2, entry->credentials().password());
- // Looking up the server entry with another NetworkIsolationKey should fail.
- EXPECT_FALSE(session->http_auth_cache()->Lookup(
- url::SchemeHostPort(GURL("http://myproxy:70")), HttpAuth::AUTH_SERVER,
- "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2));
- // Make another request with a different NetworkIsolationKey. It should use
- // another socket, reuse the cached proxy credentials, but result in a server
- // auth challenge.
- request.network_isolation_key = kNetworkIsolationKey2;
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans->Start(&request, callback.callback(), net_log_with_source);
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(401, response->headers->response_code());
- EXPECT_FALSE(response->auth_challenge->is_proxy);
- EXPECT_EQ("http://myproxy:70",
- response->auth_challenge->challenger.Serialize());
- EXPECT_EQ("MyRealm1", response->auth_challenge->realm);
- EXPECT_EQ(kBasicAuthScheme, response->auth_challenge->scheme);
- rv = trans->RestartWithAuth(AuthCredentials(kFoo3, kBar3),
- callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(200, response->headers->response_code());
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("greetings", response_data);
- // Check that the proxy credentials are still cached.
- entry = session->http_auth_cache()->Lookup(
- url::SchemeHostPort(GURL("http://myproxy:70")), HttpAuth::AUTH_PROXY,
- "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1);
- ASSERT_TRUE(entry);
- ASSERT_EQ(kFoo, entry->credentials().username());
- ASSERT_EQ(kBar, entry->credentials().password());
- EXPECT_EQ(entry, session->http_auth_cache()->Lookup(
- url::SchemeHostPort(GURL("http://myproxy:70")),
- HttpAuth::AUTH_PROXY, "MyRealm1",
- HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2));
- // Check that the correct server credentials are cached for each
- // NetworkIsolationKey.
- entry = session->http_auth_cache()->Lookup(
- url::SchemeHostPort(GURL("http://myproxy:70")), HttpAuth::AUTH_SERVER,
- "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1);
- ASSERT_TRUE(entry);
- ASSERT_EQ(kFoo2, entry->credentials().username());
- ASSERT_EQ(kBar2, entry->credentials().password());
- entry = session->http_auth_cache()->Lookup(
- url::SchemeHostPort(GURL("http://myproxy:70")), HttpAuth::AUTH_SERVER,
- "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2);
- ASSERT_TRUE(entry);
- ASSERT_EQ(kFoo3, entry->credentials().username());
- ASSERT_EQ(kBar3, entry->credentials().password());
- // Make a request with the original NetworkIsolationKey. It should reuse the
- // first socket, and the proxy credentials sent on the first socket.
- request.network_isolation_key = kNetworkIsolationKey1;
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans->Start(&request, callback.callback(), net_log_with_source);
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(200, response->headers->response_code());
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hi", response_data);
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Much like the test above, but uses tunnelled connections.
- TEST_F(HttpNetworkTransactionTest,
- BasicAuthProxyMatchesServerAuthWithNetworkIsolationKeyWithTunnel) {
- const SchemefulSite kSite1(GURL("https://foo.test/"));
- const net::NetworkIsolationKey kNetworkIsolationKey1(kSite1, kSite1);
- const SchemefulSite kSite2(GURL("https://bar.test/"));
- const net::NetworkIsolationKey kNetworkIsolationKey2(kSite2, kSite2);
- // This test would need to use a single socket without this option enabled.
- // Best to use this option when it would affect a test, as it will eventually
- // become the default behavior.
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(
- features::kPartitionConnectionsByNetworkIsolationKey);
- // Proxy matches request URL.
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- NetLogWithSource net_log_with_source =
- NetLogWithSource::Make(NetLogSourceType::NONE);
- session_deps_.net_log = NetLog::Get();
- session_deps_.key_auth_cache_server_entries_by_network_isolation_key = true;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockWrite data_writes[] = {
- // Initial tunnel request gets a proxy auth challenge.
- MockWrite("CONNECT myproxy:70 HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- // Retry with proxy auth credentials, which will result in establishing a
- // tunnel.
- MockWrite("CONNECT myproxy:70 HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- // Request over the tunnel, which gets a server auth challenge.
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Connection: keep-alive\r\n\r\n"),
- // Retry with server auth credentials, which gets a response.
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
- // Another request to the same server and using the same NIK should
- // preemptively send the correct cached server
- // auth header. Since a tunnel was already established, the proxy headers
- // won't be sent again except when establishing another tunnel.
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
- };
- MockRead data_reads[] = {
- // Proxy auth challenge.
- MockRead("HTTP/1.0 407 Proxy Authentication Required\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Content-Length: 0\r\n\r\n"),
- // Tunnel success
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- // Server auth challenge.
- MockRead("HTTP/1.0 401 Authentication Required\r\n"
- "Connection: keep-alive\r\n"
- "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Content-Length: 0\r\n\r\n"),
- // Response.
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 5\r\n\r\n"
- "hello"),
- // Response to second request.
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 2\r\n\r\n"
- "hi"),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- // One for the proxy connection, one of the server connection.
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- MockWrite data_writes2[] = {
- // Initial request using a different NetworkIsolationKey includes the
- // cached proxy credentials when establishing a tunnel.
- MockWrite("CONNECT myproxy:70 HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- // Request over the tunnel, which gets a server auth challenge. Cached
- // credentials cannot be used, since the NIK is different.
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Connection: keep-alive\r\n\r\n"),
- // Retry with server auth credentials, which gets a response.
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: myproxy:70\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- // Tunnel success
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- // Server auth challenge.
- MockRead("HTTP/1.0 401 Authentication Required\r\n"
- "Connection: keep-alive\r\n"
- "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Content-Length: 0\r\n\r\n"),
- // Response.
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 9\r\n\r\n"
- "greetings"),
- };
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- // One for the proxy connection, one of the server connection.
- SSLSocketDataProvider ssl3(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl3);
- SSLSocketDataProvider ssl4(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl4);
- TestCompletionCallback callback;
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://myproxy:70/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request.network_isolation_key = kNetworkIsolationKey1;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), net_log_with_source);
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(CheckBasicSecureProxyAuth(response->auth_challenge));
- rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(401, response->headers->response_code());
- EXPECT_FALSE(response->auth_challenge->is_proxy);
- EXPECT_EQ("https://myproxy:70",
- response->auth_challenge->challenger.Serialize());
- EXPECT_EQ("MyRealm1", response->auth_challenge->realm);
- EXPECT_EQ(kBasicAuthScheme, response->auth_challenge->scheme);
- rv = trans->RestartWithAuth(AuthCredentials(kFoo2, kBar2),
- callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(200, response->headers->response_code());
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- std::string response_data;
- EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello", response_data);
- // Check that the proxy credentials were cached correctly. The should be
- // accessible with any NetworkIsolationKey.
- HttpAuthCache::Entry* entry = session->http_auth_cache()->Lookup(
- url::SchemeHostPort(url::SchemeHostPort(GURL("https://myproxy:70"))),
- HttpAuth::AUTH_PROXY, "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC,
- kNetworkIsolationKey1);
- ASSERT_TRUE(entry);
- ASSERT_EQ(kFoo, entry->credentials().username());
- ASSERT_EQ(kBar, entry->credentials().password());
- EXPECT_EQ(entry, session->http_auth_cache()->Lookup(
- url::SchemeHostPort(GURL("https://myproxy:70")),
- HttpAuth::AUTH_PROXY, "MyRealm1",
- HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2));
- // Check that the server credentials were cached correctly. The should be
- // accessible with only kNetworkIsolationKey1.
- entry = session->http_auth_cache()->Lookup(
- url::SchemeHostPort(GURL("https://myproxy:70")), HttpAuth::AUTH_SERVER,
- "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1);
- ASSERT_TRUE(entry);
- ASSERT_EQ(kFoo2, entry->credentials().username());
- ASSERT_EQ(kBar2, entry->credentials().password());
- // Looking up the server entry with another NetworkIsolationKey should fail.
- EXPECT_FALSE(session->http_auth_cache()->Lookup(
- url::SchemeHostPort(GURL("https://myproxy:70")), HttpAuth::AUTH_SERVER,
- "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2));
- // Make another request with a different NetworkIsolationKey. It should use
- // another socket, reuse the cached proxy credentials, but result in a server
- // auth challenge.
- request.network_isolation_key = kNetworkIsolationKey2;
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans->Start(&request, callback.callback(), net_log_with_source);
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(401, response->headers->response_code());
- EXPECT_FALSE(response->auth_challenge->is_proxy);
- EXPECT_EQ("https://myproxy:70",
- response->auth_challenge->challenger.Serialize());
- EXPECT_EQ("MyRealm1", response->auth_challenge->realm);
- EXPECT_EQ(kBasicAuthScheme, response->auth_challenge->scheme);
- rv = trans->RestartWithAuth(AuthCredentials(kFoo3, kBar3),
- callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(200, response->headers->response_code());
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("greetings", response_data);
- // Check that the proxy credentials are still cached.
- entry = session->http_auth_cache()->Lookup(
- url::SchemeHostPort(GURL("https://myproxy:70")), HttpAuth::AUTH_PROXY,
- "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1);
- ASSERT_TRUE(entry);
- ASSERT_EQ(kFoo, entry->credentials().username());
- ASSERT_EQ(kBar, entry->credentials().password());
- EXPECT_EQ(entry, session->http_auth_cache()->Lookup(
- url::SchemeHostPort(GURL("https://myproxy:70")),
- HttpAuth::AUTH_PROXY, "MyRealm1",
- HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2));
- // Check that the correct server credentials are cached for each
- // NetworkIsolationKey.
- entry = session->http_auth_cache()->Lookup(
- url::SchemeHostPort(GURL("https://myproxy:70")), HttpAuth::AUTH_SERVER,
- "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey1);
- ASSERT_TRUE(entry);
- ASSERT_EQ(kFoo2, entry->credentials().username());
- ASSERT_EQ(kBar2, entry->credentials().password());
- entry = session->http_auth_cache()->Lookup(
- url::SchemeHostPort(GURL("https://myproxy:70")), HttpAuth::AUTH_SERVER,
- "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC, kNetworkIsolationKey2);
- ASSERT_TRUE(entry);
- ASSERT_EQ(kFoo3, entry->credentials().username());
- ASSERT_EQ(kBar3, entry->credentials().password());
- // Make a request with the original NetworkIsolationKey. It should reuse the
- // first socket, and the proxy credentials sent on the first socket.
- request.network_isolation_key = kNetworkIsolationKey1;
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans->Start(&request, callback.callback(), net_log_with_source);
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(200, response->headers->response_code());
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hi", response_data);
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Test that we don't pass extraneous headers from the proxy's response to the
- // caller when the proxy responds to CONNECT with 407.
- TEST_F(HttpNetworkTransactionTest, SanitizeProxyAuthHeaders) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407.
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("X-Foo: bar\r\n"),
- MockRead("Set-Cookie: foo=bar\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Length: 10\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_UNEXPECTED),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_FALSE(response->headers->HasHeader("X-Foo"));
- EXPECT_FALSE(response->headers->HasHeader("Set-Cookie"));
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
- // Flush the idle socket before the HttpNetworkTransaction goes out of scope.
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Test when a server (non-proxy) returns a 407 (proxy-authenticate).
- // The request should fail with ERR_UNEXPECTED_PROXY_AUTH.
- TEST_F(HttpNetworkTransactionTest, UnexpectedProxyAuth) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // We are using a DIRECT connection (i.e. no proxy) for this session.
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes1[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 407 Proxy Auth required\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- // Large content-length -- won't matter, as connection will be reset.
- MockRead("Content-Length: 10000\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_UNEXPECTED_PROXY_AUTH));
- }
- // Tests when an HTTPS server (non-proxy) returns a 407 (proxy-authentication)
- // through a non-authenticating proxy. The request should fail with
- // ERR_UNEXPECTED_PROXY_AUTH.
- // Note that it is impossible to detect if an HTTP server returns a 407 through
- // a non-authenticating proxy - there is nothing to indicate whether the
- // response came from the proxy or the server, so it is treated as if the proxy
- // issued the challenge.
- TEST_F(HttpNetworkTransactionTest, HttpsServerRequestsProxyAuthThroughProxy) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- RecordingNetLogObserver net_log_observer;
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- MockRead("HTTP/1.1 407 Unauthorized\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_UNEXPECTED_PROXY_AUTH));
- auto entries = net_log_observer.GetEntries();
- size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLogEventPhase::NONE);
- ExpectLogContainsSomewhere(
- entries, pos,
- NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLogEventPhase::NONE);
- }
- // Test a proxy auth scheme that allows default credentials and a proxy server
- // that uses non-persistent connections.
- TEST_F(HttpNetworkTransactionTest,
- AuthAllowsDefaultCredentialsTunnelConnectionClose) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- auto auth_handler_factory = std::make_unique<HttpAuthHandlerMock::Factory>();
- auth_handler_factory->set_do_init_from_challenge(true);
- auto mock_handler = std::make_unique<HttpAuthHandlerMock>();
- mock_handler->set_allows_default_credentials(true);
- auth_handler_factory->AddMockHandler(std::move(mock_handler),
- HttpAuth::AUTH_PROXY);
- session_deps_.http_auth_handler_factory = std::move(auth_handler_factory);
- // Add NetLog just so can verify load timing information gets a NetLog ID.
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407, using a non-persistent
- // connection.
- MockRead data_reads1[] = {
- // No credentials.
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Mock\r\n"),
- MockRead("Proxy-Connection: close\r\n\r\n"),
- };
- // Since the first connection couldn't be reused, need to establish another
- // once given credentials.
- MockWrite data_writes2[] = {
- // After calling trans->RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: auth_token\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 200 Connection Established\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead(SYNCHRONOUS, "hello"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_FALSE(response->headers->IsKeepAlive());
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(trans->IsReadyToRestartForAuth());
- EXPECT_FALSE(response->auth_challenge.has_value());
- LoadTimingInfo load_timing_info;
- // CONNECT requests and responses are handled at the connect job level, so
- // the transaction does not yet have a connection.
- EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info));
- rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(5, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_SSL_TIMES);
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Test a proxy auth scheme that allows default credentials and a proxy server
- // that hangs up when credentials are initially sent.
- TEST_F(HttpNetworkTransactionTest,
- AuthAllowsDefaultCredentialsTunnelServerClosesConnection) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- auto auth_handler_factory = std::make_unique<HttpAuthHandlerMock::Factory>();
- auth_handler_factory->set_do_init_from_challenge(true);
- auto mock_handler = std::make_unique<HttpAuthHandlerMock>();
- mock_handler->set_allows_default_credentials(true);
- auth_handler_factory->AddMockHandler(std::move(mock_handler),
- HttpAuth::AUTH_PROXY);
- session_deps_.http_auth_handler_factory = std::move(auth_handler_factory);
- // Add NetLog just so can verify load timing information gets a NetLog ID.
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- // Should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: auth_token\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407, using a non-persistent
- // connection.
- MockRead data_reads1[] = {
- // No credentials.
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Mock\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED),
- };
- // Since the first connection was closed, need to establish another once given
- // credentials.
- MockWrite data_writes2[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: auth_token\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 200 Connection Established\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead(SYNCHRONOUS, "hello"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(trans->IsReadyToRestartForAuth());
- EXPECT_FALSE(response->auth_challenge.has_value());
- LoadTimingInfo load_timing_info;
- // CONNECT requests and responses are handled at the connect job level, so
- // the transaction does not yet have a connection.
- EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info));
- rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(5, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_SSL_TIMES);
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Test a proxy auth scheme that allows default credentials and a proxy server
- // that hangs up when credentials are initially sent, and hangs up again when
- // they are retried.
- TEST_F(HttpNetworkTransactionTest,
- AuthAllowsDefaultCredentialsTunnelServerClosesConnectionTwice) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- auto auth_handler_factory = std::make_unique<HttpAuthHandlerMock::Factory>();
- auth_handler_factory->set_do_init_from_challenge(true);
- auto mock_handler = std::make_unique<HttpAuthHandlerMock>();
- mock_handler->set_allows_default_credentials(true);
- auth_handler_factory->AddMockHandler(std::move(mock_handler),
- HttpAuth::AUTH_PROXY);
- session_deps_.http_auth_handler_factory = std::move(auth_handler_factory);
- // Add NetLog just so can verify load timing information gets a NetLog ID.
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- // Should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: auth_token\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407, and then hangs up after the
- // second request is sent.
- MockRead data_reads1[] = {
- // No credentials.
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Content-Length: 0\r\n"),
- MockRead("Proxy-Connection: keep-alive\r\n"),
- MockRead("Proxy-Authenticate: Mock\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED),
- };
- // HttpNetworkTransaction sees a reused connection that was closed with
- // ERR_CONNECTION_CLOSED, realized it might have been a race, so retries the
- // request.
- MockWrite data_writes2[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // The proxy, having had more than enough of us, just hangs up.
- MockRead data_reads2[] = {
- // No credentials.
- MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(trans->IsReadyToRestartForAuth());
- EXPECT_FALSE(response->auth_challenge.has_value());
- LoadTimingInfo load_timing_info;
- EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info));
- rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_EMPTY_RESPONSE));
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // This test exercises an odd edge case where the proxy closes the connection
- // after the authentication handshake is complete. Presumably this technique is
- // used in lieu of returning a 403 or 5xx status code when the authentication
- // succeeds, but the user is not authorized to connect to the destination
- // server. There's no standard for what a proxy should do to indicate a blocked
- // site.
- TEST_F(HttpNetworkTransactionTest,
- AuthAllowsDefaultCredentialsTunnelConnectionClosesBeforeBody) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- auto auth_handler_factory = std::make_unique<HttpAuthHandlerMock::Factory>();
- auth_handler_factory->set_do_init_from_challenge(true);
- // Create two mock AuthHandlers. This is because the transaction gets retried
- // after the first ERR_CONNECTION_CLOSED since it's ambiguous whether there
- // was a real network error.
- //
- // The handlers support both default and explicit credentials. The retry
- // mentioned above should be able to reuse the default identity. Thus there
- // should never be a need to prompt for explicit credentials.
- auto mock_handler = std::make_unique<HttpAuthHandlerMock>();
- mock_handler->set_allows_default_credentials(true);
- mock_handler->set_allows_explicit_credentials(true);
- mock_handler->set_connection_based(true);
- auth_handler_factory->AddMockHandler(std::move(mock_handler),
- HttpAuth::AUTH_PROXY);
- mock_handler = std::make_unique<HttpAuthHandlerMock>();
- mock_handler->set_allows_default_credentials(true);
- mock_handler->set_allows_explicit_credentials(true);
- mock_handler->set_connection_based(true);
- auth_handler_factory->AddMockHandler(std::move(mock_handler),
- HttpAuth::AUTH_PROXY);
- session_deps_.http_auth_handler_factory = std::move(auth_handler_factory);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- // Data for both sockets.
- //
- // Writes are for the tunnel establishment attempts and the
- // authentication handshake.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: auth_token\r\n\r\n"),
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: auth_token\r\n\r\n"),
- };
- // The server side of the authentication handshake. Note that the response to
- // the final CONNECT request is ERR_CONNECTION_CLOSED.
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Content-Length: 0\r\n"),
- MockRead("Proxy-Connection: keep-alive\r\n"),
- MockRead("Proxy-Authenticate: Mock\r\n\r\n"),
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Content-Length: 0\r\n"),
- MockRead("Proxy-Connection: keep-alive\r\n"),
- MockRead("Proxy-Authenticate: Mock foo\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- // The second socket is for the reconnection attempt. Data is identical to the
- // first attempt.
- StaticSocketDataProvider data2(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- // Two rounds per handshake. After one retry, the error is propagated up the
- // stack.
- for (int i = 0; i < 4; ++i) {
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- ASSERT_TRUE(trans->IsReadyToRestartForAuth());
- rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
- }
- // One shall be the number thou shalt retry, and the number of the retrying
- // shall be one. Two shalt thou not retry, neither retry thou zero, excepting
- // that thou then proceed to one. Three is right out. Once the number one,
- // being the first number, be reached, then lobbest thou thy
- // ERR_CONNECTION_CLOSED towards they network transaction, who shall snuff it.
- EXPECT_EQ(ERR_CONNECTION_CLOSED, callback.GetResult(rv));
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Test a proxy auth scheme that allows default credentials and a proxy server
- // that hangs up when credentials are initially sent, and sends a challenge
- // again they are retried.
- TEST_F(HttpNetworkTransactionTest,
- AuthAllowsDefaultCredentialsTunnelServerChallengesTwice) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- auto auth_handler_factory = std::make_unique<HttpAuthHandlerMock::Factory>();
- auth_handler_factory->set_do_init_from_challenge(true);
- auto mock_handler = std::make_unique<HttpAuthHandlerMock>();
- mock_handler->set_allows_default_credentials(true);
- auth_handler_factory->AddMockHandler(std::move(mock_handler),
- HttpAuth::AUTH_PROXY);
- // Add another handler for the second challenge. It supports default
- // credentials, but they shouldn't be used, since they were already tried.
- mock_handler = std::make_unique<HttpAuthHandlerMock>();
- mock_handler->set_allows_default_credentials(true);
- auth_handler_factory->AddMockHandler(std::move(mock_handler),
- HttpAuth::AUTH_PROXY);
- session_deps_.http_auth_handler_factory = std::move(auth_handler_factory);
- // Add NetLog just so can verify load timing information gets a NetLog ID.
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- // Should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407, using a non-persistent
- // connection.
- MockRead data_reads1[] = {
- // No credentials.
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Mock\r\n"),
- MockRead("Proxy-Connection: close\r\n\r\n"),
- };
- // Since the first connection was closed, need to establish another once given
- // credentials.
- MockWrite data_writes2[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: auth_token\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Mock\r\n"),
- MockRead("Proxy-Connection: close\r\n\r\n"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(trans->IsReadyToRestartForAuth());
- EXPECT_FALSE(response->auth_challenge.has_value());
- LoadTimingInfo load_timing_info;
- EXPECT_FALSE(trans->GetLoadTimingInfo(&load_timing_info));
- rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_FALSE(trans->IsReadyToRestartForAuth());
- EXPECT_TRUE(response->auth_challenge.has_value());
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // A more nuanced test than GenerateAuthToken test which asserts that
- // ERR_INVALID_AUTH_CREDENTIALS does not cause the auth scheme to be
- // unnecessarily invalidated, and that if the server co-operates, the
- // authentication handshake can continue with the same scheme but with a
- // different identity.
- TEST_F(HttpNetworkTransactionTest, NonPermanentGenerateAuthTokenError) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto auth_handler_factory = std::make_unique<HttpAuthHandlerMock::Factory>();
- auth_handler_factory->set_do_init_from_challenge(true);
- // First handler. Uses default credentials, but barfs at generate auth token.
- auto mock_handler = std::make_unique<HttpAuthHandlerMock>();
- mock_handler->set_allows_default_credentials(true);
- mock_handler->set_allows_explicit_credentials(true);
- mock_handler->set_connection_based(true);
- mock_handler->SetGenerateExpectation(true, ERR_INVALID_AUTH_CREDENTIALS);
- auth_handler_factory->AddMockHandler(std::move(mock_handler),
- HttpAuth::AUTH_SERVER);
- // Add another handler for the second challenge. It supports default
- // credentials, but they shouldn't be used, since they were already tried.
- mock_handler = std::make_unique<HttpAuthHandlerMock>();
- mock_handler->set_allows_default_credentials(true);
- mock_handler->set_allows_explicit_credentials(true);
- mock_handler->set_connection_based(true);
- auth_handler_factory->AddMockHandler(std::move(mock_handler),
- HttpAuth::AUTH_SERVER);
- session_deps_.http_auth_handler_factory = std::move(auth_handler_factory);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- MockWrite data_writes1[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 401 Authentication Required\r\n"
- "WWW-Authenticate: Mock\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- // Identical to data_writes1[]. The AuthHandler encounters a
- // ERR_INVALID_AUTH_CREDENTIALS during the GenerateAuthToken stage, so the
- // transaction procceds without an authorization header.
- MockWrite data_writes2[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 401 Authentication Required\r\n"
- "WWW-Authenticate: Mock\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockWrite data_writes3[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: auth_token\r\n\r\n"),
- };
- MockRead data_reads3[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Content-Length: 5\r\n"
- "Content-Type: text/plain\r\n"
- "Connection: keep-alive\r\n\r\n"
- "Hello"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- StaticSocketDataProvider data3(data_reads3, data_writes3);
- session_deps_.socket_factory->AddSocketDataProvider(&data3);
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- // The following three tests assert that an authentication challenge was
- // received and that the stack is ready to respond to the challenge using
- // ambient credentials.
- EXPECT_EQ(401, response->headers->response_code());
- EXPECT_TRUE(trans->IsReadyToRestartForAuth());
- EXPECT_FALSE(response->auth_challenge.has_value());
- rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- // The following three tests assert that an authentication challenge was
- // received and that the stack needs explicit credentials before it is ready
- // to respond to the challenge.
- EXPECT_EQ(401, response->headers->response_code());
- EXPECT_FALSE(trans->IsReadyToRestartForAuth());
- EXPECT_TRUE(response->auth_challenge.has_value());
- rv = trans->RestartWithAuth(AuthCredentials(), callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(200, response->headers->response_code());
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Proxy resolver that returns a proxy with the same host and port for different
- // schemes, based on the path of the URL being requests.
- class SameProxyWithDifferentSchemesProxyResolver : public ProxyResolver {
- public:
- SameProxyWithDifferentSchemesProxyResolver() = default;
- SameProxyWithDifferentSchemesProxyResolver(
- const SameProxyWithDifferentSchemesProxyResolver&) = delete;
- SameProxyWithDifferentSchemesProxyResolver& operator=(
- const SameProxyWithDifferentSchemesProxyResolver&) = delete;
- ~SameProxyWithDifferentSchemesProxyResolver() override = default;
- static constexpr uint16_t kProxyPort = 10000;
- static HostPortPair ProxyHostPortPair() {
- return HostPortPair("proxy.test", kProxyPort);
- }
- static std::string ProxyHostPortPairAsString() {
- return ProxyHostPortPair().ToString();
- }
- // ProxyResolver implementation.
- int GetProxyForURL(const GURL& url,
- const NetworkIsolationKey& network_isolation_key,
- ProxyInfo* results,
- CompletionOnceCallback callback,
- std::unique_ptr<Request>* request,
- const NetLogWithSource& /*net_log*/) override {
- *results = ProxyInfo();
- results->set_traffic_annotation(
- MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
- if (url.path() == "/socks4") {
- results->UsePacString("SOCKS " + ProxyHostPortPairAsString());
- return OK;
- }
- if (url.path() == "/socks5") {
- results->UsePacString("SOCKS5 " + ProxyHostPortPairAsString());
- return OK;
- }
- if (url.path() == "/http") {
- results->UsePacString("PROXY " + ProxyHostPortPairAsString());
- return OK;
- }
- if (url.path() == "/https") {
- results->UsePacString("HTTPS " + ProxyHostPortPairAsString());
- return OK;
- }
- NOTREACHED();
- return ERR_NOT_IMPLEMENTED;
- }
- };
- class SameProxyWithDifferentSchemesProxyResolverFactory
- : public ProxyResolverFactory {
- public:
- SameProxyWithDifferentSchemesProxyResolverFactory()
- : ProxyResolverFactory(false) {}
- SameProxyWithDifferentSchemesProxyResolverFactory(
- const SameProxyWithDifferentSchemesProxyResolverFactory&) = delete;
- SameProxyWithDifferentSchemesProxyResolverFactory& operator=(
- const SameProxyWithDifferentSchemesProxyResolverFactory&) = delete;
- int CreateProxyResolver(const scoped_refptr<PacFileData>& pac_script,
- std::unique_ptr<ProxyResolver>* resolver,
- CompletionOnceCallback callback,
- std::unique_ptr<Request>* request) override {
- *resolver = std::make_unique<SameProxyWithDifferentSchemesProxyResolver>();
- return OK;
- }
- };
- // Check that when different proxy schemes are all applied to a proxy at the
- // same address, the connections are not grouped together. i.e., a request to
- // foo.com using proxy.com as an HTTPS proxy won't use the same socket as a
- // request to foo.com using proxy.com as an HTTP proxy.
- TEST_F(HttpNetworkTransactionTest, SameDestinationForDifferentProxyTypes) {
- session_deps_.proxy_resolution_service =
- std::make_unique<ConfiguredProxyResolutionService>(
- std::make_unique<ProxyConfigServiceFixed>(ProxyConfigWithAnnotation(
- ProxyConfig::CreateAutoDetect(), TRAFFIC_ANNOTATION_FOR_TESTS)),
- std::make_unique<SameProxyWithDifferentSchemesProxyResolverFactory>(),
- nullptr, /*quick_check_enabled=*/true);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- MockWrite socks_writes[] = {
- MockWrite(SYNCHRONOUS, kSOCKS4OkRequestLocalHostPort80,
- kSOCKS4OkRequestLocalHostPort80Length),
- MockWrite(SYNCHRONOUS,
- "GET /socks4 HTTP/1.1\r\n"
- "Host: test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead socks_reads[] = {
- MockRead(SYNCHRONOUS, kSOCKS4OkReply, kSOCKS4OkReplyLength),
- MockRead("HTTP/1.0 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 15\r\n\r\n"
- "SOCKS4 Response"),
- };
- StaticSocketDataProvider socks_data(socks_reads, socks_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&socks_data);
- const char kSOCKS5Request[] = {
- 0x05, // Version
- 0x01, // Command (CONNECT)
- 0x00, // Reserved
- 0x03, // Address type (DOMAINNAME)
- 0x04, // Length of domain (4)
- 't', 'e', 's', 't', // Domain string
- 0x00, 0x50, // 16-bit port (80)
- };
- MockWrite socks5_writes[] = {
- MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
- MockWrite(ASYNC, kSOCKS5Request, std::size(kSOCKS5Request)),
- MockWrite(SYNCHRONOUS,
- "GET /socks5 HTTP/1.1\r\n"
- "Host: test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead socks5_reads[] = {
- MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
- MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength),
- MockRead("HTTP/1.0 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 15\r\n\r\n"
- "SOCKS5 Response"),
- };
- StaticSocketDataProvider socks5_data(socks5_reads, socks5_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&socks5_data);
- MockWrite http_writes[] = {
- MockWrite(SYNCHRONOUS,
- "GET http://test/http HTTP/1.1\r\n"
- "Host: test\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Content-Length: 13\r\n\r\n"
- "HTTP Response"),
- };
- StaticSocketDataProvider http_data(http_reads, http_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&http_data);
- MockWrite https_writes[] = {
- MockWrite(SYNCHRONOUS,
- "GET http://test/https HTTP/1.1\r\n"
- "Host: test\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockRead https_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Content-Length: 14\r\n\r\n"
- "HTTPS Response"),
- };
- StaticSocketDataProvider https_data(https_reads, https_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&https_data);
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- SSLSocketDataProvider ssl2(SYNCHRONOUS, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- struct TestCase {
- GURL url;
- std::string expected_response;
- // How many idle sockets there should be in the SOCKS 4/5 proxy socket pools
- // after the test.
- int expected_idle_socks4_sockets;
- int expected_idle_socks5_sockets;
- // How many idle sockets there should be in the HTTP/HTTPS proxy socket
- // pools after the test.
- int expected_idle_http_sockets;
- int expected_idle_https_sockets;
- } const kTestCases[] = {
- {GURL("http://test/socks4"), "SOCKS4 Response", 1, 0, 0, 0},
- {GURL("http://test/socks5"), "SOCKS5 Response", 1, 1, 0, 0},
- {GURL("http://test/http"), "HTTP Response", 1, 1, 1, 0},
- {GURL("http://test/https"), "HTTPS Response", 1, 1, 1, 1},
- };
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(test_case.url);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = test_case.url;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- ConnectedHandler connected_handler;
- auto transaction = std::make_unique<HttpNetworkTransaction>(
- DEFAULT_PRIORITY, session.get());
- transaction->SetConnectedCallback(connected_handler.Callback());
- TestCompletionCallback callback;
- int rv =
- transaction->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = transaction->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(200, response->headers->response_code());
- std::string response_data;
- EXPECT_THAT(ReadTransaction(transaction.get(), &response_data), IsOk());
- EXPECT_EQ(test_case.expected_response, response_data);
- TransportInfo expected_transport;
- expected_transport.type = TransportType::kProxied;
- expected_transport.endpoint =
- IPEndPoint(IPAddress::IPv4Localhost(),
- SameProxyWithDifferentSchemesProxyResolver::kProxyPort);
- EXPECT_THAT(connected_handler.transports(),
- ElementsAre(expected_transport));
- // Return the socket to the socket pool, so can make sure it's not used for
- // the next requests.
- transaction.reset();
- base::RunLoop().RunUntilIdle();
- // Check the number of idle sockets in the pool, to make sure that used
- // sockets are indeed being returned to the socket pool. If each request
- // doesn't return an idle socket to the pool, the test would incorrectly
- // pass.
- EXPECT_EQ(test_case.expected_idle_socks4_sockets,
- session
- ->GetSocketPool(
- HttpNetworkSession::NORMAL_SOCKET_POOL,
- ProxyServer(ProxyServer::SCHEME_SOCKS4,
- SameProxyWithDifferentSchemesProxyResolver::
- ProxyHostPortPair()))
- ->IdleSocketCount());
- EXPECT_EQ(test_case.expected_idle_socks5_sockets,
- session
- ->GetSocketPool(
- HttpNetworkSession::NORMAL_SOCKET_POOL,
- ProxyServer(ProxyServer::SCHEME_SOCKS5,
- SameProxyWithDifferentSchemesProxyResolver::
- ProxyHostPortPair()))
- ->IdleSocketCount());
- EXPECT_EQ(test_case.expected_idle_http_sockets,
- session
- ->GetSocketPool(
- HttpNetworkSession::NORMAL_SOCKET_POOL,
- ProxyServer(ProxyServer::SCHEME_HTTP,
- SameProxyWithDifferentSchemesProxyResolver::
- ProxyHostPortPair()))
- ->IdleSocketCount());
- EXPECT_EQ(test_case.expected_idle_https_sockets,
- session
- ->GetSocketPool(
- HttpNetworkSession::NORMAL_SOCKET_POOL,
- ProxyServer(ProxyServer::SCHEME_HTTPS,
- SameProxyWithDifferentSchemesProxyResolver::
- ProxyHostPortPair()))
- ->IdleSocketCount());
- }
- }
- // Test the load timing for HTTPS requests with an HTTP proxy.
- TEST_F(HttpNetworkTransactionTest, HttpProxyLoadTimingNoPacTwoRequests) {
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://www.example.org/1");
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://www.example.org/2");
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- NetLogWithSource net_log_with_source =
- NetLogWithSource::Make(NetLogSourceType::NONE);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("GET /1 HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- MockWrite("GET /2 HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407, using a persistent
- // connection.
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 1\r\n\r\n"),
- MockRead(SYNCHRONOUS, "1"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 2\r\n\r\n"),
- MockRead(SYNCHRONOUS, "22"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback1;
- auto trans1 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans1->Start(&request1, callback1.callback(), net_log_with_source);
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
- ASSERT_TRUE(response1);
- EXPECT_TRUE(response1->proxy_server.is_http());
- ASSERT_TRUE(response1->headers);
- EXPECT_EQ(1, response1->headers->GetContentLength());
- LoadTimingInfo load_timing_info1;
- EXPECT_TRUE(trans1->GetLoadTimingInfo(&load_timing_info1));
- TestLoadTimingNotReused(load_timing_info1, CONNECT_TIMING_HAS_SSL_TIMES);
- trans1.reset();
- TestCompletionCallback callback2;
- auto trans2 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans2->Start(&request2, callback2.callback(), net_log_with_source);
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response2 = trans2->GetResponseInfo();
- ASSERT_TRUE(response2);
- EXPECT_TRUE(response2->proxy_server.is_http());
- ASSERT_TRUE(response2->headers);
- EXPECT_EQ(2, response2->headers->GetContentLength());
- LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2));
- TestLoadTimingReused(load_timing_info2);
- EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
- trans2.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Test the load timing for HTTPS requests with an HTTP proxy and a PAC script.
- TEST_F(HttpNetworkTransactionTest, HttpProxyLoadTimingWithPacTwoRequests) {
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://www.example.org/1");
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://www.example.org/2");
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- NetLogWithSource net_log_with_source =
- NetLogWithSource::Make(NetLogSourceType::NONE);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("GET /1 HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- MockWrite("GET /2 HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407, using a persistent
- // connection.
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 1\r\n\r\n"),
- MockRead(SYNCHRONOUS, "1"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 2\r\n\r\n"),
- MockRead(SYNCHRONOUS, "22"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback1;
- auto trans1 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans1->Start(&request1, callback1.callback(), net_log_with_source);
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
- ASSERT_TRUE(response1);
- ASSERT_TRUE(response1->headers);
- EXPECT_EQ(1, response1->headers->GetContentLength());
- LoadTimingInfo load_timing_info1;
- EXPECT_TRUE(trans1->GetLoadTimingInfo(&load_timing_info1));
- TestLoadTimingNotReusedWithPac(load_timing_info1,
- CONNECT_TIMING_HAS_SSL_TIMES);
- trans1.reset();
- TestCompletionCallback callback2;
- auto trans2 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans2->Start(&request2, callback2.callback(), net_log_with_source);
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response2 = trans2->GetResponseInfo();
- ASSERT_TRUE(response2);
- ASSERT_TRUE(response2->headers);
- EXPECT_EQ(2, response2->headers->GetContentLength());
- LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2));
- TestLoadTimingReusedWithPac(load_timing_info2);
- EXPECT_EQ(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
- trans2.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Make sure that NetworkIsolationKeys are passed down to the proxy layer.
- TEST_F(HttpNetworkTransactionTest, ProxyResolvedWithNetworkIsolationKey) {
- const SchemefulSite kSite(GURL("https://foo.test/"));
- ProxyConfig proxy_config;
- proxy_config.set_auto_detect(true);
- proxy_config.set_pac_url(GURL("http://fooproxyurl"));
- CapturingProxyResolver capturing_proxy_resolver;
- capturing_proxy_resolver.set_proxy_server(ProxyServer::Direct());
- session_deps_.proxy_resolution_service =
- std::make_unique<ConfiguredProxyResolutionService>(
- std::make_unique<ProxyConfigServiceFixed>(ProxyConfigWithAnnotation(
- proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)),
- std::make_unique<CapturingProxyResolverFactory>(
- &capturing_proxy_resolver),
- nullptr, /*quick_check_enabled=*/true);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // No need to continue with the network request - proxy resolution occurs
- // before establishing a data.
- StaticSocketDataProvider data{base::span<MockRead>(),
- base::span<MockWrite>()};
- data.set_connect_data(MockConnect(SYNCHRONOUS, ERR_FAILED));
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- // Run first request until an auth challenge is observed.
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://foo.test/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans(LOWEST, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_FAILED));
- }
- // Test that a failure in resolving the proxy hostname is retrievable.
- TEST_F(HttpNetworkTransactionTest, ProxyHostResolutionFailure) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against https proxy server "proxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- auto resolver = std::make_unique<MockHostResolver>();
- resolver->rules()->AddSimulatedTimeoutFailure("proxy");
- session_deps_.net_log = net::NetLog::Get();
- session_deps_.host_resolver = std::move(resolver);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsError(ERR_PROXY_CONNECTION_FAILED));
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_THAT(response->resolve_error_info.error, IsError(ERR_DNS_TIMED_OUT));
- }
- // Test a simple get through an HTTPS Proxy.
- TEST_F(HttpNetworkTransactionTest, HttpsProxyGet) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against https proxy server "proxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since we have proxy, should use full url
- MockWrite data_writes1[] = {
- MockWrite(
- "GET http://www.example.org/ HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
- ASSERT_TRUE(ssl.ssl_info.cert);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- ConnectedHandler connected_handler;
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- trans.SetConnectedCallback(connected_handler.Callback());
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info,
- CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->proxy_server.is_https());
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(100, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- // DNS aliases should be empty when using a proxy.
- EXPECT_TRUE(response->dns_aliases.empty());
- TransportInfo expected_transport;
- expected_transport.type = TransportType::kProxied;
- expected_transport.endpoint = IPEndPoint(IPAddress::IPv4Localhost(), 70);
- EXPECT_THAT(connected_handler.transports(), ElementsAre(expected_transport));
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- // Although we use an HTTPS proxy, the `SSLInfo` from that connection should
- // not be reported as a property of the origin.
- EXPECT_FALSE(response->ssl_info.cert);
- }
- // Test a SPDY get through an HTTPS Proxy.
- TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGet) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against https proxy server "proxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // fetch http://www.example.org/ via SPDY
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet("http://www.example.org/", 1, LOWEST));
- MockWrite spdy_writes[] = {CreateMockWrite(req, 0)};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead spdy_reads[] = {
- CreateMockRead(resp, 1), CreateMockRead(data, 2), MockRead(ASYNC, 0, 3),
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
- ASSERT_TRUE(ssl.ssl_info.cert);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- ConnectedHandler connected_handler;
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- trans.SetConnectedCallback(connected_handler.Callback());
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info,
- CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->proxy_server.is_https());
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- // DNS aliases should be empty when using a proxy.
- EXPECT_TRUE(response->dns_aliases.empty());
- TransportInfo expected_transport;
- expected_transport.type = TransportType::kProxied;
- expected_transport.endpoint = IPEndPoint(IPAddress::IPv4Localhost(), 70);
- EXPECT_THAT(connected_handler.transports(), ElementsAre(expected_transport));
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ(kUploadData, response_data);
- // Although we use an HTTPS proxy, the `SSLInfo` from that connection should
- // not be reported as a property of the origin.
- EXPECT_FALSE(response->ssl_info.cert);
- }
- // Verifies that a session which races and wins against the owning transaction
- // (completing prior to host resolution), doesn't fail the transaction.
- // Regression test for crbug.com/334413.
- TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGetWithSessionRace) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure SPDY proxy server "proxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- NetLogWithSource net_log_with_source =
- NetLogWithSource::Make(NetLogSourceType::NONE);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Fetch http://www.example.org/ through the SPDY proxy.
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet("http://www.example.org/", 1, LOWEST));
- MockWrite spdy_writes[] = {CreateMockWrite(req, 0)};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead spdy_reads[] = {
- CreateMockRead(resp, 1), CreateMockRead(data, 2), MockRead(ASYNC, 0, 3),
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Stall the hostname resolution begun by the transaction.
- session_deps_.host_resolver->set_ondemand_mode(true);
- int rv = trans.Start(&request, callback1.callback(), net_log_with_source);
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Race a session to the proxy, which completes first.
- session_deps_.host_resolver->set_ondemand_mode(false);
- SpdySessionKey key(HostPortPair("proxy", 70), ProxyServer::Direct(),
- PRIVACY_MODE_DISABLED,
- SpdySessionKey::IsProxySession::kTrue, SocketTag(),
- NetworkIsolationKey(), SecureDnsPolicy::kAllow);
- base::WeakPtr<SpdySession> spdy_session =
- CreateSpdySession(session.get(), key, net_log_with_source);
- // Unstall the resolution begun by the transaction.
- session_deps_.host_resolver->set_ondemand_mode(true);
- session_deps_.host_resolver->ResolveAllPending();
- EXPECT_FALSE(callback1.have_result());
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ(kUploadData, response_data);
- }
- // Test a SPDY get through an HTTPS Proxy.
- TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyGetWithProxyAuth) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against https proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // The first request will be a bare GET, the second request will be a
- // GET with a Proxy-Authorization header.
- spdy_util_.set_default_url(request.url);
- spdy::SpdySerializedFrame req_get(
- spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
- spdy_util_.UpdateWithStreamDestruction(1);
- const char* const kExtraAuthorizationHeaders[] = {
- "proxy-authorization", "Basic Zm9vOmJhcg=="
- };
- spdy::SpdySerializedFrame req_get_authorization(spdy_util_.ConstructSpdyGet(
- kExtraAuthorizationHeaders, std::size(kExtraAuthorizationHeaders) / 2, 3,
- LOWEST));
- MockWrite spdy_writes[] = {
- CreateMockWrite(req_get, 0), CreateMockWrite(req_get_authorization, 3),
- };
- // The first response is a 407 proxy authentication challenge, and the second
- // response will be a 200 response since the second request includes a valid
- // Authorization header.
- const char* const kExtraAuthenticationHeaders[] = {
- "proxy-authenticate", "Basic realm=\"MyRealm1\""
- };
- spdy::SpdySerializedFrame resp_authentication(
- spdy_util_.ConstructSpdyReplyError(
- "407", kExtraAuthenticationHeaders,
- std::size(kExtraAuthenticationHeaders) / 2, 1));
- spdy::SpdySerializedFrame body_authentication(
- spdy_util_.ConstructSpdyDataFrame(1, true));
- spdy::SpdySerializedFrame resp_data(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
- spdy::SpdySerializedFrame body_data(
- spdy_util_.ConstructSpdyDataFrame(3, true));
- MockRead spdy_reads[] = {
- CreateMockRead(resp_authentication, 1),
- CreateMockRead(body_authentication, 2, SYNCHRONOUS),
- CreateMockRead(resp_data, 4),
- CreateMockRead(body_data, 5),
- MockRead(ASYNC, 0, 6),
- };
- SequencedSocketData data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* const response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(CheckBasicSecureProxyAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* const response_restart = trans.GetResponseInfo();
- ASSERT_TRUE(response_restart);
- ASSERT_TRUE(response_restart->headers);
- EXPECT_EQ(200, response_restart->headers->response_code());
- // The password prompt info should not be set.
- EXPECT_FALSE(response_restart->auth_challenge.has_value());
- }
- // Test a SPDY CONNECT through an HTTPS Proxy to an HTTPS (non-SPDY) Server.
- TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectHttps) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against https proxy server "proxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // CONNECT to www.example.org:443 via SPDY
- spdy::SpdySerializedFrame connect(spdy_util_.ConstructSpdyConnect(
- nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
- HostPortPair("www.example.org", 443)));
- // fetch https://www.example.org/ via HTTP
- const char get[] =
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n";
- spdy::SpdySerializedFrame wrapped_get(
- spdy_util_.ConstructSpdyDataFrame(1, get, false));
- spdy::SpdySerializedFrame conn_resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- const char resp[] = "HTTP/1.1 200 OK\r\n"
- "Content-Length: 10\r\n\r\n";
- spdy::SpdySerializedFrame wrapped_get_resp(
- spdy_util_.ConstructSpdyDataFrame(1, resp, false));
- spdy::SpdySerializedFrame wrapped_body(
- spdy_util_.ConstructSpdyDataFrame(1, "1234567890", false));
- spdy::SpdySerializedFrame window_update(
- spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp.size()));
- MockWrite spdy_writes[] = {
- CreateMockWrite(connect, 0), CreateMockWrite(wrapped_get, 2),
- CreateMockWrite(window_update, 6),
- };
- MockRead spdy_reads[] = {
- CreateMockRead(conn_resp, 1, ASYNC),
- CreateMockRead(wrapped_get_resp, 3, ASYNC),
- CreateMockRead(wrapped_body, 4, ASYNC),
- CreateMockRead(wrapped_body, 5, ASYNC),
- MockRead(ASYNC, 0, 7),
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- ASSERT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_SSL_TIMES);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ("1234567890", response_data);
- }
- // Test a SPDY CONNECT through an HTTPS Proxy to a SPDY server.
- TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectSpdy) {
- SpdyTestUtil spdy_util_wrapped;
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against https proxy server "proxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // CONNECT to www.example.org:443 via SPDY
- spdy::SpdySerializedFrame connect(spdy_util_.ConstructSpdyConnect(
- nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
- HostPortPair("www.example.org", 443)));
- // fetch https://www.example.org/ via SPDY
- const char kMyUrl[] = "https://www.example.org/";
- spdy::SpdySerializedFrame get(
- spdy_util_wrapped.ConstructSpdyGet(kMyUrl, 1, LOWEST));
- spdy::SpdySerializedFrame wrapped_get(
- spdy_util_.ConstructWrappedSpdyFrame(get, 1));
- spdy::SpdySerializedFrame conn_resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame get_resp(
- spdy_util_wrapped.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame wrapped_get_resp(
- spdy_util_.ConstructWrappedSpdyFrame(get_resp, 1));
- spdy::SpdySerializedFrame body(
- spdy_util_wrapped.ConstructSpdyDataFrame(1, true));
- spdy::SpdySerializedFrame wrapped_body(
- spdy_util_.ConstructWrappedSpdyFrame(body, 1));
- spdy::SpdySerializedFrame window_update_get_resp(
- spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp.size()));
- spdy::SpdySerializedFrame window_update_body(
- spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_body.size()));
- MockWrite spdy_writes[] = {
- CreateMockWrite(connect, 0), CreateMockWrite(wrapped_get, 2),
- CreateMockWrite(window_update_get_resp, 6),
- CreateMockWrite(window_update_body, 7),
- };
- MockRead spdy_reads[] = {
- CreateMockRead(conn_resp, 1, ASYNC),
- MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(wrapped_get_resp, 4, ASYNC),
- CreateMockRead(wrapped_body, 5, ASYNC),
- MockRead(ASYNC, 0, 8),
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- ssl2.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Allow the SpdyProxyClientSocket's write callback to complete.
- base::RunLoop().RunUntilIdle();
- // Now allow the read of the response to complete.
- spdy_data.Resume();
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_SSL_TIMES);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ(kUploadData, response_data);
- }
- // Test a SPDY CONNECT failure through an HTTPS Proxy.
- TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyConnectFailure) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against https proxy server "proxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // CONNECT to www.example.org:443 via SPDY
- spdy::SpdySerializedFrame connect(spdy_util_.ConstructSpdyConnect(
- nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
- HostPortPair("www.example.org", 443)));
- spdy::SpdySerializedFrame get(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite spdy_writes[] = {
- CreateMockWrite(connect, 0), CreateMockWrite(get, 2),
- };
- spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyReplyError(1));
- spdy::SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead spdy_reads[] = {
- CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, 0, 3),
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- ssl2.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
- // TODO(juliatuttle): Anything else to check here?
- }
- // Test the case where a proxied H2 session doesn't exist when an auth challenge
- // is observed, but does exist by the time auth credentials are provided. In
- // this case, auth and SSL are fully negotated on the second request, but then
- // the socket is discarded to use the shared session.
- TEST_F(HttpNetworkTransactionTest, ProxiedH2SessionAppearsDuringAuth) {
- ProxyConfig proxy_config;
- proxy_config.set_auto_detect(true);
- proxy_config.set_pac_url(GURL("http://fooproxyurl"));
- CapturingProxyResolver capturing_proxy_resolver;
- capturing_proxy_resolver.set_proxy_server(
- ProxyServer(ProxyServer::SCHEME_HTTP, HostPortPair("myproxy", 70)));
- session_deps_.proxy_resolution_service =
- std::make_unique<ConfiguredProxyResolutionService>(
- std::make_unique<ProxyConfigServiceFixed>(ProxyConfigWithAnnotation(
- proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)),
- std::make_unique<CapturingProxyResolverFactory>(
- &capturing_proxy_resolver),
- nullptr, /*quick_check_enabled=*/true);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- const char kMyUrl[] = "https://www.example.org/";
- spdy::SpdySerializedFrame get(spdy_util_.ConstructSpdyGet(kMyUrl, 1, LOWEST));
- spdy::SpdySerializedFrame get_resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
- spdy_util_.UpdateWithStreamDestruction(1);
- spdy::SpdySerializedFrame get2(
- spdy_util_.ConstructSpdyGet(kMyUrl, 3, LOWEST));
- spdy::SpdySerializedFrame get_resp2(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
- spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
- MockWrite auth_challenge_writes[] = {
- MockWrite(ASYNC, 0,
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite(ASYNC, 2,
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockRead auth_challenge_reads[] = {
- MockRead(ASYNC, 1,
- "HTTP/1.1 407 Authentication Required\r\n"
- "Content-Length: 0\r\n"
- "Proxy-Connection: close\r\n"
- "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n"),
- };
- MockWrite spdy_writes[] = {
- MockWrite(ASYNC, 0,
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- CreateMockWrite(get, 2),
- CreateMockWrite(get2, 5),
- };
- MockRead spdy_reads[] = {
- MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
- CreateMockRead(get_resp, 3, ASYNC),
- CreateMockRead(body, 4, ASYNC),
- CreateMockRead(get_resp2, 6, ASYNC),
- CreateMockRead(body2, 7, ASYNC),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 8),
- };
- MockWrite auth_response_writes_discarded_socket[] = {
- MockWrite(ASYNC, 0,
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- MockRead auth_response_reads_discarded_socket[] = {
- MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
- };
- SequencedSocketData auth_challenge1(auth_challenge_reads,
- auth_challenge_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&auth_challenge1);
- SequencedSocketData auth_challenge2(auth_challenge_reads,
- auth_challenge_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&auth_challenge2);
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- SequencedSocketData auth_response_discarded_socket(
- auth_response_reads_discarded_socket,
- auth_response_writes_discarded_socket);
- session_deps_.socket_factory->AddSocketDataProvider(
- &auth_response_discarded_socket);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- ssl2.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- TestCompletionCallback callback;
- std::string response_data;
- // Run first request until an auth challenge is observed.
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL(kMyUrl);
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans1(LOWEST, session.get());
- int rv = trans1.Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans1.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge));
- // Run second request until an auth challenge is observed.
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL(kMyUrl);
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans2(LOWEST, session.get());
- rv = trans2.Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans2.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge));
- // Now provide credentials for the first request, and wait for it to complete.
- rv = trans1.RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback());
- rv = callback.GetResult(rv);
- EXPECT_THAT(rv, IsOk());
- response = trans1.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- ASSERT_THAT(ReadTransaction(&trans1, &response_data), IsOk());
- EXPECT_EQ(kUploadData, response_data);
- // Now provide credentials for the second request. It should notice the
- // existing session, and reuse it.
- rv = trans2.RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans2.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- ASSERT_THAT(ReadTransaction(&trans2, &response_data), IsOk());
- EXPECT_EQ(kUploadData, response_data);
- }
- // Test load timing in the case of two HTTPS (non-SPDY) requests through a SPDY
- // HTTPS Proxy to different servers.
- TEST_F(HttpNetworkTransactionTest,
- HttpsProxySpdyConnectHttpsLoadTimingTwoRequestsTwoServers) {
- // Configure against https proxy server "proxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(
- SpdySessionDependencies::SpdyCreateSession(&session_deps_));
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://www.example.org/");
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://mail.example.org/");
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // CONNECT to www.example.org:443 via SPDY.
- spdy::SpdySerializedFrame connect1(spdy_util_.ConstructSpdyConnect(
- nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
- HostPortPair("www.example.org", 443)));
- spdy::SpdySerializedFrame conn_resp1(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- // Fetch https://www.example.org/ via HTTP.
- const char get1[] =
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n";
- spdy::SpdySerializedFrame wrapped_get1(
- spdy_util_.ConstructSpdyDataFrame(1, get1, false));
- const char resp1[] = "HTTP/1.1 200 OK\r\n"
- "Content-Length: 1\r\n\r\n";
- spdy::SpdySerializedFrame wrapped_get_resp1(
- spdy_util_.ConstructSpdyDataFrame(1, resp1, false));
- spdy::SpdySerializedFrame wrapped_body1(
- spdy_util_.ConstructSpdyDataFrame(1, "1", false));
- spdy::SpdySerializedFrame window_update(
- spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp1.size()));
- // CONNECT to mail.example.org:443 via SPDY.
- spdy::Http2HeaderBlock connect2_block;
- connect2_block[spdy::kHttp2MethodHeader] = "CONNECT";
- connect2_block[spdy::kHttp2AuthorityHeader] = "mail.example.org:443";
- spdy::SpdySerializedFrame connect2(spdy_util_.ConstructSpdyHeaders(
- 3, std::move(connect2_block), HttpProxyConnectJob::kH2QuicTunnelPriority,
- false));
- spdy::SpdySerializedFrame conn_resp2(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
- // Fetch https://mail.example.org/ via HTTP.
- const char get2[] =
- "GET / HTTP/1.1\r\n"
- "Host: mail.example.org\r\n"
- "Connection: keep-alive\r\n\r\n";
- spdy::SpdySerializedFrame wrapped_get2(
- spdy_util_.ConstructSpdyDataFrame(3, get2, false));
- const char resp2[] = "HTTP/1.1 200 OK\r\n"
- "Content-Length: 2\r\n\r\n";
- spdy::SpdySerializedFrame wrapped_get_resp2(
- spdy_util_.ConstructSpdyDataFrame(3, resp2, false));
- spdy::SpdySerializedFrame wrapped_body2(
- spdy_util_.ConstructSpdyDataFrame(3, "22", false));
- MockWrite spdy_writes[] = {
- CreateMockWrite(connect1, 0), CreateMockWrite(wrapped_get1, 2),
- CreateMockWrite(connect2, 5), CreateMockWrite(wrapped_get2, 7),
- };
- MockRead spdy_reads[] = {
- CreateMockRead(conn_resp1, 1, ASYNC),
- CreateMockRead(wrapped_get_resp1, 3, ASYNC),
- CreateMockRead(wrapped_body1, 4, ASYNC),
- CreateMockRead(conn_resp2, 6, ASYNC),
- CreateMockRead(wrapped_get_resp2, 8, ASYNC),
- CreateMockRead(wrapped_body2, 9, ASYNC),
- MockRead(ASYNC, 0, 10),
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- SSLSocketDataProvider ssl3(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl3);
- TestCompletionCallback callback;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_SSL_TIMES);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(256);
- rv = trans.Read(buf.get(), 256, callback.callback());
- EXPECT_EQ(1, callback.GetResult(rv));
- HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- rv = trans2.Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans2.GetLoadTimingInfo(&load_timing_info2));
- // Even though the SPDY connection is reused, a new tunnelled connection has
- // to be created, so the socket's load timing looks like a fresh connection.
- TestLoadTimingNotReused(load_timing_info2, CONNECT_TIMING_HAS_SSL_TIMES);
- // The requests should have different IDs, since they each are using their own
- // separate stream.
- EXPECT_NE(load_timing_info.socket_log_id, load_timing_info2.socket_log_id);
- rv = trans2.Read(buf.get(), 256, callback.callback());
- EXPECT_EQ(2, callback.GetResult(rv));
- }
- // Test load timing in the case of two HTTPS (non-SPDY) requests through a SPDY
- // HTTPS Proxy to the same server.
- TEST_F(HttpNetworkTransactionTest,
- HttpsProxySpdyConnectHttpsLoadTimingTwoRequestsSameServer) {
- // Configure against https proxy server "proxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(
- SpdySessionDependencies::SpdyCreateSession(&session_deps_));
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://www.example.org/");
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://www.example.org/2");
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // CONNECT to www.example.org:443 via SPDY.
- spdy::SpdySerializedFrame connect1(spdy_util_.ConstructSpdyConnect(
- nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
- HostPortPair("www.example.org", 443)));
- spdy::SpdySerializedFrame conn_resp1(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- // Fetch https://www.example.org/ via HTTP.
- const char get1[] =
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n";
- spdy::SpdySerializedFrame wrapped_get1(
- spdy_util_.ConstructSpdyDataFrame(1, get1, false));
- const char resp1[] = "HTTP/1.1 200 OK\r\n"
- "Content-Length: 1\r\n\r\n";
- spdy::SpdySerializedFrame wrapped_get_resp1(
- spdy_util_.ConstructSpdyDataFrame(1, resp1, false));
- spdy::SpdySerializedFrame wrapped_body1(
- spdy_util_.ConstructSpdyDataFrame(1, "1", false));
- spdy::SpdySerializedFrame window_update(
- spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp1.size()));
- // Fetch https://www.example.org/2 via HTTP.
- const char get2[] =
- "GET /2 HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n";
- spdy::SpdySerializedFrame wrapped_get2(
- spdy_util_.ConstructSpdyDataFrame(1, get2, false));
- const char resp2[] = "HTTP/1.1 200 OK\r\n"
- "Content-Length: 2\r\n\r\n";
- spdy::SpdySerializedFrame wrapped_get_resp2(
- spdy_util_.ConstructSpdyDataFrame(1, resp2, false));
- spdy::SpdySerializedFrame wrapped_body2(
- spdy_util_.ConstructSpdyDataFrame(1, "22", false));
- MockWrite spdy_writes[] = {
- CreateMockWrite(connect1, 0), CreateMockWrite(wrapped_get1, 2),
- CreateMockWrite(wrapped_get2, 5),
- };
- MockRead spdy_reads[] = {
- CreateMockRead(conn_resp1, 1, ASYNC),
- CreateMockRead(wrapped_get_resp1, 3, ASYNC),
- CreateMockRead(wrapped_body1, 4, SYNCHRONOUS),
- CreateMockRead(wrapped_get_resp2, 6, ASYNC),
- CreateMockRead(wrapped_body2, 7, SYNCHRONOUS),
- MockRead(ASYNC, 0, 8),
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_SSL_TIMES);
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(256);
- EXPECT_EQ(1, trans->Read(buf.get(), 256, callback.callback()));
- trans.reset();
- auto trans2 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans2->GetLoadTimingInfo(&load_timing_info2));
- TestLoadTimingReused(load_timing_info2);
- // The requests should have the same ID.
- EXPECT_EQ(load_timing_info.socket_log_id, load_timing_info2.socket_log_id);
- EXPECT_EQ(2, trans2->Read(buf.get(), 256, callback.callback()));
- }
- // Test load timing in the case of of two HTTP requests through a SPDY HTTPS
- // Proxy to different servers.
- TEST_F(HttpNetworkTransactionTest, HttpsProxySpdyLoadTimingTwoHttpRequests) {
- // Configure against https proxy server "proxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(
- SpdySessionDependencies::SpdyCreateSession(&session_deps_));
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("http://www.example.org/");
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("http://mail.example.org/");
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // http://www.example.org/
- spdy::Http2HeaderBlock headers(
- spdy_util_.ConstructGetHeaderBlockForProxy("http://www.example.org/"));
- spdy::SpdySerializedFrame get1(
- spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
- spdy::SpdySerializedFrame get_resp1(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame body1(
- spdy_util_.ConstructSpdyDataFrame(1, "1", true));
- spdy_util_.UpdateWithStreamDestruction(1);
- // http://mail.example.org/
- spdy::Http2HeaderBlock headers2(
- spdy_util_.ConstructGetHeaderBlockForProxy("http://mail.example.org/"));
- spdy::SpdySerializedFrame get2(
- spdy_util_.ConstructSpdyHeaders(3, std::move(headers2), LOWEST, true));
- spdy::SpdySerializedFrame get_resp2(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
- spdy::SpdySerializedFrame body2(
- spdy_util_.ConstructSpdyDataFrame(3, "22", true));
- MockWrite spdy_writes[] = {
- CreateMockWrite(get1, 0), CreateMockWrite(get2, 3),
- };
- MockRead spdy_reads[] = {
- CreateMockRead(get_resp1, 1, ASYNC),
- CreateMockRead(body1, 2, ASYNC),
- CreateMockRead(get_resp2, 4, ASYNC),
- CreateMockRead(body2, 5, ASYNC),
- MockRead(ASYNC, 0, 6),
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info,
- CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- std::string response_data;
- scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(256);
- rv = trans->Read(buf.get(), 256, callback.callback());
- EXPECT_EQ(1, callback.GetResult(rv));
- // Delete the first request, so the second one can reuse the socket.
- trans.reset();
- HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- rv = trans2.Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans2.GetLoadTimingInfo(&load_timing_info2));
- TestLoadTimingReused(load_timing_info2);
- // The requests should have the same ID.
- EXPECT_EQ(load_timing_info.socket_log_id, load_timing_info2.socket_log_id);
- rv = trans2.Read(buf.get(), 256, callback.callback());
- EXPECT_EQ(2, callback.GetResult(rv));
- }
- // Test that an HTTP/2 CONNECT through an HTTPS Proxy to a HTTP/2 server and a
- // direct (non-proxied) request to the proxy server are not pooled, as that
- // would break socket pool isolation.
- TEST_F(HttpNetworkTransactionTest, SpdyProxyIsolation1) {
- ProxyConfig proxy_config;
- proxy_config.set_auto_detect(true);
- proxy_config.set_pac_url(GURL("http://fooproxyurl"));
- CapturingProxyResolver capturing_proxy_resolver;
- session_deps_.proxy_resolution_service =
- std::make_unique<ConfiguredProxyResolutionService>(
- std::make_unique<ProxyConfigServiceFixed>(ProxyConfigWithAnnotation(
- proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)),
- std::make_unique<CapturingProxyResolverFactory>(
- &capturing_proxy_resolver),
- nullptr, /*quick_check_enabled=*/true);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- SpdyTestUtil spdy_util1;
- // CONNECT to www.example.org:443 via HTTP/2.
- spdy::SpdySerializedFrame connect(spdy_util_.ConstructSpdyConnect(
- nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
- HostPortPair("www.example.org", 443)));
- // fetch https://www.example.org/ via HTTP/2.
- const char kMyUrl[] = "https://www.example.org/";
- spdy::SpdySerializedFrame get(spdy_util1.ConstructSpdyGet(kMyUrl, 1, LOWEST));
- spdy::SpdySerializedFrame wrapped_get(
- spdy_util_.ConstructWrappedSpdyFrame(get, 1));
- spdy::SpdySerializedFrame conn_resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame get_resp(
- spdy_util1.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame wrapped_get_resp(
- spdy_util_.ConstructWrappedSpdyFrame(get_resp, 1));
- spdy::SpdySerializedFrame body(spdy_util1.ConstructSpdyDataFrame(1, true));
- spdy::SpdySerializedFrame wrapped_body(
- spdy_util_.ConstructWrappedSpdyFrame(body, 1));
- spdy::SpdySerializedFrame window_update_get_resp(
- spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp.size()));
- spdy::SpdySerializedFrame window_update_body(
- spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_body.size()));
- MockWrite spdy_writes1[] = {
- CreateMockWrite(connect, 0),
- CreateMockWrite(wrapped_get, 2),
- CreateMockWrite(window_update_get_resp, 6),
- CreateMockWrite(window_update_body, 7),
- };
- MockRead spdy_reads1[] = {
- CreateMockRead(conn_resp, 1, ASYNC),
- MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(wrapped_get_resp, 4, ASYNC),
- CreateMockRead(wrapped_body, 5, ASYNC),
- MockRead(ASYNC, 0, 8),
- };
- SequencedSocketData spdy_data1(spdy_reads1, spdy_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data1);
- // Fetch https://proxy:70/ via HTTP/2. Needs a new SpdyTestUtil, since it uses
- // a new pipe.
- SpdyTestUtil spdy_util2;
- spdy::SpdySerializedFrame req(
- spdy_util2.ConstructSpdyGet("https://proxy:70/", 1, LOWEST));
- MockWrite spdy_writes2[] = {CreateMockWrite(req, 0)};
- spdy::SpdySerializedFrame resp(
- spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame data(spdy_util2.ConstructSpdyDataFrame(1, true));
- MockRead spdy_reads2[] = {
- CreateMockRead(resp, 1),
- CreateMockRead(data, 2),
- MockRead(ASYNC, 0, 3),
- };
- SequencedSocketData spdy_data2(spdy_reads2, spdy_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data2);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- ssl2.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- SSLSocketDataProvider ssl3(ASYNC, OK);
- ssl3.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl3);
- TestCompletionCallback callback;
- std::string response_data;
- // Make a request using proxy:70 as a HTTP/2 proxy.
- capturing_proxy_resolver.set_proxy_server(
- ProxyServer(ProxyServer::SCHEME_HTTPS, HostPortPair("proxy", 70)));
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://www.example.org/");
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans1(LOWEST, session.get());
- int rv = trans1.Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Allow the SpdyProxyClientSocket's write callback to complete.
- base::RunLoop().RunUntilIdle();
- // Now allow the read of the response to complete.
- spdy_data1.Resume();
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans1.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- ASSERT_THAT(ReadTransaction(&trans1, &response_data), IsOk());
- EXPECT_EQ(kUploadData, response_data);
- RunUntilIdle();
- // Make a direct HTTP/2 request to proxy:70.
- capturing_proxy_resolver.set_proxy_server(ProxyServer::Direct());
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://proxy:70/");
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans2(LOWEST, session.get());
- EXPECT_THAT(callback.GetResult(trans2.Start(&request2, callback.callback(),
- NetLogWithSource())),
- IsOk());
- ASSERT_THAT(ReadTransaction(&trans2, &response_data), IsOk());
- }
- // Same as above, but reverse request order, since the code to check for an
- // existing session is different for tunnels and direct connections.
- TEST_F(HttpNetworkTransactionTest, SpdyProxyIsolation2) {
- // Configure against https proxy server "myproxy:80".
- ProxyConfig proxy_config;
- proxy_config.set_auto_detect(true);
- proxy_config.set_pac_url(GURL("http://fooproxyurl"));
- CapturingProxyResolver capturing_proxy_resolver;
- session_deps_.proxy_resolution_service =
- std::make_unique<ConfiguredProxyResolutionService>(
- std::make_unique<ProxyConfigServiceFixed>(ProxyConfigWithAnnotation(
- proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)),
- std::make_unique<CapturingProxyResolverFactory>(
- &capturing_proxy_resolver),
- nullptr, /*quick_check_enabled=*/true);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Fetch https://proxy:70/ via HTTP/2.
- SpdyTestUtil spdy_util1;
- spdy::SpdySerializedFrame req(
- spdy_util1.ConstructSpdyGet("https://proxy:70/", 1, LOWEST));
- MockWrite spdy_writes1[] = {CreateMockWrite(req, 0)};
- spdy::SpdySerializedFrame resp(
- spdy_util1.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame data(spdy_util1.ConstructSpdyDataFrame(1, true));
- MockRead spdy_reads1[] = {
- CreateMockRead(resp, 1),
- CreateMockRead(data, 2),
- MockRead(ASYNC, 0, 3),
- };
- SequencedSocketData spdy_data1(spdy_reads1, spdy_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data1);
- SpdyTestUtil spdy_util2;
- // CONNECT to www.example.org:443 via HTTP/2.
- spdy::SpdySerializedFrame connect(spdy_util_.ConstructSpdyConnect(
- nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
- HostPortPair("www.example.org", 443)));
- // fetch https://www.example.org/ via HTTP/2.
- const char kMyUrl[] = "https://www.example.org/";
- spdy::SpdySerializedFrame get(spdy_util2.ConstructSpdyGet(kMyUrl, 1, LOWEST));
- spdy::SpdySerializedFrame wrapped_get(
- spdy_util_.ConstructWrappedSpdyFrame(get, 1));
- spdy::SpdySerializedFrame conn_resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame get_resp(
- spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame wrapped_get_resp(
- spdy_util_.ConstructWrappedSpdyFrame(get_resp, 1));
- spdy::SpdySerializedFrame body(spdy_util2.ConstructSpdyDataFrame(1, true));
- spdy::SpdySerializedFrame wrapped_body(
- spdy_util_.ConstructWrappedSpdyFrame(body, 1));
- spdy::SpdySerializedFrame window_update_get_resp(
- spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_get_resp.size()));
- spdy::SpdySerializedFrame window_update_body(
- spdy_util_.ConstructSpdyWindowUpdate(1, wrapped_body.size()));
- MockWrite spdy_writes2[] = {
- CreateMockWrite(connect, 0),
- CreateMockWrite(wrapped_get, 2),
- CreateMockWrite(window_update_get_resp, 6),
- CreateMockWrite(window_update_body, 7),
- };
- MockRead spdy_reads2[] = {
- CreateMockRead(conn_resp, 1, ASYNC),
- MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(wrapped_get_resp, 4, ASYNC),
- CreateMockRead(wrapped_body, 5, ASYNC),
- MockRead(ASYNC, 0, 8),
- };
- SequencedSocketData spdy_data2(spdy_reads2, spdy_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data2);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- ssl2.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- SSLSocketDataProvider ssl3(ASYNC, OK);
- ssl3.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl3);
- TestCompletionCallback callback;
- std::string response_data;
- // Make a direct HTTP/2 request to proxy:70.
- capturing_proxy_resolver.set_proxy_server(ProxyServer::Direct());
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://proxy:70/");
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans1(LOWEST, session.get());
- EXPECT_THAT(callback.GetResult(trans1.Start(&request1, callback.callback(),
- NetLogWithSource())),
- IsOk());
- ASSERT_THAT(ReadTransaction(&trans1, &response_data), IsOk());
- RunUntilIdle();
- // Make a request using proxy:70 as a HTTP/2 proxy.
- capturing_proxy_resolver.set_proxy_server(
- ProxyServer(ProxyServer::SCHEME_HTTPS, HostPortPair("proxy", 70)));
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://www.example.org/");
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans2(LOWEST, session.get());
- int rv = trans2.Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Allow the SpdyProxyClientSocket's write callback to complete.
- base::RunLoop().RunUntilIdle();
- // Now allow the read of the response to complete.
- spdy_data2.Resume();
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response2 = trans2.GetResponseInfo();
- ASSERT_TRUE(response2);
- ASSERT_TRUE(response2->headers);
- EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
- ASSERT_THAT(ReadTransaction(&trans2, &response_data), IsOk());
- EXPECT_EQ(kUploadData, response_data);
- }
- // Test the challenge-response-retry sequence through an HTTPS Proxy
- TEST_F(HttpNetworkTransactionTest, HttpsProxyAuthRetry) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- // when the no authentication data flag is set.
- request.privacy_mode = PRIVACY_MODE_ENABLED;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against https proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since we have proxy, should use full url
- MockWrite data_writes1[] = {
- MockWrite("GET http://www.example.org/ HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- // After calling trans.RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite("GET http://www.example.org/ HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- // The proxy responds to the GET with a 407, using a persistent
- // connection.
- MockRead data_reads1[] = {
- // No credentials.
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Proxy-Connection: keep-alive\r\n"),
- MockRead("Content-Length: 0\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info,
- CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(CheckBasicSecureProxyAuth(response->auth_challenge));
- EXPECT_FALSE(response->did_use_http_auth);
- EXPECT_EQ(PacResultElementToProxyServer("HTTPS myproxy:70"),
- response->proxy_server);
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- load_timing_info = LoadTimingInfo();
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- // Retrying with HTTP AUTH is considered to be reusing a socket.
- TestLoadTimingReused(load_timing_info);
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(100, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(response->did_use_http_auth);
- EXPECT_EQ(PacResultElementToProxyServer("HTTPS myproxy:70"),
- response->proxy_server);
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- }
- // Test the challenge-response-retry sequence through an HTTPS Proxy over a
- // connection that requires a restart.
- TEST_F(HttpNetworkTransactionTest, HttpsProxyAuthRetryNoKeepAlive) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- // when the no authentication data flag is set.
- request.privacy_mode = PRIVACY_MODE_ENABLED;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against https proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since we have proxy, should use full url
- MockWrite data_writes1[] = {
- MockWrite("GET http://www.example.org/ HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the GET with a 407, using a non-persistent
- // connection.
- MockRead data_reads1[] = {
- // No credentials.
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Proxy-Connection: close\r\n"),
- MockRead("Content-Length: 0\r\n\r\n"),
- };
- MockWrite data_writes2[] = {
- // After calling trans.RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite("GET http://www.example.org/ HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- // One per each proxy connection.
- SSLSocketDataProvider ssl1(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info,
- CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(CheckBasicSecureProxyAuth(response->auth_challenge));
- EXPECT_FALSE(response->did_use_http_auth);
- EXPECT_EQ(PacResultElementToProxyServer("HTTPS myproxy:70"),
- response->proxy_server);
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- load_timing_info = LoadTimingInfo();
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info,
- CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(100, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(response->did_use_http_auth);
- EXPECT_EQ(PacResultElementToProxyServer("HTTPS myproxy:70"),
- response->proxy_server);
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- }
- // Test the challenge-response-retry sequence through an HTTPS Proxy over a
- // connection that requires a restart, with a proxy change occurring over the
- // restart.
- TEST_F(HttpNetworkTransactionTest, HttpsProxyAuthRetryNoKeepAliveChangeProxy) {
- const auto proxy1 = PacResultElementToProxyServer("HTTPS myproxy:70");
- const auto proxy2 = PacResultElementToProxyServer("HTTPS myproxy2:70");
- auto proxy_delegate = std::make_unique<SingleProxyDelegate>();
- proxy_delegate->set_proxy(proxy1);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- // when the no authentication data flag is set.
- request.privacy_mode = PRIVACY_MODE_ENABLED;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against https proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.proxy_resolution_service->SetProxyDelegate(
- proxy_delegate.get());
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since we have proxy, should use full url
- MockWrite data_writes1[] = {
- MockWrite("GET http://www.example.org/ HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the GET with a 407, using a non-persistent
- // connection.
- MockRead data_reads1[] = {
- // No credentials.
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Proxy-Connection: close\r\n"),
- MockRead("Content-Length: 0\r\n\r\n"),
- };
- MockWrite data_writes2[] = {
- // After calling trans.RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite("GET http://www.example.org/ HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- // One per each proxy connection.
- SSLSocketDataProvider ssl1(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info,
- CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(CheckBasicSecureProxyAuth(response->auth_challenge));
- EXPECT_FALSE(response->did_use_http_auth);
- EXPECT_EQ(proxy1, response->proxy_server);
- TestCompletionCallback callback2;
- // Configure against https proxy server "myproxy2:70".
- proxy_delegate->set_proxy(proxy2);
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- load_timing_info = LoadTimingInfo();
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info,
- CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(100, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(response->did_use_http_auth);
- EXPECT_EQ(proxy2, response->proxy_server);
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- }
- // Test the challenge-response-retry sequence through an HTTPS Proxy over a
- // connection that requires a restart, with a change to a direct connection
- // occurring over the restart.
- TEST_F(HttpNetworkTransactionTest,
- HttpsProxyAuthRetryNoKeepAliveChangeToDirect) {
- const auto proxy = PacResultElementToProxyServer("HTTPS myproxy:70");
- const auto direct = ProxyServer::Direct();
- auto proxy_delegate = std::make_unique<SingleProxyDelegate>();
- proxy_delegate->set_proxy(proxy);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- // when the no authentication data flag is set.
- request.privacy_mode = PRIVACY_MODE_ENABLED;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against https proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.proxy_resolution_service->SetProxyDelegate(
- proxy_delegate.get());
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since we have proxy, should use full url
- MockWrite data_writes1[] = {
- MockWrite("GET http://www.example.org/ HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the GET with a 407, using a non-persistent
- // connection.
- MockRead data_reads1[] = {
- // No credentials.
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Proxy-Connection: close\r\n"),
- MockRead("Content-Length: 0\r\n\r\n"),
- };
- MockWrite data_writes2[] = {
- // After calling trans.RestartWithAuth(), this is the request we should
- // be issuing.
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- // One per each connection.
- SSLSocketDataProvider ssl1(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info,
- CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(CheckBasicSecureProxyAuth(response->auth_challenge));
- EXPECT_FALSE(response->did_use_http_auth);
- EXPECT_EQ(proxy, response->proxy_server);
- TestCompletionCallback callback2;
- // Configure to use a direct connection.
- proxy_delegate->set_proxy(direct);
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- load_timing_info = LoadTimingInfo();
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info, CONNECT_TIMING_HAS_DNS_TIMES);
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(100, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_FALSE(response->did_use_http_auth);
- EXPECT_EQ(direct, response->proxy_server);
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- }
- void HttpNetworkTransactionTest::ConnectStatusHelperWithExpectedStatus(
- const MockRead& status, int expected_status) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- status, MockRead("Content-Length: 10\r\n\r\n"),
- // No response body because the test stops reading here.
- MockRead(SYNCHRONOUS, ERR_UNEXPECTED),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_EQ(expected_status, rv);
- }
- void HttpNetworkTransactionTest::ConnectStatusHelper(
- const MockRead& status) {
- ConnectStatusHelperWithExpectedStatus(
- status, ERR_TUNNEL_CONNECTION_FAILED);
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus100) {
- ConnectStatusHelper(MockRead("HTTP/1.1 100 Continue\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus101) {
- ConnectStatusHelper(MockRead("HTTP/1.1 101 Switching Protocols\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus201) {
- ConnectStatusHelper(MockRead("HTTP/1.1 201 Created\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus202) {
- ConnectStatusHelper(MockRead("HTTP/1.1 202 Accepted\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus203) {
- ConnectStatusHelper(
- MockRead("HTTP/1.1 203 Non-Authoritative Information\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus204) {
- ConnectStatusHelper(MockRead("HTTP/1.1 204 No Content\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus205) {
- ConnectStatusHelper(MockRead("HTTP/1.1 205 Reset Content\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus206) {
- ConnectStatusHelper(MockRead("HTTP/1.1 206 Partial Content\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus300) {
- ConnectStatusHelper(MockRead("HTTP/1.1 300 Multiple Choices\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus301) {
- ConnectStatusHelper(MockRead("HTTP/1.1 301 Moved Permanently\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus302) {
- ConnectStatusHelper(MockRead("HTTP/1.1 302 Found\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus303) {
- ConnectStatusHelper(MockRead("HTTP/1.1 303 See Other\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus304) {
- ConnectStatusHelper(MockRead("HTTP/1.1 304 Not Modified\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus305) {
- ConnectStatusHelper(MockRead("HTTP/1.1 305 Use Proxy\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus306) {
- ConnectStatusHelper(MockRead("HTTP/1.1 306\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus307) {
- ConnectStatusHelper(MockRead("HTTP/1.1 307 Temporary Redirect\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus308) {
- ConnectStatusHelper(MockRead("HTTP/1.1 308 Permanent Redirect\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus400) {
- ConnectStatusHelper(MockRead("HTTP/1.1 400 Bad Request\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus401) {
- ConnectStatusHelper(MockRead("HTTP/1.1 401 Unauthorized\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus402) {
- ConnectStatusHelper(MockRead("HTTP/1.1 402 Payment Required\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus403) {
- ConnectStatusHelper(MockRead("HTTP/1.1 403 Forbidden\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus404) {
- ConnectStatusHelper(MockRead("HTTP/1.1 404 Not Found\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus405) {
- ConnectStatusHelper(MockRead("HTTP/1.1 405 Method Not Allowed\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus406) {
- ConnectStatusHelper(MockRead("HTTP/1.1 406 Not Acceptable\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus407) {
- ConnectStatusHelperWithExpectedStatus(
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- ERR_PROXY_AUTH_UNSUPPORTED);
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus408) {
- ConnectStatusHelper(MockRead("HTTP/1.1 408 Request Timeout\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus409) {
- ConnectStatusHelper(MockRead("HTTP/1.1 409 Conflict\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus410) {
- ConnectStatusHelper(MockRead("HTTP/1.1 410 Gone\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus411) {
- ConnectStatusHelper(MockRead("HTTP/1.1 411 Length Required\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus412) {
- ConnectStatusHelper(MockRead("HTTP/1.1 412 Precondition Failed\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus413) {
- ConnectStatusHelper(MockRead("HTTP/1.1 413 Request Entity Too Large\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus414) {
- ConnectStatusHelper(MockRead("HTTP/1.1 414 Request-URI Too Long\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus415) {
- ConnectStatusHelper(MockRead("HTTP/1.1 415 Unsupported Media Type\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus416) {
- ConnectStatusHelper(
- MockRead("HTTP/1.1 416 Requested Range Not Satisfiable\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus417) {
- ConnectStatusHelper(MockRead("HTTP/1.1 417 Expectation Failed\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus500) {
- ConnectStatusHelper(MockRead("HTTP/1.1 500 Internal Server Error\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus501) {
- ConnectStatusHelper(MockRead("HTTP/1.1 501 Not Implemented\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus502) {
- ConnectStatusHelper(MockRead("HTTP/1.1 502 Bad Gateway\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus503) {
- ConnectStatusHelper(MockRead("HTTP/1.1 503 Service Unavailable\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus504) {
- ConnectStatusHelper(MockRead("HTTP/1.1 504 Gateway Timeout\r\n"));
- }
- TEST_F(HttpNetworkTransactionTest, ConnectStatus505) {
- ConnectStatusHelper(MockRead("HTTP/1.1 505 HTTP Version Not Supported\r\n"));
- }
- // Test the flow when both the proxy server AND origin server require
- // authentication. Again, this uses basic auth for both since that is
- // the simplest to mock.
- TEST_F(HttpNetworkTransactionTest, BasicAuthProxyThenServer) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes1[] = {
- MockWrite(
- "GET http://www.example.org/ HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 407 Unauthorized\r\n"),
- // Give a couple authenticate options (only the middle one is actually
- // supported).
- MockRead("Proxy-Authenticate: Basic invalid\r\n"), // Malformed.
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Proxy-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- // Large content-length -- won't matter, as connection will be reset.
- MockRead("Content-Length: 10000\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- // After calling trans.RestartWithAuth() the first time, this is the
- // request we should be issuing -- the final header line contains the
- // proxy's credentials.
- MockWrite data_writes2[] = {
- MockWrite(
- "GET http://www.example.org/ HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- // Now the proxy server lets the request pass through to origin server.
- // The origin server responds with a 401.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- // Note: We are using the same realm-name as the proxy server. This is
- // completely valid, as realms are unique across hosts.
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 2000\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED), // Won't be reached.
- };
- // After calling trans.RestartWithAuth() the second time, we should send
- // the credentials for both the proxy and origin server.
- MockWrite data_writes3[] = {
- MockWrite(
- "GET http://www.example.org/ HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n"
- "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
- };
- // Lastly we get the desired content.
- MockRead data_reads3[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- StaticSocketDataProvider data3(data_reads3, data_writes3);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- session_deps_.socket_factory->AddSocketDataProvider(&data3);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckBasicProxyAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge));
- TestCompletionCallback callback3;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo2, kBar2),
- callback3.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback3.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(100, response->headers->GetContentLength());
- }
- // For the NTLM implementation using SSPI, we skip the NTLM tests since we
- // can't hook into its internals to cause it to generate predictable NTLM
- // authorization headers.
- #if defined(NTLM_PORTABLE)
- // The NTLM authentication unit tests are based on known test data from the
- // [MS-NLMP] Specification [1]. These tests are primarily of the authentication
- // flow rather than the implementation of the NTLM protocol. See net/ntlm
- // for the implementation and testing of the protocol.
- //
- // [1] https://msdn.microsoft.com/en-us/library/cc236621.aspx
- // Enter the correct password and authenticate successfully.
- TEST_F(HttpNetworkTransactionTest, NTLMAuthV2) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://server/kids/login.aspx");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Ensure load is not disrupted by flags which suppress behaviour specific
- // to other auth schemes.
- request.load_flags = LOAD_DO_NOT_USE_EMBEDDED_IDENTITY;
- HttpAuthNtlmMechanism::ScopedProcSetter proc_setter(
- MockGetMSTime, MockGenerateRandom, MockGetHostName);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Generate the NTLM messages based on known test data.
- std::string negotiate_msg;
- std::string challenge_msg;
- std::string authenticate_msg;
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(ntlm::test::kExpectedNegotiateMsg),
- std::size(ntlm::test::kExpectedNegotiateMsg)),
- &negotiate_msg);
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(ntlm::test::kChallengeMsgFromSpecV2),
- std::size(ntlm::test::kChallengeMsgFromSpecV2)),
- &challenge_msg);
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(
- ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2),
- std::size(
- ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2)),
- &authenticate_msg);
- MockWrite data_writes1[] = {
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: server\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 401 Access Denied\r\n"),
- // Negotiate and NTLM are often requested together. However, we only want
- // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip
- // the header that requests Negotiate for this test.
- MockRead("WWW-Authenticate: NTLM\r\n"),
- MockRead("Connection: close\r\n"),
- MockRead("Content-Length: 42\r\n"),
- MockRead("Content-Type: text/html\r\n\r\n"),
- // Missing content -- won't matter, as connection will be reset.
- };
- MockWrite data_writes2[] = {
- // After restarting with a null identity, this is the
- // request we should be issuing -- the final header line contains a Type
- // 1 message.
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: server\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: NTLM "),
- MockWrite(negotiate_msg.c_str()), MockWrite("\r\n\r\n"),
- // After calling trans.RestartWithAuth(), we should send a Type 3 message
- // (using correct credentials). The second request continues on the
- // same connection.
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: server\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: NTLM "),
- MockWrite(authenticate_msg.c_str()), MockWrite("\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- // The origin server responds with a Type 2 message.
- MockRead("HTTP/1.1 401 Access Denied\r\n"),
- MockRead("WWW-Authenticate: NTLM "), MockRead(challenge_msg.c_str()),
- MockRead("\r\n"), MockRead("Content-Length: 42\r\n"),
- MockRead("Content-Type: text/html\r\n\r\n"),
- MockRead("You are not authorized to view this page\r\n"),
- // Lastly we get the desired content.
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=utf-8\r\n"),
- MockRead("Content-Length: 14\r\n\r\n"), MockRead("Please Login\r\n"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl1(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(
- AuthCredentials(ntlm::test::kDomainUserCombined, ntlm::test::kPassword),
- callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans.IsReadyToRestartForAuth());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- TestCompletionCallback callback3;
- rv = trans.RestartWithAuth(AuthCredentials(), callback3.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback3.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(14, response->headers->GetContentLength());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("Please Login\r\n", response_data);
- EXPECT_TRUE(data1.AllReadDataConsumed());
- EXPECT_TRUE(data1.AllWriteDataConsumed());
- EXPECT_TRUE(data2.AllReadDataConsumed());
- EXPECT_TRUE(data2.AllWriteDataConsumed());
- }
- // Enter a wrong password, and then the correct one.
- TEST_F(HttpNetworkTransactionTest, NTLMAuthV2WrongThenRightPassword) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://server/kids/login.aspx");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpAuthNtlmMechanism::ScopedProcSetter proc_setter(
- MockGetMSTime, MockGenerateRandom, MockGetHostName);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Generate the NTLM messages based on known test data.
- std::string negotiate_msg;
- std::string challenge_msg;
- std::string authenticate_msg;
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(ntlm::test::kExpectedNegotiateMsg),
- std::size(ntlm::test::kExpectedNegotiateMsg)),
- &negotiate_msg);
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(ntlm::test::kChallengeMsgFromSpecV2),
- std::size(ntlm::test::kChallengeMsgFromSpecV2)),
- &challenge_msg);
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(
- ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2),
- std::size(
- ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2)),
- &authenticate_msg);
- // The authenticate message when |kWrongPassword| is sent.
- std::string wrong_password_authenticate_msg(
- "TlRMTVNTUAADAAAAGAAYAFgAAACKAIoAcAAAAAwADAD6AAAACAAIAAYBAAAQABAADgEAAAAA"
- "AABYAAAAA4IIAAAAAAAAAAAAAPknEYqtJQtusopDRSfYzAAAAAAAAAAAAAAAAAAAAAAAAAAA"
- "AAAAAOtVz38osnFdRRggUQHUJ3EBAQAAAAAAAIALyP0A1NIBqqqqqqqqqqoAAAAAAgAMAEQA"
- "bwBtAGEAaQBuAAEADABTAGUAcgB2AGUAcgAGAAQAAgAAAAoAEAAAAAAAAAAAAAAAAAAAAAAA"
- "CQAWAEgAVABUAFAALwBzAGUAcgB2AGUAcgAAAAAAAAAAAEQAbwBtAGEAaQBuAFUAcwBlAHIA"
- "QwBPAE0AUABVAFQARQBSAA==");
- // Sanity check that it's the same length as the correct authenticate message
- // and that it's different.
- ASSERT_EQ(authenticate_msg.length(),
- wrong_password_authenticate_msg.length());
- ASSERT_NE(authenticate_msg, wrong_password_authenticate_msg);
- MockWrite data_writes1[] = {
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: server\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 401 Access Denied\r\n"),
- // Negotiate and NTLM are often requested together. However, we only want
- // to test NTLM. Since Negotiate is preferred over NTLM, we have to skip
- // the header that requests Negotiate for this test.
- MockRead("WWW-Authenticate: NTLM\r\n"),
- MockRead("Connection: close\r\n"),
- MockRead("Content-Length: 42\r\n"),
- MockRead("Content-Type: text/html\r\n\r\n"),
- // Missing content -- won't matter, as connection will be reset.
- };
- MockWrite data_writes2[] = {
- // After restarting with a null identity, this is the
- // request we should be issuing -- the final header line contains a Type
- // 1 message.
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: server\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: NTLM "),
- MockWrite(negotiate_msg.c_str()), MockWrite("\r\n\r\n"),
- // After calling trans.RestartWithAuth(), we should send a Type 3 message
- // (using incorrect credentials). The second request continues on the
- // same connection.
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: server\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: NTLM "),
- MockWrite(wrong_password_authenticate_msg.c_str()), MockWrite("\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- // The origin server responds with a Type 2 message.
- MockRead("HTTP/1.1 401 Access Denied\r\n"),
- MockRead("WWW-Authenticate: NTLM "), MockRead(challenge_msg.c_str()),
- MockRead("\r\n"), MockRead("Content-Length: 42\r\n"),
- MockRead("Content-Type: text/html\r\n\r\n"),
- MockRead("You are not authorized to view this page\r\n"),
- // Wrong password.
- MockRead("HTTP/1.1 401 Access Denied\r\n"),
- MockRead("WWW-Authenticate: NTLM\r\n"), MockRead("Connection: close\r\n"),
- MockRead("Content-Length: 42\r\n"),
- MockRead("Content-Type: text/html\r\n\r\n"),
- // Missing content -- won't matter, as connection will be reset.
- };
- MockWrite data_writes3[] = {
- // After restarting with a null identity, this is the
- // request we should be issuing -- the final header line contains a Type
- // 1 message.
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: server\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: NTLM "),
- MockWrite(negotiate_msg.c_str()), MockWrite("\r\n\r\n"),
- // After calling trans.RestartWithAuth(), we should send a Type 3 message
- // (the credentials for the origin server). The second request continues
- // on the same connection.
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: server\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: NTLM "),
- MockWrite(authenticate_msg.c_str()), MockWrite("\r\n\r\n"),
- };
- MockRead data_reads3[] = {
- // The origin server responds with a Type 2 message.
- MockRead("HTTP/1.1 401 Access Denied\r\n"),
- MockRead("WWW-Authenticate: NTLM "), MockRead(challenge_msg.c_str()),
- MockRead("\r\n"), MockRead("Content-Length: 42\r\n"),
- MockRead("Content-Type: text/html\r\n\r\n"),
- MockRead("You are not authorized to view this page\r\n"),
- // Lastly we get the desired content.
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=utf-8\r\n"),
- MockRead("Content-Length: 14\r\n\r\n"), MockRead("Please Login\r\n"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- StaticSocketDataProvider data3(data_reads3, data_writes3);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- session_deps_.socket_factory->AddSocketDataProvider(&data3);
- SSLSocketDataProvider ssl1(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- SSLSocketDataProvider ssl3(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl3);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- // Enter the wrong password.
- rv = trans.RestartWithAuth(
- AuthCredentials(ntlm::test::kDomainUserCombined, kWrongPassword),
- callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans.IsReadyToRestartForAuth());
- TestCompletionCallback callback3;
- rv = trans.RestartWithAuth(AuthCredentials(), callback3.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback3.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge));
- TestCompletionCallback callback4;
- // Now enter the right password.
- rv = trans.RestartWithAuth(
- AuthCredentials(ntlm::test::kDomainUserCombined, ntlm::test::kPassword),
- callback4.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback4.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans.IsReadyToRestartForAuth());
- TestCompletionCallback callback5;
- // One more roundtrip
- rv = trans.RestartWithAuth(AuthCredentials(), callback5.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback5.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(14, response->headers->GetContentLength());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("Please Login\r\n", response_data);
- EXPECT_TRUE(data1.AllReadDataConsumed());
- EXPECT_TRUE(data1.AllWriteDataConsumed());
- EXPECT_TRUE(data2.AllReadDataConsumed());
- EXPECT_TRUE(data2.AllWriteDataConsumed());
- EXPECT_TRUE(data3.AllReadDataConsumed());
- EXPECT_TRUE(data3.AllWriteDataConsumed());
- }
- // Server requests NTLM authentication, which is not supported over HTTP/2.
- // Subsequent request with authorization header should be sent over HTTP/1.1.
- TEST_F(HttpNetworkTransactionTest, NTLMOverHttp2) {
- HttpAuthNtlmMechanism::ScopedProcSetter proc_setter(
- MockGetMSTime, MockGenerateRandom, MockGetHostName);
- const char* kUrl = "https://server/kids/login.aspx";
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL(kUrl);
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // First request without credentials.
- spdy::Http2HeaderBlock request_headers0(
- spdy_util_.ConstructGetHeaderBlock(kUrl));
- spdy::SpdySerializedFrame request0(spdy_util_.ConstructSpdyHeaders(
- 1, std::move(request_headers0), LOWEST, true));
- spdy::Http2HeaderBlock response_headers0;
- response_headers0[spdy::kHttp2StatusHeader] = "401";
- response_headers0["www-authenticate"] = "NTLM";
- spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyResponseHeaders(
- 1, std::move(response_headers0), true));
- // Stream 1 is closed.
- spdy_util_.UpdateWithStreamDestruction(1);
- // Generate the NTLM messages based on known test data.
- std::string negotiate_msg;
- std::string challenge_msg;
- std::string authenticate_msg;
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(ntlm::test::kExpectedNegotiateMsg),
- std::size(ntlm::test::kExpectedNegotiateMsg)),
- &negotiate_msg);
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(ntlm::test::kChallengeMsgFromSpecV2),
- std::size(ntlm::test::kChallengeMsgFromSpecV2)),
- &challenge_msg);
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(
- ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2),
- std::size(
- ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2)),
- &authenticate_msg);
- MockWrite writes0[] = {CreateMockWrite(request0, 0)};
- MockRead reads0[] = {CreateMockRead(resp, 1),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 2)};
- // Retry yet again using HTTP/1.1.
- MockWrite writes1[] = {
- // After restarting with a null identity, this is the
- // request we should be issuing -- the final header line contains a Type
- // 1 message.
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: server\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: NTLM "),
- MockWrite(negotiate_msg.c_str()), MockWrite("\r\n\r\n"),
- // After calling trans.RestartWithAuth(), we should send a Type 3 message
- // (the credentials for the origin server). The second request continues
- // on the same connection.
- MockWrite("GET /kids/login.aspx HTTP/1.1\r\n"
- "Host: server\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: NTLM "),
- MockWrite(authenticate_msg.c_str()), MockWrite("\r\n\r\n"),
- };
- MockRead reads1[] = {
- // The origin server responds with a Type 2 message.
- MockRead("HTTP/1.1 401 Access Denied\r\n"),
- MockRead("WWW-Authenticate: NTLM "), MockRead(challenge_msg.c_str()),
- MockRead("\r\n"), MockRead("Content-Length: 42\r\n"),
- MockRead("Content-Type: text/html\r\n\r\n"),
- MockRead("You are not authorized to view this page\r\n"),
- // Lastly we get the desired content.
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=utf-8\r\n"),
- MockRead("Content-Length: 14\r\n\r\n"), MockRead("Please Login\r\n"),
- };
- SequencedSocketData data0(reads0, writes0);
- StaticSocketDataProvider data1(reads1, writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data0);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl0(ASYNC, OK);
- ssl0.next_proto = kProtoHTTP2;
- ssl0.next_protos_expected_in_ssl_config =
- NextProtoVector{kProtoHTTP2, kProtoHTTP11};
- SSLSocketDataProvider ssl1(ASYNC, OK);
- // When creating the second connection, only HTTP/1.1 should be allowed.
- ssl1.next_protos_expected_in_ssl_config = NextProtoVector{kProtoHTTP11};
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl0);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(
- AuthCredentials(ntlm::test::kDomainUserCombined, ntlm::test::kPassword),
- callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans.IsReadyToRestartForAuth());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- TestCompletionCallback callback3;
- rv = trans.RestartWithAuth(AuthCredentials(), callback3.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback3.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(14, response->headers->GetContentLength());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("Please Login\r\n", response_data);
- EXPECT_TRUE(data0.AllReadDataConsumed());
- EXPECT_TRUE(data0.AllWriteDataConsumed());
- EXPECT_TRUE(data1.AllReadDataConsumed());
- EXPECT_TRUE(data1.AllWriteDataConsumed());
- }
- #if BUILDFLAG(ENABLE_WEBSOCKETS)
- // Variant of above test using WebSockets.
- TEST_F(HttpNetworkTransactionTest, NTLMOverHttp2WithWebsockets) {
- const GURL kInitialUrl("https://server/");
- const GURL kWebSocketUrl("wss://server/");
- HttpAuthNtlmMechanism::ScopedProcSetter proc_setter(
- MockGetMSTime, MockGenerateRandom, MockGetHostName);
- // Initial request establishes an H2 connection, which will then be reused for
- // WebSockets. This is needed since WebSockets will reuse H2 connections, but
- // it won't create a new one.
- spdy::Http2HeaderBlock initial_request_headers(
- spdy_util_.ConstructGetHeaderBlock(kInitialUrl.spec()));
- spdy::SpdySerializedFrame initial_request(spdy_util_.ConstructSpdyHeaders(
- 1, std::move(initial_request_headers), DEFAULT_PRIORITY, true));
- spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
- // Settings frame, indicating WebSockets is supported.
- spdy::SettingsMap settings;
- settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
- spdy::SpdySerializedFrame settings_frame(
- spdy_util_.ConstructSpdySettings(settings));
- // Response headers for first request. Body is never received, but that
- // shouldn't matter for the purposes of this test.
- spdy::SpdySerializedFrame initial_response(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- // First WebSocket request, which has no credentials.
- spdy::Http2HeaderBlock websocket_request_headers;
- websocket_request_headers[spdy::kHttp2MethodHeader] = "CONNECT";
- websocket_request_headers[spdy::kHttp2AuthorityHeader] = "server";
- websocket_request_headers[spdy::kHttp2SchemeHeader] = "https";
- websocket_request_headers[spdy::kHttp2PathHeader] = "/";
- websocket_request_headers[spdy::kHttp2ProtocolHeader] = "websocket";
- websocket_request_headers["origin"] = "http://server";
- websocket_request_headers["sec-websocket-version"] = "13";
- websocket_request_headers["sec-websocket-extensions"] =
- "permessage-deflate; client_max_window_bits";
- spdy::SpdySerializedFrame websocket_request(spdy_util_.ConstructSpdyHeaders(
- 3, std::move(websocket_request_headers), MEDIUM, false));
- // Auth challenge to WebSocket request.
- spdy::Http2HeaderBlock auth_challenge_headers;
- auth_challenge_headers[spdy::kHttp2StatusHeader] = "401";
- auth_challenge_headers["www-authenticate"] = "NTLM";
- spdy::SpdySerializedFrame websocket_auth_challenge(
- spdy_util_.ConstructSpdyResponseHeaders(
- 3, std::move(auth_challenge_headers), true));
- MockWrite writes0[] = {CreateMockWrite(initial_request, 0),
- CreateMockWrite(settings_ack, 2),
- CreateMockWrite(websocket_request, 4),
- MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 7)};
- MockRead reads0[] = {CreateMockRead(settings_frame, 1),
- CreateMockRead(initial_response, 3),
- CreateMockRead(websocket_auth_challenge, 5),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)};
- // Generate the NTLM messages based on known test data.
- std::string negotiate_msg;
- std::string challenge_msg;
- std::string authenticate_msg;
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(ntlm::test::kExpectedNegotiateMsg),
- std::size(ntlm::test::kExpectedNegotiateMsg)),
- &negotiate_msg);
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(ntlm::test::kChallengeMsgFromSpecV2),
- std::size(ntlm::test::kChallengeMsgFromSpecV2)),
- &challenge_msg);
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(
- ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2),
- std::size(
- ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2)),
- &authenticate_msg);
- // Retry yet again using HTTP/1.1.
- MockWrite writes1[] = {
- // After restarting with a null identity, this is the
- // request we should be issuing -- the final header line contains a Type
- // 1 message.
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: server\r\n"
- "Connection: Upgrade\r\n"
- "Authorization: NTLM "),
- MockWrite(negotiate_msg.c_str()),
- MockWrite("\r\n"),
- MockWrite("Origin: http://server\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "Upgrade: websocket\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Sec-WebSocket-Extensions: permessage-deflate; "
- "client_max_window_bits\r\n\r\n"),
- // After calling trans.RestartWithAuth(), we should send a Type 3 message
- // (the credentials for the origin server). The second request continues
- // on the same connection.
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: server\r\n"
- "Connection: Upgrade\r\n"
- "Authorization: NTLM "),
- MockWrite(authenticate_msg.c_str()),
- MockWrite("\r\n"),
- MockWrite("Origin: http://server\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "Upgrade: websocket\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Sec-WebSocket-Extensions: permessage-deflate; "
- "client_max_window_bits\r\n\r\n"),
- };
- MockRead reads1[] = {
- // The origin server responds with a Type 2 message.
- MockRead("HTTP/1.1 401 Access Denied\r\n"),
- MockRead("WWW-Authenticate: NTLM "),
- MockRead(challenge_msg.c_str()),
- MockRead("\r\n"),
- MockRead("Content-Length: 42\r\n"),
- MockRead("Content-Type: text/html\r\n\r\n"),
- MockRead("You are not authorized to view this page\r\n"),
- // Lastly we get the desired content.
- MockRead("HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n"),
- };
- SequencedSocketData data0(reads0, writes0);
- session_deps_.socket_factory->AddSocketDataProvider(&data0);
- SSLSocketDataProvider ssl0(ASYNC, OK);
- ssl0.next_proto = kProtoHTTP2;
- ssl0.next_protos_expected_in_ssl_config =
- NextProtoVector{kProtoHTTP2, kProtoHTTP11};
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl0);
- StaticSocketDataProvider data1(reads1, writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl1(ASYNC, OK);
- // When creating the second connection, only HTTP/1.1 should be allowed.
- ssl1.next_protos_expected_in_ssl_config = NextProtoVector{kProtoHTTP11};
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpRequestInfo initial_request_info;
- initial_request_info.method = "GET";
- initial_request_info.url = kInitialUrl;
- initial_request_info.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction initial_trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback initial_callback;
- int rv = initial_trans.Start(&initial_request_info,
- initial_callback.callback(), NetLogWithSource());
- EXPECT_THAT(initial_callback.GetResult(rv), IsOk());
- EXPECT_FALSE(session->http_server_properties()->RequiresHTTP11(
- url::SchemeHostPort(kInitialUrl), NetworkIsolationKey()));
- HttpRequestInfo websocket_request_info;
- websocket_request_info.method = "GET";
- websocket_request_info.url = kWebSocketUrl;
- websocket_request_info.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- EXPECT_TRUE(HostPortPair::FromURL(initial_request_info.url)
- .Equals(HostPortPair::FromURL(websocket_request_info.url)));
- websocket_request_info.extra_headers.SetHeader("Origin", "http://server");
- websocket_request_info.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
- // The following two headers must be removed by WebSocketHttp2HandshakeStream.
- websocket_request_info.extra_headers.SetHeader("Connection", "Upgrade");
- websocket_request_info.extra_headers.SetHeader("Upgrade", "websocket");
- TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
- HttpNetworkTransaction websocket_trans(MEDIUM, session.get());
- websocket_trans.SetWebSocketHandshakeStreamCreateHelper(
- &websocket_stream_create_helper);
- TestCompletionCallback websocket_callback;
- rv = websocket_trans.Start(&websocket_request_info,
- websocket_callback.callback(), NetLogWithSource());
- EXPECT_THAT(websocket_callback.GetResult(rv), IsOk());
- EXPECT_FALSE(websocket_trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = websocket_trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckNTLMServerAuth(response->auth_challenge));
- rv = websocket_trans.RestartWithAuth(
- AuthCredentials(ntlm::test::kDomainUserCombined, ntlm::test::kPassword),
- websocket_callback.callback());
- EXPECT_THAT(websocket_callback.GetResult(rv), IsOk());
- EXPECT_TRUE(websocket_trans.IsReadyToRestartForAuth());
- response = websocket_trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- rv = websocket_trans.RestartWithAuth(AuthCredentials(),
- websocket_callback.callback());
- EXPECT_THAT(websocket_callback.GetResult(rv), IsOk());
- // The server should have been marked as requiring HTTP/1.1. The important
- // part here is that the scheme that requires HTTP/1.1 should be HTTPS, not
- // WSS.
- EXPECT_TRUE(session->http_server_properties()->RequiresHTTP11(
- url::SchemeHostPort(kInitialUrl), NetworkIsolationKey()));
- }
- #endif // BUILDFLAG(ENABLE_WEBSOCKETS)
- // Test that, if we have an NTLM proxy and the origin resets the connection, we
- // do no retry forever as a result of TLS retries. This is a regression test for
- // https://crbug.com/823387. The version interference probe has since been
- // removed, but we now have a legacy crypto fallback. (If that fallback is
- // removed, this test should be kept but with the expectations tweaked, in case
- // future fallbacks are added.)
- TEST_F(HttpNetworkTransactionTest, NTLMProxyTLSHandshakeReset) {
- // The NTLM test data expects the proxy to be named 'server'. The origin is
- // https://origin/.
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY server", TRAFFIC_ANNOTATION_FOR_TESTS);
- SSLContextConfig config;
- session_deps_.ssl_config_service =
- std::make_unique<TestSSLConfigService>(config);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://origin/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Ensure load is not disrupted by flags which suppress behaviour specific
- // to other auth schemes.
- request.load_flags = LOAD_DO_NOT_USE_EMBEDDED_IDENTITY;
- HttpAuthNtlmMechanism::ScopedProcSetter proc_setter(
- MockGetMSTime, MockGenerateRandom, MockGetHostName);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Generate the NTLM messages based on known test data.
- std::string negotiate_msg;
- std::string challenge_msg;
- std::string authenticate_msg;
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(ntlm::test::kExpectedNegotiateMsg),
- std::size(ntlm::test::kExpectedNegotiateMsg)),
- &negotiate_msg);
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(ntlm::test::kChallengeMsgFromSpecV2),
- std::size(ntlm::test::kChallengeMsgFromSpecV2)),
- &challenge_msg);
- base::Base64Encode(
- base::StringPiece(
- reinterpret_cast<const char*>(
- ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2),
- std::size(
- ntlm::test::kExpectedAuthenticateMsgEmptyChannelBindingsV2)),
- &authenticate_msg);
- MockWrite data_writes[] = {
- // The initial CONNECT request.
- MockWrite("CONNECT origin:443 HTTP/1.1\r\n"
- "Host: origin:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- // After restarting with an identity.
- MockWrite("CONNECT origin:443 HTTP/1.1\r\n"
- "Host: origin:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: NTLM "),
- MockWrite(negotiate_msg.c_str()),
- // End headers.
- MockWrite("\r\n\r\n"),
- // The second restart.
- MockWrite("CONNECT origin:443 HTTP/1.1\r\n"
- "Host: origin:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: NTLM "),
- MockWrite(authenticate_msg.c_str()),
- // End headers.
- MockWrite("\r\n\r\n"),
- };
- MockRead data_reads[] = {
- // The initial NTLM response.
- MockRead("HTTP/1.1 407 Access Denied\r\n"
- "Content-Length: 0\r\n"
- "Proxy-Authenticate: NTLM\r\n\r\n"),
- // The NTLM challenge message.
- MockRead("HTTP/1.1 407 Access Denied\r\n"
- "Content-Length: 0\r\n"
- "Proxy-Authenticate: NTLM "),
- MockRead(challenge_msg.c_str()),
- // End headers.
- MockRead("\r\n\r\n"),
- // Finally the tunnel is established.
- MockRead("HTTP/1.1 200 Connected\r\n\r\n"),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- SSLSocketDataProvider data_ssl(ASYNC, ERR_CONNECTION_RESET);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&data_ssl);
- StaticSocketDataProvider data2(data_reads, data_writes);
- SSLSocketDataProvider data2_ssl(ASYNC, ERR_CONNECTION_RESET);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&data2_ssl);
- // Start the transaction. The proxy responds with an NTLM authentication
- // request.
- TestCompletionCallback callback;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = callback.GetResult(
- trans.Start(&request, callback.callback(), NetLogWithSource()));
- EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckNTLMProxyAuth(response->auth_challenge));
- // Configure credentials and restart. The proxy responds with the challenge
- // message.
- rv = callback.GetResult(trans.RestartWithAuth(
- AuthCredentials(ntlm::test::kDomainUserCombined, ntlm::test::kPassword),
- callback.callback()));
- EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans.IsReadyToRestartForAuth());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- // Restart once more. The tunnel will be established and the the SSL handshake
- // will reset. The fallback will then kick in and restart the process. The
- // proxy responds with another NTLM authentiation request, but we don't need
- // to provide credentials as the cached ones work.
- rv = callback.GetResult(
- trans.RestartWithAuth(AuthCredentials(), callback.callback()));
- EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans.IsReadyToRestartForAuth());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- // The proxy responds with the NTLM challenge message.
- rv = callback.GetResult(
- trans.RestartWithAuth(AuthCredentials(), callback.callback()));
- EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans.IsReadyToRestartForAuth());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- // Send the NTLM authenticate message. The tunnel is established and the
- // handshake resets again. We should not retry again.
- rv = callback.GetResult(
- trans.RestartWithAuth(AuthCredentials(), callback.callback()));
- EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
- }
- #endif // NTLM_PORTABLE
- // Test reading a server response which has only headers, and no body.
- // After some maximum number of bytes is consumed, the transaction should
- // fail with ERR_RESPONSE_HEADERS_TOO_BIG.
- TEST_F(HttpNetworkTransactionTest, LargeHeadersNoBody) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Respond with 300 kb of headers (we should fail after 256 kb).
- std::string large_headers_string;
- FillLargeHeadersString(&large_headers_string, 300 * 1024);
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead(ASYNC, large_headers_string.data(), large_headers_string.size()),
- MockRead("\r\nBODY"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_RESPONSE_HEADERS_TOO_BIG));
- }
- // Make sure that we don't try to reuse a TCPClientSocket when failing to
- // establish tunnel.
- // http://code.google.com/p/chromium/issues/detail?id=3772
- TEST_F(HttpNetworkTransactionTest, DontRecycleTransportSocketForSSLTunnel) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the connect with a 404, using a persistent
- // connection. Usually a proxy would return 501 (not implemented),
- // or 200 (tunnel established).
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 404 Not Found\r\n"),
- MockRead("Content-Length: 10\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_UNEXPECTED),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- TestCompletionCallback callback1;
- int rv = trans->Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
- // Empty the current queue. This is necessary because idle sockets are
- // added to the connection pool asynchronously with a PostTask.
- base::RunLoop().RunUntilIdle();
- // We now check to make sure the TCPClientSocket was not added back to
- // the pool.
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- trans.reset();
- base::RunLoop().RunUntilIdle();
- // Make sure that the socket didn't get recycled after calling the destructor.
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- // Make sure that we recycle a socket after reading all of the response body.
- TEST_F(HttpNetworkTransactionTest, RecycleSocket) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockRead data_reads[] = {
- // A part of the response body is received with the response headers.
- MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nhel"),
- // The rest of the response body is received in two parts.
- MockRead("lo"),
- MockRead(" world"),
- MockRead("junk"), // Should not be read!!
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- std::string status_line = response->headers->GetStatusLine();
- EXPECT_EQ("HTTP/1.1 200 OK", status_line);
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- // Empty the current queue. This is necessary because idle sockets are
- // added to the connection pool asynchronously with a PostTask.
- base::RunLoop().RunUntilIdle();
- // We now check to make sure the socket was added back to the pool.
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- // Make sure that we recycle a SSL socket after reading all of the response
- // body.
- TEST_F(HttpNetworkTransactionTest, RecycleSSLSocket) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 11\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- // Empty the current queue. This is necessary because idle sockets are
- // added to the connection pool asynchronously with a PostTask.
- base::RunLoop().RunUntilIdle();
- // We now check to make sure the socket was added back to the pool.
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- // Grab a SSL socket, use it, and put it back into the pool. Then, reuse it
- // from the pool and make sure that we recover okay.
- TEST_F(HttpNetworkTransactionTest, RecycleDeadSSLSocket) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"), MockRead("Content-Length: 11\r\n\r\n"),
- MockRead("hello world"), MockRead(ASYNC, ERR_CONNECTION_CLOSED)};
- SSLSocketDataProvider ssl(ASYNC, OK);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- StaticSocketDataProvider data(data_reads, data_writes);
- StaticSocketDataProvider data2(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- // Empty the current queue. This is necessary because idle sockets are
- // added to the connection pool asynchronously with a PostTask.
- base::RunLoop().RunUntilIdle();
- // We now check to make sure the socket was added back to the pool.
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- // Now start the second transaction, which should reuse the previous socket.
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- // Empty the current queue. This is necessary because idle sockets are
- // added to the connection pool asynchronously with a PostTask.
- base::RunLoop().RunUntilIdle();
- // We now check to make sure the socket was added back to the pool.
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- TEST_F(HttpNetworkTransactionTest, CloseConnectionOnDestruction) {
- enum class TestCase {
- kReadHeaders,
- kReadPartOfBodyRead,
- kReadAllOfBody,
- };
- for (auto test_case : {TestCase::kReadHeaders, TestCase::kReadPartOfBodyRead,
- TestCase::kReadAllOfBody}) {
- SCOPED_TRACE(testing::Message()
- << "Test case: " << static_cast<int>(test_case));
- for (bool close_connection : {false, true}) {
- if (test_case != TestCase::kReadAllOfBody || close_connection == false)
- continue;
- SCOPED_TRACE(testing::Message()
- << "Close connection: " << close_connection);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://foo.test/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(
- CreateSession(&session_deps_));
- std::unique_ptr<HttpNetworkTransaction> trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
- session.get());
- MockRead data_reads[] = {
- // A part of the response body is received with the response headers.
- MockRead("HTTP/1.1 200 OK\r\n"
- "Content-Length: 11\r\n\r\n"
- "hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- std::string status_line = response->headers->GetStatusLine();
- EXPECT_EQ("HTTP/1.1 200 OK", status_line);
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- std::string response_data;
- switch (test_case) {
- case TestCase::kReadHeaders: {
- // Already read the headers, nothing else to do.
- break;
- }
- case TestCase::kReadPartOfBodyRead: {
- scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(5);
- rv = trans->Read(buf.get(), 5, callback.callback());
- ASSERT_EQ(5, callback.GetResult(rv));
- response_data.assign(buf->data(), 5);
- EXPECT_EQ("hello", response_data);
- break;
- }
- case TestCase::kReadAllOfBody: {
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- break;
- }
- }
- if (close_connection)
- trans->CloseConnectionOnDestruction();
- trans.reset();
- // Wait for the socket to be drained and added to the socket pool or
- // destroyed.
- base::RunLoop().RunUntilIdle();
- // In the case all the body was read, the socket will have been released
- // before the CloseConnectionOnDestruction() call, so will not be
- // destroyed.
- if (close_connection && test_case != TestCase::kReadAllOfBody) {
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- } else {
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- }
- }
- }
- // Grab a socket, use it, and put it back into the pool. Then, make
- // low memory notification and ensure the socket pool is flushed.
- TEST_F(HttpNetworkTransactionTest, FlushSocketPoolOnLowMemoryNotifications) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.load_flags = 0;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockRead data_reads[] = {
- // A part of the response body is received with the response headers.
- MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nhel"),
- // The rest of the response body is received in two parts.
- MockRead("lo"), MockRead(" world"),
- MockRead("junk"), // Should not be read!!
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- std::string status_line = response->headers->GetStatusLine();
- EXPECT_EQ("HTTP/1.1 200 OK", status_line);
- // Make memory critical notification and ensure the transaction still has been
- // operating right.
- base::MemoryPressureListener::NotifyMemoryPressure(
- base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
- base::RunLoop().RunUntilIdle();
- // Socket should not be flushed as long as it is not idle.
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- // Empty the current queue. This is necessary because idle sockets are
- // added to the connection pool asynchronously with a PostTask.
- base::RunLoop().RunUntilIdle();
- // We now check to make sure the socket was added back to the pool.
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- // Idle sockets should be flushed now.
- base::MemoryPressureListener::NotifyMemoryPressure(
- base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- // Disable idle socket closing on memory pressure.
- // Grab a socket, use it, and put it back into the pool. Then, make
- // low memory notification and ensure the socket pool is NOT flushed.
- TEST_F(HttpNetworkTransactionTest, NoFlushSocketPoolOnLowMemoryNotifications) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.load_flags = 0;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Disable idle socket closing on memory pressure.
- session_deps_.disable_idle_sockets_close_on_memory_pressure = true;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockRead data_reads[] = {
- // A part of the response body is received with the response headers.
- MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nhel"),
- // The rest of the response body is received in two parts.
- MockRead("lo"), MockRead(" world"),
- MockRead("junk"), // Should not be read!!
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- std::string status_line = response->headers->GetStatusLine();
- EXPECT_EQ("HTTP/1.1 200 OK", status_line);
- // Make memory critical notification and ensure the transaction still has been
- // operating right.
- base::MemoryPressureListener::NotifyMemoryPressure(
- base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
- base::RunLoop().RunUntilIdle();
- // Socket should not be flushed as long as it is not idle.
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- // Empty the current queue. This is necessary because idle sockets are
- // added to the connection pool asynchronously with a PostTask.
- base::RunLoop().RunUntilIdle();
- // We now check to make sure the socket was added back to the pool.
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- // Idle sockets should NOT be flushed on moderate memory pressure.
- base::MemoryPressureListener::NotifyMemoryPressure(
- base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- // Idle sockets should NOT be flushed on critical memory pressure.
- base::MemoryPressureListener::NotifyMemoryPressure(
- base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- // Grab an SSL socket, use it, and put it back into the pool. Then, make
- // low memory notification and ensure the socket pool is flushed.
- TEST_F(HttpNetworkTransactionTest, FlushSSLSocketPoolOnLowMemoryNotifications) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.load_flags = 0;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"), MockRead("Content-Length: 11\r\n\r\n"),
- MockRead("hello world"), MockRead(ASYNC, ERR_CONNECTION_CLOSED)};
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- // Make memory critical notification and ensure the transaction still has been
- // operating right.
- base::MemoryPressureListener::NotifyMemoryPressure(
- base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- // Empty the current queue. This is necessary because idle sockets are
- // added to the connection pool asynchronously with a PostTask.
- base::RunLoop().RunUntilIdle();
- // We now check to make sure the socket was added back to the pool.
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- // Make memory notification once again and ensure idle socket is closed.
- base::MemoryPressureListener::NotifyMemoryPressure(
- base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
- base::RunLoop().RunUntilIdle();
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- // Make sure that we recycle a socket after a zero-length response.
- // http://crbug.com/9880
- TEST_F(HttpNetworkTransactionTest, RecycleSocketAfterZeroContentLength) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL(
- "http://www.example.org/csi?v=3&s=web&action=&"
- "tran=undefined&ei=mAXcSeegAo-SMurloeUN&"
- "e=17259,18167,19592,19773,19981,20133,20173,20233&"
- "rt=prt.2642,ol.2649,xjs.2951");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 204 No Content\r\n"
- "Content-Length: 0\r\n"
- "Content-Type: text/html\r\n\r\n"),
- MockRead("junk"), // Should not be read!!
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- // Transaction must be created after the MockReads, so it's destroyed before
- // them.
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- std::string status_line = response->headers->GetStatusLine();
- EXPECT_EQ("HTTP/1.1 204 No Content", status_line);
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("", response_data);
- // Empty the current queue. This is necessary because idle sockets are
- // added to the connection pool asynchronously with a PostTask.
- base::RunLoop().RunUntilIdle();
- // We now check to make sure the socket was added back to the pool.
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- TEST_F(HttpNetworkTransactionTest, ResendRequestOnWriteBodyError) {
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(
- std::make_unique<UploadBytesElementReader>("foo", 3));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request[2];
- // Transaction 1: a GET request that succeeds. The socket is recycled
- // after use.
- request[0].method = "GET";
- request[0].url = GURL("http://www.google.com/");
- request[0].load_flags = 0;
- request[0].traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Transaction 2: a POST request. Reuses the socket kept alive from
- // transaction 1. The first attempts fails when writing the POST data.
- // This causes the transaction to retry with a new socket. The second
- // attempt succeeds.
- request[1].method = "POST";
- request[1].url = GURL("http://www.google.com/login.cgi");
- request[1].upload_data_stream = &upload_data_stream;
- request[1].load_flags = 0;
- request[1].traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // The first socket is used for transaction 1 and the first attempt of
- // transaction 2.
- // The response of transaction 1.
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- // The mock write results of transaction 1 and the first attempt of
- // transaction 2.
- MockWrite data_writes1[] = {
- MockWrite(SYNCHRONOUS, 64), // GET
- MockWrite(SYNCHRONOUS, 93), // POST
- MockWrite(SYNCHRONOUS, ERR_CONNECTION_ABORTED), // POST data
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- // The second socket is used for the second attempt of transaction 2.
- // The response of transaction 2.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 OK\r\nContent-Length: 7\r\n\r\n"),
- MockRead("welcome"),
- MockRead(SYNCHRONOUS, OK),
- };
- // The mock write results of the second attempt of transaction 2.
- MockWrite data_writes2[] = {
- MockWrite(SYNCHRONOUS, 93), // POST
- MockWrite(SYNCHRONOUS, 3), // POST data
- };
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- const char* const kExpectedResponseData[] = {
- "hello world", "welcome"
- };
- for (int i = 0; i < 2; ++i) {
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request[i], callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ(kExpectedResponseData[i], response_data);
- }
- }
- // Test the request-challenge-retry sequence for basic auth when there is
- // an identity in the URL. The request should be sent as normal, but when
- // it fails the identity from the URL is used to answer the challenge.
- TEST_F(HttpNetworkTransactionTest, AuthIdentityInURL) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://foo:b@r@www.example.org/");
- request.load_flags = LOAD_NORMAL;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // The password contains an escaped character -- for this test to pass it
- // will need to be unescaped by HttpNetworkTransaction.
- EXPECT_EQ("b%40r", request.url.password());
- MockWrite data_writes1[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Length: 10\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- // After the challenge above, the transaction will be restarted using the
- // identity from the url (foo, b@r) to answer the challenge.
- MockWrite data_writes2[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJAcg==\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans.IsReadyToRestartForAuth());
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- // There is no challenge info, since the identity in URL worked.
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(100, response->headers->GetContentLength());
- // Empty the current queue.
- base::RunLoop().RunUntilIdle();
- }
- // Test the request-challenge-retry sequence for basic auth when there is an
- // incorrect identity in the URL. The identity from the URL should be used only
- // once.
- TEST_F(HttpNetworkTransactionTest, WrongAuthIdentityInURL) {
- HttpRequestInfo request;
- request.method = "GET";
- // Note: the URL has a username:password in it. The password "baz" is
- // wrong (should be "bar").
- request.url = GURL("http://foo:baz@www.example.org/");
- request.load_flags = LOAD_NORMAL;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes1[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Length: 10\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- // After the challenge above, the transaction will be restarted using the
- // identity from the url (foo, baz) to answer the challenge.
- MockWrite data_writes2[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJheg==\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Length: 10\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- // After the challenge above, the transaction will be restarted using the
- // identity supplied by the user (foo, bar) to answer the challenge.
- MockWrite data_writes3[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- MockRead data_reads3[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- StaticSocketDataProvider data3(data_reads3, data_writes3);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- session_deps_.socket_factory->AddSocketDataProvider(&data3);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans.IsReadyToRestartForAuth());
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge));
- TestCompletionCallback callback3;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback3.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback3.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- // There is no challenge info, since the identity worked.
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(100, response->headers->GetContentLength());
- // Empty the current queue.
- base::RunLoop().RunUntilIdle();
- }
- // Test the request-challenge-retry sequence for basic auth when there is a
- // correct identity in the URL, but its use is being suppressed. The identity
- // from the URL should never be used.
- TEST_F(HttpNetworkTransactionTest, AuthIdentityInURLSuppressed) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://foo:bar@www.example.org/");
- request.load_flags = LOAD_DO_NOT_USE_EMBEDDED_IDENTITY;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes1[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Length: 10\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- // After the challenge above, the transaction will be restarted using the
- // identity supplied by the user, not the one in the URL, to answer the
- // challenge.
- MockWrite data_writes3[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- MockRead data_reads3[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data3(data_reads3, data_writes3);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data3);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge));
- TestCompletionCallback callback3;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback3.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback3.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- // There is no challenge info, since the identity worked.
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(100, response->headers->GetContentLength());
- // Empty the current queue.
- base::RunLoop().RunUntilIdle();
- }
- // Test that previously tried username/passwords for a realm get re-used.
- TEST_F(HttpNetworkTransactionTest, BasicAuthCacheAndPreauth) {
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Transaction 1: authenticate (foo, bar) on MyRealm1
- {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/x/y/z");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes1[] = {
- MockWrite(
- "GET /x/y/z HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Length: 10000\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- // Resend with authorization (username=foo, password=bar)
- MockWrite data_writes2[] = {
- MockWrite(
- "GET /x/y/z HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- // Sever accepts the authorization.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar),
- callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(100, response->headers->GetContentLength());
- }
- // ------------------------------------------------------------------------
- // Transaction 2: authenticate (foo2, bar2) on MyRealm2
- {
- HttpRequestInfo request;
- request.method = "GET";
- // Note that Transaction 1 was at /x/y/z, so this is in the same
- // protection space as MyRealm1.
- request.url = GURL("http://www.example.org/x/y/a/b");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes1[] = {
- MockWrite(
- "GET /x/y/a/b HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- // Send preemptive authorization for MyRealm1
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- // The server didn't like the preemptive authorization, and
- // challenges us for a different realm (MyRealm2).
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm2\"\r\n"),
- MockRead("Content-Length: 10000\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- // Resend with authorization for MyRealm2 (username=foo2, password=bar2)
- MockWrite data_writes2[] = {
- MockWrite(
- "GET /x/y/a/b HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vMjpiYXIy\r\n\r\n"),
- };
- // Sever accepts the authorization.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->auth_challenge);
- EXPECT_FALSE(response->auth_challenge->is_proxy);
- EXPECT_EQ("http://www.example.org",
- response->auth_challenge->challenger.Serialize());
- EXPECT_EQ("MyRealm2", response->auth_challenge->realm);
- EXPECT_EQ(kBasicAuthScheme, response->auth_challenge->scheme);
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo2, kBar2),
- callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(100, response->headers->GetContentLength());
- }
- // ------------------------------------------------------------------------
- // Transaction 3: Resend a request in MyRealm's protection space --
- // succeed with preemptive authorization.
- {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/x/y/z2");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes1[] = {
- MockWrite(
- "GET /x/y/z2 HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- // The authorization for MyRealm1 gets sent preemptively
- // (since the url is in the same protection space)
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- // Sever accepts the preemptive authorization
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(100, response->headers->GetContentLength());
- }
- // ------------------------------------------------------------------------
- // Transaction 4: request another URL in MyRealm (however the
- // url is not known to belong to the protection space, so no pre-auth).
- {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/x/1");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes1[] = {
- MockWrite(
- "GET /x/1 HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Length: 10000\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- // Resend with authorization from MyRealm's cache.
- MockWrite data_writes2[] = {
- MockWrite(
- "GET /x/1 HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- // Sever accepts the authorization.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans.IsReadyToRestartForAuth());
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(100, response->headers->GetContentLength());
- }
- // ------------------------------------------------------------------------
- // Transaction 5: request a URL in MyRealm, but the server rejects the
- // cached identity. Should invalidate and re-prompt.
- {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/p/q/t");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes1[] = {
- MockWrite(
- "GET /p/q/t HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Length: 10000\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- // Resend with authorization from cache for MyRealm.
- MockWrite data_writes2[] = {
- MockWrite(
- "GET /p/q/t HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- // Sever rejects the authorization.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Length: 10000\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- // At this point we should prompt for new credentials for MyRealm.
- // Restart with username=foo3, password=foo4.
- MockWrite data_writes3[] = {
- MockWrite(
- "GET /p/q/t HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vMzpiYXIz\r\n\r\n"),
- };
- // Sever accepts the authorization.
- MockRead data_reads3[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- StaticSocketDataProvider data3(data_reads3, data_writes3);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- session_deps_.socket_factory->AddSocketDataProvider(&data3);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(trans.IsReadyToRestartForAuth());
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge));
- TestCompletionCallback callback3;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo3, kBar3),
- callback3.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback3.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(100, response->headers->GetContentLength());
- }
- }
- // Tests that nonce count increments when multiple auth attempts
- // are started with the same nonce.
- TEST_F(HttpNetworkTransactionTest, DigestPreAuthNonceCount) {
- auto digest_factory = std::make_unique<HttpAuthHandlerDigest::Factory>();
- auto nonce_generator =
- std::make_unique<HttpAuthHandlerDigest::FixedNonceGenerator>(
- "0123456789abcdef");
- digest_factory->set_nonce_generator(std::move(nonce_generator));
- session_deps_.http_auth_handler_factory = std::move(digest_factory);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Transaction 1: authenticate (foo, bar) on MyRealm1
- {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/x/y/z");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes1[] = {
- MockWrite(
- "GET /x/y/z HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Digest realm=\"digestive\", nonce=\"OU812\", "
- "algorithm=MD5, qop=\"auth\"\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- // Resend with authorization (username=foo, password=bar)
- MockWrite data_writes2[] = {
- MockWrite(
- "GET /x/y/z HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Digest username=\"foo\", realm=\"digestive\", "
- "nonce=\"OU812\", uri=\"/x/y/z\", algorithm=MD5, "
- "response=\"03ffbcd30add722589c1de345d7a927f\", qop=auth, "
- "nc=00000001, cnonce=\"0123456789abcdef\"\r\n\r\n"),
- };
- // Sever accepts the authorization.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckDigestServerAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar),
- callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- }
- // ------------------------------------------------------------------------
- // Transaction 2: Request another resource in digestive's protection space.
- // This will preemptively add an Authorization header which should have an
- // "nc" value of 2 (as compared to 1 in the first use.
- {
- HttpRequestInfo request;
- request.method = "GET";
- // Note that Transaction 1 was at /x/y/z, so this is in the same
- // protection space as digest.
- request.url = GURL("http://www.example.org/x/y/a/b");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes1[] = {
- MockWrite(
- "GET /x/y/a/b HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Digest username=\"foo\", realm=\"digestive\", "
- "nonce=\"OU812\", uri=\"/x/y/a/b\", algorithm=MD5, "
- "response=\"d6f9a2c07d1c5df7b89379dca1269b35\", qop=auth, "
- "nc=00000002, cnonce=\"0123456789abcdef\"\r\n\r\n"),
- };
- // Sever accepts the authorization.
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- }
- }
- // Test the ResetStateForRestart() private method.
- TEST_F(HttpNetworkTransactionTest, ResetStateForRestart) {
- // Create a transaction (the dependencies aren't important).
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Setup some state (which we expect ResetStateForRestart() will clear).
- trans.read_buf_ = base::MakeRefCounted<IOBuffer>(15);
- trans.read_buf_len_ = 15;
- trans.request_headers_.SetHeader("Authorization", "NTLM");
- // Setup state in response_
- HttpResponseInfo* response = &trans.response_;
- response->auth_challenge = absl::nullopt;
- response->ssl_info.cert_status = static_cast<CertStatus>(-1); // Nonsensical.
- response->response_time = base::Time::Now();
- response->was_cached = true; // (Wouldn't ever actually be true...)
- // Cause the above state to be reset.
- trans.ResetStateForRestart();
- // Verify that the state that needed to be reset, has been reset.
- EXPECT_FALSE(trans.read_buf_);
- EXPECT_EQ(0, trans.read_buf_len_);
- EXPECT_TRUE(trans.request_headers_.IsEmpty());
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_FALSE(response->headers);
- EXPECT_FALSE(response->was_cached);
- EXPECT_EQ(0U, response->ssl_info.cert_status);
- }
- // Test HTTPS connections to a site with a bad certificate
- TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificate) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider ssl_bad_certificate;
- StaticSocketDataProvider data(data_reads, data_writes);
- SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSocketDataProvider(&ssl_bad_certificate);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_bad);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_CERT_AUTHORITY_INVALID));
- rv = trans.RestartIgnoringLastError(callback.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(100, response->headers->GetContentLength());
- }
- // Test HTTPS connections to a site with a bad certificate, going through a
- // proxy
- TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaProxy) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite proxy_writes[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockRead proxy_reads[] = {
- MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK)
- };
- MockWrite data_writes[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider ssl_bad_certificate(proxy_reads, proxy_writes);
- StaticSocketDataProvider data(data_reads, data_writes);
- SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSocketDataProvider(&ssl_bad_certificate);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_bad);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback;
- for (int i = 0; i < 2; i++) {
- session_deps_.socket_factory->ResetNextMockIndexes();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_CERT_AUTHORITY_INVALID));
- rv = trans.RestartIgnoringLastError(callback.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(100, response->headers->GetContentLength());
- }
- }
- // Test HTTPS connections to a site, going through an HTTPS proxy
- TEST_F(HttpNetworkTransactionTest, HTTPSViaHttpsProxy) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "HTTPS proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy
- SSLSocketDataProvider tunnel_ssl(ASYNC, OK); // SSL through the tunnel
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&tunnel_ssl);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->proxy_server.is_https());
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(100, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_SSL_TIMES);
- }
- // Test that an HTTPS Proxy cannot redirect a CONNECT request for main frames.
- TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaHttpsProxy) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "HTTPS proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- const base::TimeDelta kTimeIncrement = base::Seconds(4);
- session_deps_.host_resolver->set_ondemand_mode(true);
- HttpRequestInfo request;
- request.load_flags = LOAD_MAIN_FRAME_DEPRECATED;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite(ASYNC, 0,
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- // Pause on first read.
- MockRead(ASYNC, ERR_IO_PENDING, 1),
- MockRead(ASYNC, 2, "HTTP/1.1 302 Redirect\r\n"),
- MockRead(ASYNC, 3, "Location: http://login.example.com/\r\n"),
- MockRead(ASYNC, 4, "Content-Length: 0\r\n\r\n"),
- };
- SequencedSocketData data(MockConnect(ASYNC, OK), data_reads, data_writes);
- SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_TRUE(session_deps_.host_resolver->has_pending_requests());
- // Host resolution takes |kTimeIncrement|.
- FastForwardBy(kTimeIncrement);
- // Resolving the current request with |ResolveNow| will cause the pending
- // request to instantly complete, and the async connect will start as well.
- session_deps_.host_resolver->ResolveOnlyRequestNow();
- // Connecting takes |kTimeIncrement|.
- FastForwardBy(kTimeIncrement);
- data.RunUntilPaused();
- // The server takes |kTimeIncrement| to respond.
- FastForwardBy(kTimeIncrement);
- data.Resume();
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
- }
- // Test that an HTTPS Proxy cannot redirect a CONNECT request for subresources.
- TEST_F(HttpNetworkTransactionTest,
- RedirectOfHttpsConnectSubresourceViaHttpsProxy) {
- base::HistogramTester histograms;
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "HTTPS proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite(ASYNC, 0,
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead(ASYNC, 1, "HTTP/1.1 302 Redirect\r\n"),
- MockRead(ASYNC, 2, "Location: http://login.example.com/\r\n"),
- MockRead(ASYNC, 3, "Content-Length: 0\r\n\r\n"),
- };
- SequencedSocketData data(MockConnect(ASYNC, OK), data_reads, data_writes);
- SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
- }
- // Test that an HTTPS Proxy which was auto-detected cannot redirect a CONNECT
- // request for main frames.
- TEST_F(HttpNetworkTransactionTest,
- RedirectOfHttpsConnectViaAutoDetectedHttpsProxy) {
- base::HistogramTester histograms;
- session_deps_.proxy_resolution_service = ConfiguredProxyResolutionService::
- CreateFixedFromAutoDetectedPacResultForTest("HTTPS proxy:70",
- TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- HttpRequestInfo request;
- request.load_flags = LOAD_MAIN_FRAME_DEPRECATED;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite(ASYNC, 0,
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead(ASYNC, 1, "HTTP/1.1 302 Redirect\r\n"),
- MockRead(ASYNC, 2, "Location: http://login.example.com/\r\n"),
- MockRead(ASYNC, 3, "Content-Length: 0\r\n\r\n"),
- };
- SequencedSocketData data(MockConnect(ASYNC, OK), data_reads, data_writes);
- SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
- }
- // Tests that an HTTPS (SPDY) Proxy's cannot redirect a CONNECT request for main
- // frames.
- TEST_F(HttpNetworkTransactionTest, RedirectOfHttpsConnectViaSpdyProxy) {
- base::HistogramTester histograms;
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- const base::TimeDelta kTimeIncrement = base::Seconds(4);
- session_deps_.host_resolver->set_ondemand_mode(true);
- HttpRequestInfo request;
- request.method = "GET";
- request.load_flags = LOAD_MAIN_FRAME_DEPRECATED;
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- spdy::SpdySerializedFrame conn(spdy_util_.ConstructSpdyConnect(
- nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
- HostPortPair("www.example.org", 443)));
- spdy::SpdySerializedFrame goaway(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite data_writes[] = {
- CreateMockWrite(conn, 0, SYNCHRONOUS),
- CreateMockWrite(goaway, 3, SYNCHRONOUS),
- };
- static const char* const kExtraHeaders[] = {
- "location",
- "http://login.example.com/",
- };
- spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyReplyError(
- "302", kExtraHeaders, std::size(kExtraHeaders) / 2, 1));
- MockRead data_reads[] = {
- // Pause on first read.
- MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(resp, 2),
- MockRead(ASYNC, 0, 4), // EOF
- };
- SequencedSocketData data(MockConnect(ASYNC, OK), data_reads, data_writes);
- SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy
- proxy_ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_TRUE(session_deps_.host_resolver->has_pending_requests());
- // Host resolution takes |kTimeIncrement|.
- FastForwardBy(kTimeIncrement);
- // Resolving the current request with |ResolveNow| will cause the pending
- // request to instantly complete, and the async connect will start as well.
- session_deps_.host_resolver->ResolveOnlyRequestNow();
- // Connecting takes |kTimeIncrement|.
- FastForwardBy(kTimeIncrement);
- data.RunUntilPaused();
- FastForwardBy(kTimeIncrement);
- data.Resume();
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
- }
- // Test that an HTTPS proxy's response to a CONNECT request is filtered.
- TEST_F(HttpNetworkTransactionTest, ErrorResponseToHttpsConnectViaHttpsProxy) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 404 Not Found\r\n"),
- MockRead("Content-Length: 23\r\n\r\n"),
- MockRead("The host does not exist"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
- // TODO(juliatuttle): Anything else to check here?
- }
- // Test that a SPDY proxy's response to a CONNECT request is filtered.
- TEST_F(HttpNetworkTransactionTest, ErrorResponseToHttpsConnectViaSpdyProxy) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- spdy::SpdySerializedFrame conn(spdy_util_.ConstructSpdyConnect(
- nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
- HostPortPair("www.example.org", 443)));
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- MockWrite data_writes[] = {
- CreateMockWrite(conn, 0), CreateMockWrite(rst, 3),
- };
- static const char* const kExtraHeaders[] = {
- "location",
- "http://login.example.com/",
- };
- spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyReplyError(
- "404", kExtraHeaders, std::size(kExtraHeaders) / 2, 1));
- spdy::SpdySerializedFrame body(
- spdy_util_.ConstructSpdyDataFrame(1, "The host does not exist", true));
- MockRead data_reads[] = {
- CreateMockRead(resp, 1), CreateMockRead(body, 2),
- MockRead(ASYNC, 0, 4), // EOF
- };
- SequencedSocketData data(data_reads, data_writes);
- SSLSocketDataProvider proxy_ssl(ASYNC, OK); // SSL to the proxy
- proxy_ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy_ssl);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
- // TODO(juliatuttle): Anything else to check here?
- }
- // Test the request-challenge-retry sequence for basic auth, through
- // a SPDY proxy over a single SPDY session.
- TEST_F(HttpNetworkTransactionTest, BasicAuthSpdyProxy) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- // when the no authentication data flag is set.
- request.privacy_mode = PRIVACY_MODE_ENABLED;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against https proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- RecordingNetLogObserver net_log_observer;
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since we have proxy, should try to establish tunnel.
- spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
- nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
- HostPortPair("www.example.org", 443)));
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
- spdy_util_.UpdateWithStreamDestruction(1);
- // After calling trans.RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- const char* const kAuthCredentials[] = {
- "proxy-authorization", "Basic Zm9vOmJhcg==",
- };
- spdy::SpdySerializedFrame connect2(spdy_util_.ConstructSpdyConnect(
- kAuthCredentials, std::size(kAuthCredentials) / 2, 3,
- HttpProxyConnectJob::kH2QuicTunnelPriority,
- HostPortPair("www.example.org", 443)));
- // fetch https://www.example.org/ via HTTP
- const char get[] =
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n";
- spdy::SpdySerializedFrame wrapped_get(
- spdy_util_.ConstructSpdyDataFrame(3, get, false));
- MockWrite spdy_writes[] = {
- CreateMockWrite(req, 0, ASYNC), CreateMockWrite(rst, 2, ASYNC),
- CreateMockWrite(connect2, 3), CreateMockWrite(wrapped_get, 5),
- };
- // The proxy responds to the connect with a 407, using a persistent
- // connection.
- const char kAuthStatus[] = "407";
- const char* const kAuthChallenge[] = {
- "proxy-authenticate", "Basic realm=\"MyRealm1\"",
- };
- spdy::SpdySerializedFrame conn_auth_resp(spdy_util_.ConstructSpdyReplyError(
- kAuthStatus, kAuthChallenge, std::size(kAuthChallenge) / 2, 1));
- spdy::SpdySerializedFrame conn_resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
- const char resp[] = "HTTP/1.1 200 OK\r\n"
- "Content-Length: 5\r\n\r\n";
- spdy::SpdySerializedFrame wrapped_get_resp(
- spdy_util_.ConstructSpdyDataFrame(3, resp, false));
- spdy::SpdySerializedFrame wrapped_body(
- spdy_util_.ConstructSpdyDataFrame(3, "hello", false));
- MockRead spdy_reads[] = {
- CreateMockRead(conn_auth_resp, 1, ASYNC),
- CreateMockRead(conn_resp, 4, ASYNC),
- CreateMockRead(wrapped_get_resp, 6, ASYNC),
- CreateMockRead(wrapped_body, 7, ASYNC),
- MockRead(ASYNC, OK, 8), // EOF. May or may not be read.
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- // Negotiate SPDY to the proxy
- SSLSocketDataProvider proxy(ASYNC, OK);
- proxy.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&proxy);
- // Vanilla SSL to the server
- SSLSocketDataProvider server(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&server);
- TestCompletionCallback callback1;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- auto entries = net_log_observer.GetEntries();
- size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLogEventPhase::NONE);
- ExpectLogContainsSomewhere(
- entries, pos,
- NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLogEventPhase::NONE);
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(response->auth_challenge.has_value());
- EXPECT_TRUE(CheckBasicSecureProxyAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar),
- callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(5, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- // The password prompt info should not be set.
- EXPECT_FALSE(response->auth_challenge.has_value());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_SSL_TIMES);
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Test HTTPS connections to a site with a bad certificate, going through an
- // HTTPS proxy
- TEST_F(HttpNetworkTransactionTest, HTTPSBadCertificateViaHttpsProxy) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Attempt to fetch the URL from a server with a bad cert
- MockWrite bad_cert_writes[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockRead bad_cert_reads[] = {
- MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK)
- };
- // Attempt to fetch the URL with a good cert
- MockWrite good_data_writes[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead good_cert_reads[] = {
- MockRead("HTTP/1.0 200 Connected\r\n\r\n"),
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider ssl_bad_certificate(bad_cert_reads, bad_cert_writes);
- StaticSocketDataProvider data(good_cert_reads, good_data_writes);
- SSLSocketDataProvider ssl_bad(ASYNC, ERR_CERT_AUTHORITY_INVALID);
- SSLSocketDataProvider ssl(ASYNC, OK);
- // SSL to the proxy, then CONNECT request, then SSL with bad certificate
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- session_deps_.socket_factory->AddSocketDataProvider(&ssl_bad_certificate);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_bad);
- // SSL to the proxy, then CONNECT request, then valid SSL certificate
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_CERT_AUTHORITY_INVALID));
- rv = trans.RestartIgnoringLastError(callback.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(100, response->headers->GetContentLength());
- }
- TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgent) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
- "Chromium Ultra Awesome X Edition");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "User-Agent: Chromium Ultra Awesome X Edition\r\n\r\n"),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- }
- TEST_F(HttpNetworkTransactionTest, BuildRequest_UserAgentOverTunnel) {
- // Test user agent values, used both for the request header of the original
- // request, and the value returned by the HttpUserAgentSettings. nullptr means
- // no request header / no HttpUserAgentSettings object.
- const char* kTestUserAgents[] = {nullptr, "", "Foopy"};
- for (const char* setting_user_agent : kTestUserAgents) {
- if (!setting_user_agent) {
- session_deps_.http_user_agent_settings.reset();
- } else {
- session_deps_.http_user_agent_settings =
- std::make_unique<StaticHttpUserAgentSettings>(
- std::string() /* accept-language */, setting_user_agent);
- }
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- for (const char* request_user_agent : kTestUserAgents) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- if (request_user_agent) {
- request.extra_headers.SetHeader(HttpRequestHeaders::kUserAgent,
- request_user_agent);
- }
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- std::string expected_request;
- if (!setting_user_agent || strlen(setting_user_agent) == 0) {
- expected_request =
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n";
- } else {
- expected_request = base::StringPrintf(
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "User-Agent: %s\r\n\r\n",
- setting_user_agent);
- }
- MockWrite data_writes[] = {
- MockWrite(expected_request.c_str()),
- };
- MockRead data_reads[] = {
- // Return an error, so the transaction stops here (this test isn't
- // interested in the rest).
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Proxy-Connection: close\r\n\r\n"),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- }
- }
- }
- TEST_F(HttpNetworkTransactionTest, BuildRequest_Referer) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.extra_headers.SetHeader(HttpRequestHeaders::kReferer,
- "http://the.previous.site.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Referer: http://the.previous.site.com/\r\n\r\n"),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- }
- TEST_F(HttpNetworkTransactionTest, BuildRequest_PostContentLengthZero) {
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite(
- "POST / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 0\r\n\r\n"),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- }
- TEST_F(HttpNetworkTransactionTest, BuildRequest_PutContentLengthZero) {
- HttpRequestInfo request;
- request.method = "PUT";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite(
- "PUT / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 0\r\n\r\n"),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- }
- TEST_F(HttpNetworkTransactionTest, BuildRequest_HeadContentLengthZero) {
- HttpRequestInfo request;
- request.method = "HEAD";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite("HEAD / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- }
- TEST_F(HttpNetworkTransactionTest, BuildRequest_CacheControlNoCache) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.load_flags = LOAD_BYPASS_CACHE;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Pragma: no-cache\r\n"
- "Cache-Control: no-cache\r\n\r\n"),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- }
- TEST_F(HttpNetworkTransactionTest, BuildRequest_CacheControlValidateCache) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.load_flags = LOAD_VALIDATE_CACHE;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Cache-Control: max-age=0\r\n\r\n"),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- }
- TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeaders) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.extra_headers.SetHeader("FooHeader", "Bar");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "FooHeader: Bar\r\n\r\n"),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- }
- TEST_F(HttpNetworkTransactionTest, BuildRequest_ExtraHeadersStripped) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.extra_headers.SetHeader("referer", "www.foo.com");
- request.extra_headers.SetHeader("hEllo", "Kitty");
- request.extra_headers.SetHeader("FoO", "bar");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "referer: www.foo.com\r\n"
- "hEllo: Kitty\r\n"
- "FoO: bar\r\n\r\n"),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- }
- TEST_F(HttpNetworkTransactionTest, SOCKS4_HTTP_GET) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "SOCKS myproxy:1080", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 };
- char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
- MockWrite data_writes[] = {
- MockWrite(ASYNC, write_buffer, std::size(write_buffer)),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n")};
- MockRead data_reads[] = {
- MockRead(ASYNC, read_buffer, std::size(read_buffer)),
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
- MockRead("Payload"), MockRead(SYNCHRONOUS, OK)};
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(ProxyServer::SCHEME_SOCKS4, response->proxy_server.scheme());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- std::string response_text;
- rv = ReadTransaction(&trans, &response_text);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("Payload", response_text);
- }
- TEST_F(HttpNetworkTransactionTest, SOCKS4_SSL_GET) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "SOCKS myproxy:1080", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- unsigned char write_buffer[] = { 0x04, 0x01, 0x01, 0xBB, 127, 0, 0, 1, 0 };
- unsigned char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
- MockWrite data_writes[] = {
- MockWrite(ASYNC, reinterpret_cast<char*>(write_buffer),
- std::size(write_buffer)),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n")};
- MockRead data_reads[] = {
- MockRead(ASYNC, reinterpret_cast<char*>(read_buffer),
- std::size(read_buffer)),
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
- MockRead("Payload"), MockRead(SYNCHRONOUS, OK)};
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_SSL_TIMES);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(ProxyServer::SCHEME_SOCKS4, response->proxy_server.scheme());
- std::string response_text;
- rv = ReadTransaction(&trans, &response_text);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("Payload", response_text);
- }
- TEST_F(HttpNetworkTransactionTest, SOCKS4_HTTP_GET_no_PAC) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "socks4://myproxy:1080", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- char write_buffer[] = { 0x04, 0x01, 0x00, 0x50, 127, 0, 0, 1, 0 };
- char read_buffer[] = { 0x00, 0x5A, 0x00, 0x00, 0, 0, 0, 0 };
- MockWrite data_writes[] = {
- MockWrite(ASYNC, write_buffer, std::size(write_buffer)),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n")};
- MockRead data_reads[] = {
- MockRead(ASYNC, read_buffer, std::size(read_buffer)),
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
- MockRead("Payload"), MockRead(SYNCHRONOUS, OK)};
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReused(load_timing_info,
- CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- std::string response_text;
- rv = ReadTransaction(&trans, &response_text);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("Payload", response_text);
- }
- TEST_F(HttpNetworkTransactionTest, SOCKS5_HTTP_GET) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "SOCKS5 myproxy:1080", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- const char kSOCKS5ExampleOkRequest[] = {
- 0x05, // Version
- 0x01, // Command (CONNECT)
- 0x00, // Reserved.
- 0x03, // Address type (DOMAINNAME).
- 0x0F, // Length of domain (15)
- 'w', 'w', 'w', '.', 'e', 'x',
- 'a', 'm', 'p', 'l', 'e', // Domain string
- '.', 'o', 'r', 'g', 0x00, 0x50, // 16-bit port (80)
- };
- MockWrite data_writes[] = {
- MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
- MockWrite(ASYNC, kSOCKS5ExampleOkRequest,
- std::size(kSOCKS5ExampleOkRequest)),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n")};
- MockRead data_reads[] = {
- MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
- MockRead(ASYNC, kSOCKS5OkResponse, kSOCKS5OkResponseLength),
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
- MockRead("Payload"),
- MockRead(SYNCHRONOUS, OK)};
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(ProxyServer::SCHEME_SOCKS5, response->proxy_server.scheme());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- std::string response_text;
- rv = ReadTransaction(&trans, &response_text);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("Payload", response_text);
- }
- TEST_F(HttpNetworkTransactionTest, SOCKS5_SSL_GET) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "SOCKS5 myproxy:1080", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- const unsigned char kSOCKS5ExampleOkRequest[] = {
- 0x05, // Version
- 0x01, // Command (CONNECT)
- 0x00, // Reserved.
- 0x03, // Address type (DOMAINNAME).
- 0x0F, // Length of domain (15)
- 'w', 'w', 'w', '.', 'e', 'x',
- 'a', 'm', 'p', 'l', 'e', // Domain string
- '.', 'o', 'r', 'g', 0x01, 0xBB, // 16-bit port (443)
- };
- const char kSOCKS5SslOkResponse[] = {0x05, 0x00, 0x00, 0x01, 0,
- 0, 0, 0, 0x00, 0x00};
- MockWrite data_writes[] = {
- MockWrite(ASYNC, kSOCKS5GreetRequest, kSOCKS5GreetRequestLength),
- MockWrite(ASYNC, reinterpret_cast<const char*>(kSOCKS5ExampleOkRequest),
- std::size(kSOCKS5ExampleOkRequest)),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n")};
- MockRead data_reads[] = {
- MockRead(ASYNC, kSOCKS5GreetResponse, kSOCKS5GreetResponseLength),
- MockRead(ASYNC, kSOCKS5SslOkResponse, std::size(kSOCKS5SslOkResponse)),
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n\r\n"),
- MockRead("Payload"),
- MockRead(SYNCHRONOUS, OK)};
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(ProxyServer::SCHEME_SOCKS5, response->proxy_server.scheme());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_SSL_TIMES);
- std::string response_text;
- rv = ReadTransaction(&trans, &response_text);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("Payload", response_text);
- }
- namespace {
- // Tests that for connection endpoints the group ids are correctly set.
- struct GroupIdTest {
- std::string proxy_server;
- std::string url;
- ClientSocketPool::GroupId expected_group_id;
- bool ssl;
- };
- std::unique_ptr<HttpNetworkSession> SetupSessionForGroupIdTests(
- SpdySessionDependencies* session_deps_) {
- std::unique_ptr<HttpNetworkSession> session(CreateSession(session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- AlternativeService alternative_service(kProtoHTTP2, "", 444);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetHttp2AlternativeService(
- url::SchemeHostPort("https", "host.with.alternate", 443),
- NetworkIsolationKey(), alternative_service, expiration);
- return session;
- }
- int GroupIdTransactionHelper(const std::string& url,
- HttpNetworkSession* session) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL(url);
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session);
- TestCompletionCallback callback;
- // We do not complete this request, the dtor will clean the transaction up.
- return trans.Start(&request, callback.callback(), NetLogWithSource());
- }
- } // namespace
- TEST_F(HttpNetworkTransactionTest, GroupIdForDirectConnections) {
- const GroupIdTest tests[] = {
- {
- "", // unused
- "http://www.example.org/direct",
- ClientSocketPool::GroupId(
- url::SchemeHostPort(url::kHttpScheme, "www.example.org", 80),
- PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
- SecureDnsPolicy::kAllow),
- false,
- },
- {
- "", // unused
- "http://[2001:1418:13:1::25]/direct",
- ClientSocketPool::GroupId(
- url::SchemeHostPort(url::kHttpScheme, "[2001:1418:13:1::25]", 80),
- PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
- SecureDnsPolicy::kAllow),
- false,
- },
- // SSL Tests
- {
- "", // unused
- "https://www.example.org/direct_ssl",
- ClientSocketPool::GroupId(
- url::SchemeHostPort(url::kHttpsScheme, "www.example.org", 443),
- PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
- SecureDnsPolicy::kAllow),
- true,
- },
- {
- "", // unused
- "https://[2001:1418:13:1::25]/direct",
- ClientSocketPool::GroupId(
- url::SchemeHostPort(url::kHttpsScheme, "[2001:1418:13:1::25]",
- 443),
- PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
- SecureDnsPolicy::kAllow),
- true,
- },
- {
- "", // unused
- "https://host.with.alternate/direct",
- ClientSocketPool::GroupId(
- url::SchemeHostPort(url::kHttpsScheme, "host.with.alternate",
- 443),
- PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
- SecureDnsPolicy::kAllow),
- true,
- },
- };
- for (const auto& test : tests) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- test.proxy_server, TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(
- SetupSessionForGroupIdTests(&session_deps_));
- HttpNetworkSessionPeer peer(session.get());
- auto transport_conn_pool =
- std::make_unique<CaptureGroupIdTransportSocketPool>(
- &dummy_connect_job_params_);
- auto* transport_conn_pool_ptr = transport_conn_pool.get();
- auto mock_pool_manager = std::make_unique<MockClientSocketPoolManager>();
- mock_pool_manager->SetSocketPool(ProxyServer::Direct(),
- std::move(transport_conn_pool));
- peer.SetClientSocketPoolManager(std::move(mock_pool_manager));
- EXPECT_EQ(ERR_IO_PENDING,
- GroupIdTransactionHelper(test.url, session.get()));
- EXPECT_EQ(test.expected_group_id,
- transport_conn_pool_ptr->last_group_id_received());
- EXPECT_TRUE(transport_conn_pool_ptr->socket_requested());
- }
- }
- TEST_F(HttpNetworkTransactionTest, GroupIdForHTTPProxyConnections) {
- const GroupIdTest tests[] = {
- {
- "http_proxy",
- "http://www.example.org/http_proxy_normal",
- ClientSocketPool::GroupId(
- url::SchemeHostPort(url::kHttpScheme, "www.example.org", 80),
- PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
- SecureDnsPolicy::kAllow),
- false,
- },
- // SSL Tests
- {
- "http_proxy",
- "https://www.example.org/http_connect_ssl",
- ClientSocketPool::GroupId(
- url::SchemeHostPort(url::kHttpsScheme, "www.example.org", 443),
- PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
- SecureDnsPolicy::kAllow),
- true,
- },
- {
- "http_proxy",
- "https://host.with.alternate/direct",
- ClientSocketPool::GroupId(
- url::SchemeHostPort(url::kHttpsScheme, "host.with.alternate",
- 443),
- PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
- SecureDnsPolicy::kAllow),
- true,
- },
- };
- for (const auto& test : tests) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- test.proxy_server, TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(
- SetupSessionForGroupIdTests(&session_deps_));
- HttpNetworkSessionPeer peer(session.get());
- ProxyServer proxy_server(ProxyServer::SCHEME_HTTP,
- HostPortPair("http_proxy", 80));
- auto http_proxy_pool = std::make_unique<CaptureGroupIdTransportSocketPool>(
- &dummy_connect_job_params_);
- auto* http_proxy_pool_ptr = http_proxy_pool.get();
- auto mock_pool_manager = std::make_unique<MockClientSocketPoolManager>();
- mock_pool_manager->SetSocketPool(proxy_server, std::move(http_proxy_pool));
- peer.SetClientSocketPoolManager(std::move(mock_pool_manager));
- EXPECT_EQ(ERR_IO_PENDING,
- GroupIdTransactionHelper(test.url, session.get()));
- EXPECT_EQ(test.expected_group_id,
- http_proxy_pool_ptr->last_group_id_received());
- }
- }
- TEST_F(HttpNetworkTransactionTest, GroupIdForSOCKSConnections) {
- const GroupIdTest tests[] = {
- {
- "socks4://socks_proxy:1080",
- "http://www.example.org/socks4_direct",
- ClientSocketPool::GroupId(
- url::SchemeHostPort(url::kHttpScheme, "www.example.org", 80),
- PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
- SecureDnsPolicy::kAllow),
- false,
- },
- {
- "socks5://socks_proxy:1080",
- "http://www.example.org/socks5_direct",
- ClientSocketPool::GroupId(
- url::SchemeHostPort(url::kHttpScheme, "www.example.org", 80),
- PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
- SecureDnsPolicy::kAllow),
- false,
- },
- // SSL Tests
- {
- "socks4://socks_proxy:1080",
- "https://www.example.org/socks4_ssl",
- ClientSocketPool::GroupId(
- url::SchemeHostPort(url::kHttpsScheme, "www.example.org", 443),
- PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
- SecureDnsPolicy::kAllow),
- true,
- },
- {
- "socks5://socks_proxy:1080",
- "https://www.example.org/socks5_ssl",
- ClientSocketPool::GroupId(
- url::SchemeHostPort(url::kHttpsScheme, "www.example.org", 443),
- PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
- SecureDnsPolicy::kAllow),
- true,
- },
- {
- "socks4://socks_proxy:1080",
- "https://host.with.alternate/direct",
- ClientSocketPool::GroupId(
- url::SchemeHostPort(url::kHttpsScheme, "host.with.alternate",
- 443),
- PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
- SecureDnsPolicy::kAllow),
- true,
- },
- };
- for (const auto& test : tests) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- test.proxy_server, TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(
- SetupSessionForGroupIdTests(&session_deps_));
- HttpNetworkSessionPeer peer(session.get());
- ProxyServer proxy_server(
- ProxyUriToProxyServer(test.proxy_server, ProxyServer::SCHEME_HTTP));
- ASSERT_TRUE(proxy_server.is_valid());
- auto socks_conn_pool = std::make_unique<CaptureGroupIdTransportSocketPool>(
- &dummy_connect_job_params_);
- auto* socks_conn_pool_ptr = socks_conn_pool.get();
- auto mock_pool_manager = std::make_unique<MockClientSocketPoolManager>();
- mock_pool_manager->SetSocketPool(proxy_server, std::move(socks_conn_pool));
- peer.SetClientSocketPoolManager(std::move(mock_pool_manager));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- EXPECT_EQ(ERR_IO_PENDING,
- GroupIdTransactionHelper(test.url, session.get()));
- EXPECT_EQ(test.expected_group_id,
- socks_conn_pool_ptr->last_group_id_received());
- }
- }
- TEST_F(HttpNetworkTransactionTest, ReconsiderProxyAfterFailedConnection) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70;foobar:80", TRAFFIC_ANNOTATION_FOR_TESTS);
- // This simulates failure resolving all hostnames; that means we will fail
- // connecting to both proxies (myproxy:70 and foobar:80).
- session_deps_.host_resolver->rules()->AddSimulatedFailure("*");
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_PROXY_CONNECTION_FAILED));
- }
- // Make sure we can handle an error when writing the request.
- TEST_F(HttpNetworkTransactionTest, RequestWriteError) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.foo.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite write_failure[] = {
- MockWrite(ASYNC, ERR_CONNECTION_RESET),
- };
- StaticSocketDataProvider data(base::span<MockRead>(), write_failure);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- TestCompletionCallback callback;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
- IPEndPoint endpoint;
- EXPECT_TRUE(trans.GetRemoteEndpoint(&endpoint));
- EXPECT_LT(0u, endpoint.address().size());
- }
- // Check that a connection closed after the start of the headers finishes ok.
- TEST_F(HttpNetworkTransactionTest, ConnectionClosedAfterStartOfHeaders) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.foo.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockRead data_reads[] = {
- MockRead("HTTP/1."),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- TestCompletionCallback callback;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("", response_data);
- IPEndPoint endpoint;
- EXPECT_TRUE(trans.GetRemoteEndpoint(&endpoint));
- EXPECT_LT(0u, endpoint.address().size());
- }
- // Make sure that a dropped connection while draining the body for auth
- // restart does the right thing.
- TEST_F(HttpNetworkTransactionTest, DrainResetOK) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes1[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 401 Unauthorized\r\n"),
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 14\r\n\r\n"),
- MockRead("Unauth"),
- MockRead(ASYNC, ERR_CONNECTION_RESET),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- // After calling trans.RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite data_writes2[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(CheckBasicServerAuth(response->auth_challenge));
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(100, response->headers->GetContentLength());
- }
- // Test HTTPS connections going through a proxy that sends extra data.
- TEST_F(HttpNetworkTransactionTest, HTTPSViaProxyWithExtraData) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockRead proxy_reads[] = {
- MockRead("HTTP/1.0 200 Connected\r\n\r\nExtra data"),
- MockRead(SYNCHRONOUS, OK)
- };
- StaticSocketDataProvider data(proxy_reads, base::span<MockWrite>());
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback;
- session_deps_.socket_factory->ResetNextMockIndexes();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
- }
- TEST_F(HttpNetworkTransactionTest, LargeContentLengthThenClose) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\nContent-Length:6719476739\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsError(ERR_CONTENT_LENGTH_MISMATCH));
- }
- TEST_F(HttpNetworkTransactionTest, UploadFileSmallerThanLength) {
- base::FilePath temp_file_path;
- ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path));
- const uint64_t kFakeSize = 100000; // file is actually blank
- UploadFileElementReader::ScopedOverridingContentLengthForTests
- overriding_content_length(kFakeSize);
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(std::make_unique<UploadFileElementReader>(
- base::ThreadTaskRunnerHandle::Get().get(), temp_file_path, 0,
- std::numeric_limits<uint64_t>::max(), base::Time()));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.example.org/upload");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_UPLOAD_FILE_CHANGED));
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->headers);
- base::DeleteFile(temp_file_path);
- }
- TEST_F(HttpNetworkTransactionTest, UploadUnreadableFile) {
- base::FilePath temp_file;
- ASSERT_TRUE(base::CreateTemporaryFile(&temp_file));
- std::string temp_file_content("Unreadable file.");
- ASSERT_EQ(static_cast<int>(temp_file_content.length()),
- base::WriteFile(temp_file, temp_file_content.c_str(),
- temp_file_content.length()));
- ASSERT_TRUE(base::MakeFileUnreadable(temp_file));
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(std::make_unique<UploadFileElementReader>(
- base::ThreadTaskRunnerHandle::Get().get(), temp_file, 0,
- std::numeric_limits<uint64_t>::max(), base::Time()));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.example.org/upload");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // If we try to upload an unreadable file, the transaction should fail.
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- StaticSocketDataProvider data;
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_ACCESS_DENIED));
- base::DeleteFile(temp_file);
- }
- TEST_F(HttpNetworkTransactionTest, CancelDuringInitRequestBody) {
- class FakeUploadElementReader : public UploadElementReader {
- public:
- FakeUploadElementReader() = default;
- ~FakeUploadElementReader() override = default;
- CompletionOnceCallback TakeCallback() { return std::move(callback_); }
- // UploadElementReader overrides:
- int Init(CompletionOnceCallback callback) override {
- callback_ = std::move(callback);
- return ERR_IO_PENDING;
- }
- uint64_t GetContentLength() const override { return 0; }
- uint64_t BytesRemaining() const override { return 0; }
- int Read(IOBuffer* buf,
- int buf_length,
- CompletionOnceCallback callback) override {
- return ERR_FAILED;
- }
- private:
- CompletionOnceCallback callback_;
- };
- auto fake_reader = std::make_unique<FakeUploadElementReader>();
- auto* fake_reader_ptr = fake_reader.get();
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(std::move(fake_reader));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.example.org/upload");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- StaticSocketDataProvider data;
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- base::RunLoop().RunUntilIdle();
- // Transaction is pending on request body initialization.
- CompletionOnceCallback init_callback = fake_reader_ptr->TakeCallback();
- ASSERT_FALSE(init_callback.is_null());
- // Return Init()'s result after the transaction gets destroyed.
- trans.reset();
- std::move(init_callback).Run(OK); // Should not crash.
- }
- // Tests that changes to Auth realms are treated like auth rejections.
- TEST_F(HttpNetworkTransactionTest, ChangeAuthRealms) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // First transaction will request a resource and receive a Basic challenge
- // with realm="first_realm".
- MockWrite data_writes1[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 401 Unauthorized\r\n"
- "WWW-Authenticate: Basic realm=\"first_realm\"\r\n"
- "\r\n"),
- };
- // After calling trans.RestartWithAuth(), provide an Authentication header
- // for first_realm. The server will reject and provide a challenge with
- // second_realm.
- MockWrite data_writes2[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zmlyc3Q6YmF6\r\n"
- "\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 401 Unauthorized\r\n"
- "WWW-Authenticate: Basic realm=\"second_realm\"\r\n"
- "\r\n"),
- };
- // This again fails, and goes back to first_realm. Make sure that the
- // entry is removed from cache.
- MockWrite data_writes3[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic c2Vjb25kOmZvdQ==\r\n"
- "\r\n"),
- };
- MockRead data_reads3[] = {
- MockRead("HTTP/1.1 401 Unauthorized\r\n"
- "WWW-Authenticate: Basic realm=\"first_realm\"\r\n"
- "\r\n"),
- };
- // Try one last time (with the correct password) and get the resource.
- MockWrite data_writes4[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zmlyc3Q6YmFy\r\n"
- "\r\n"),
- };
- MockRead data_reads4[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Content-Type: text/html; charset=iso-8859-1\r\n"
- "Content-Length: 5\r\n"
- "\r\n"
- "hello"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- StaticSocketDataProvider data3(data_reads3, data_writes3);
- StaticSocketDataProvider data4(data_reads4, data_writes4);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- session_deps_.socket_factory->AddSocketDataProvider(&data3);
- session_deps_.socket_factory->AddSocketDataProvider(&data4);
- TestCompletionCallback callback1;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Issue the first request with Authorize headers. There should be a
- // password prompt for first_realm waiting to be filled in after the
- // transaction completes.
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- absl::optional<AuthChallengeInfo> challenge = response->auth_challenge;
- ASSERT_TRUE(challenge);
- EXPECT_FALSE(challenge->is_proxy);
- EXPECT_EQ("http://www.example.org", challenge->challenger.Serialize());
- EXPECT_EQ("first_realm", challenge->realm);
- EXPECT_EQ(kBasicAuthScheme, challenge->scheme);
- // Issue the second request with an incorrect password. There should be a
- // password prompt for second_realm waiting to be filled in after the
- // transaction completes.
- TestCompletionCallback callback2;
- rv = trans.RestartWithAuth(AuthCredentials(kFirst, kBaz),
- callback2.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback2.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- challenge = response->auth_challenge;
- ASSERT_TRUE(challenge);
- EXPECT_FALSE(challenge->is_proxy);
- EXPECT_EQ("http://www.example.org", challenge->challenger.Serialize());
- EXPECT_EQ("second_realm", challenge->realm);
- EXPECT_EQ(kBasicAuthScheme, challenge->scheme);
- // Issue the third request with another incorrect password. There should be
- // a password prompt for first_realm waiting to be filled in. If the password
- // prompt is not present, it indicates that the HttpAuthCacheEntry for
- // first_realm was not correctly removed.
- TestCompletionCallback callback3;
- rv = trans.RestartWithAuth(AuthCredentials(kSecond, kFou),
- callback3.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback3.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- challenge = response->auth_challenge;
- ASSERT_TRUE(challenge);
- EXPECT_FALSE(challenge->is_proxy);
- EXPECT_EQ("http://www.example.org", challenge->challenger.Serialize());
- EXPECT_EQ("first_realm", challenge->realm);
- EXPECT_EQ(kBasicAuthScheme, challenge->scheme);
- // Issue the fourth request with the correct password and username.
- TestCompletionCallback callback4;
- rv = trans.RestartWithAuth(AuthCredentials(kFirst, kBar),
- callback4.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback4.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- }
- // Regression test for https://crbug.com/754395.
- TEST_F(HttpNetworkTransactionTest, IgnoreAltSvcWithInvalidCert) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(kAlternativeServiceHttpHeader),
- MockRead("\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
- ASSERT_TRUE(ssl.ssl_info.cert);
- ssl.ssl_info.cert_status = CERT_STATUS_COMMON_NAME_INVALID;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- url::SchemeHostPort test_server(request.url);
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- EXPECT_TRUE(
- http_server_properties
- ->GetAlternativeServiceInfos(test_server, NetworkIsolationKey())
- .empty());
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_alpn_negotiated);
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- EXPECT_TRUE(
- http_server_properties
- ->GetAlternativeServiceInfos(test_server, NetworkIsolationKey())
- .empty());
- }
- TEST_F(HttpNetworkTransactionTest, HonorAlternativeServiceHeader) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(kAlternativeServiceHttpHeader),
- MockRead("\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
- ASSERT_TRUE(ssl.ssl_info.cert);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- url::SchemeHostPort test_server(request.url);
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- EXPECT_TRUE(
- http_server_properties
- ->GetAlternativeServiceInfos(test_server, NetworkIsolationKey())
- .empty());
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_alpn_negotiated);
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- AlternativeServiceInfoVector alternative_service_info_vector =
- http_server_properties->GetAlternativeServiceInfos(test_server,
- NetworkIsolationKey());
- ASSERT_EQ(1u, alternative_service_info_vector.size());
- AlternativeService alternative_service(kProtoHTTP2, "mail.example.org", 443);
- EXPECT_EQ(alternative_service,
- alternative_service_info_vector[0].alternative_service());
- }
- TEST_F(HttpNetworkTransactionTest,
- HonorAlternativeServiceHeaderWithNetworkIsolationKey) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- // enabled_features
- {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
- // Need to partition connections by NetworkIsolationKey for
- // SpdySessionKeys to include NetworkIsolationKeys.
- features::kPartitionConnectionsByNetworkIsolationKey},
- // disabled_features
- {});
- // Since HttpServerProperties caches the feature value, have to create a new
- // one.
- session_deps_.http_server_properties =
- std::make_unique<HttpServerProperties>();
- const SchemefulSite kSite1(GURL("https://foo.test/"));
- const net::NetworkIsolationKey kNetworkIsolationKey1(kSite1, kSite1);
- const SchemefulSite kSite2(GURL("https://bar.test/"));
- const net::NetworkIsolationKey kNetworkIsolationKey2(kSite2, kSite2);
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(kAlternativeServiceHttpHeader),
- MockRead("\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request.network_isolation_key = kNetworkIsolationKey1;
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
- ASSERT_TRUE(ssl.ssl_info.cert);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- url::SchemeHostPort test_server(request.url);
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- EXPECT_TRUE(
- http_server_properties
- ->GetAlternativeServiceInfos(test_server, kNetworkIsolationKey1)
- .empty());
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_alpn_negotiated);
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- AlternativeServiceInfoVector alternative_service_info_vector =
- http_server_properties->GetAlternativeServiceInfos(test_server,
- kNetworkIsolationKey1);
- ASSERT_EQ(1u, alternative_service_info_vector.size());
- AlternativeService alternative_service(kProtoHTTP2, "mail.example.org", 443);
- EXPECT_EQ(alternative_service,
- alternative_service_info_vector[0].alternative_service());
- // Make sure the alternative service information is only associated with
- // kNetworkIsolationKey1.
- EXPECT_TRUE(
- http_server_properties
- ->GetAlternativeServiceInfos(test_server, NetworkIsolationKey())
- .empty());
- EXPECT_TRUE(
- http_server_properties
- ->GetAlternativeServiceInfos(test_server, kNetworkIsolationKey2)
- .empty());
- }
- // Regression test for https://crbug.com/615497.
- TEST_F(HttpNetworkTransactionTest,
- DoNotParseAlternativeServiceHeaderOnInsecureRequest) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(kAlternativeServiceHttpHeader),
- MockRead("\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.load_flags = 0;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- url::SchemeHostPort test_server(request.url);
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- EXPECT_TRUE(
- http_server_properties
- ->GetAlternativeServiceInfos(test_server, NetworkIsolationKey())
- .empty());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_alpn_negotiated);
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- EXPECT_TRUE(
- http_server_properties
- ->GetAlternativeServiceInfos(test_server, NetworkIsolationKey())
- .empty());
- }
- // HTTP/2 Alternative Services should be disabled by default.
- // TODO(bnc): Remove when https://crbug.com/615413 is fixed.
- TEST_F(HttpNetworkTransactionTest,
- DisableHTTP2AlternativeServicesWithDifferentHost) {
- session_deps_.enable_http2_alternative_service = false;
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.load_flags = 0;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED);
- StaticSocketDataProvider first_data;
- first_data.set_connect_data(mock_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&first_data);
- SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello world"),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider second_data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&second_data);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- AlternativeService alternative_service(kProtoHTTP2, "different.example.org",
- 444);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetHttp2AlternativeService(
- url::SchemeHostPort(request.url), NetworkIsolationKey(),
- alternative_service, expiration);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- // Alternative service is not used, request fails.
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_CONNECTION_REFUSED));
- }
- // Regression test for https://crbug.com/615497:
- // Alternative Services should be disabled for http origin.
- TEST_F(HttpNetworkTransactionTest,
- DisableAlternativeServicesForInsecureOrigin) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.load_flags = 0;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED);
- StaticSocketDataProvider first_data;
- first_data.set_connect_data(mock_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&first_data);
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello world"),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider second_data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&second_data);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- AlternativeService alternative_service(kProtoHTTP2, "", 444);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetHttp2AlternativeService(
- url::SchemeHostPort(request.url), NetworkIsolationKey(),
- alternative_service, expiration);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- // Alternative service is not used, request fails.
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_CONNECTION_REFUSED));
- }
- TEST_F(HttpNetworkTransactionTest, ClearAlternativeServices) {
- // Set an alternative service for origin.
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- url::SchemeHostPort test_server("https", "www.example.org", 443);
- AlternativeService alternative_service(kProtoQUIC, "", 80);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetQuicAlternativeService(
- test_server, NetworkIsolationKey(), alternative_service, expiration,
- session->context().quic_context->params()->supported_versions);
- EXPECT_EQ(1u,
- http_server_properties
- ->GetAlternativeServiceInfos(test_server, NetworkIsolationKey())
- .size());
- // Send a clear header.
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Alt-Svc: clear\r\n"),
- MockRead("\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
- ASSERT_TRUE(ssl.ssl_info.cert);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- TestCompletionCallback callback;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_alpn_negotiated);
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- EXPECT_TRUE(
- http_server_properties
- ->GetAlternativeServiceInfos(test_server, NetworkIsolationKey())
- .empty());
- }
- TEST_F(HttpNetworkTransactionTest, HonorMultipleAlternativeServiceHeaders) {
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Alt-Svc: h2=\"www.example.com:443\","),
- MockRead("h2=\":1234\"\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
- ASSERT_TRUE(ssl.ssl_info.cert);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- url::SchemeHostPort test_server("https", "www.example.org", 443);
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- EXPECT_TRUE(
- http_server_properties
- ->GetAlternativeServiceInfos(test_server, NetworkIsolationKey())
- .empty());
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_alpn_negotiated);
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- AlternativeServiceInfoVector alternative_service_info_vector =
- http_server_properties->GetAlternativeServiceInfos(test_server,
- NetworkIsolationKey());
- ASSERT_EQ(2u, alternative_service_info_vector.size());
- AlternativeService alternative_service(kProtoHTTP2, "www.example.com", 443);
- EXPECT_EQ(alternative_service,
- alternative_service_info_vector[0].alternative_service());
- AlternativeService alternative_service_2(kProtoHTTP2, "www.example.org",
- 1234);
- EXPECT_EQ(alternative_service_2,
- alternative_service_info_vector[1].alternative_service());
- }
- TEST_F(HttpNetworkTransactionTest, IdentifyQuicBroken) {
- url::SchemeHostPort server("https", "origin.example.org", 443);
- HostPortPair alternative("alternative.example.org", 443);
- std::string origin_url = "https://origin.example.org:443";
- std::string alternative_url = "https://alternative.example.org:443";
- // Negotiate HTTP/1.1 with alternative.example.org.
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- // HTTP/1.1 data for request.
- MockWrite http_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: alternative.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Content-Type: text/html; charset=iso-8859-1\r\n"
- "Content-Length: 40\r\n\r\n"
- "first HTTP/1.1 response from alternative"),
- };
- StaticSocketDataProvider http_data(http_reads, http_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&http_data);
- StaticSocketDataProvider data_refused;
- data_refused.set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_REFUSED));
- session_deps_.socket_factory->AddSocketDataProvider(&data_refused);
- // Set up a QUIC alternative service for server.
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- AlternativeService alternative_service(kProtoQUIC, alternative);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetQuicAlternativeService(
- server, NetworkIsolationKey(), alternative_service, expiration,
- DefaultSupportedQuicVersions());
- // Mark the QUIC alternative service as broken.
- http_server_properties->MarkAlternativeServiceBroken(alternative_service,
- NetworkIsolationKey());
- HttpRequestInfo request;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- request.method = "GET";
- request.url = GURL(origin_url);
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- TestCompletionCallback callback;
- NetErrorDetails details;
- EXPECT_FALSE(details.quic_broken);
- trans.Start(&request, callback.callback(), NetLogWithSource());
- trans.PopulateNetErrorDetails(&details);
- EXPECT_TRUE(details.quic_broken);
- }
- TEST_F(HttpNetworkTransactionTest, IdentifyQuicNotBroken) {
- url::SchemeHostPort server("https", "origin.example.org", 443);
- HostPortPair alternative1("alternative1.example.org", 443);
- HostPortPair alternative2("alternative2.example.org", 443);
- std::string origin_url = "https://origin.example.org:443";
- std::string alternative_url1 = "https://alternative1.example.org:443";
- std::string alternative_url2 = "https://alternative2.example.org:443";
- // Negotiate HTTP/1.1 with alternative1.example.org.
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- // HTTP/1.1 data for request.
- MockWrite http_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: alternative1.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Content-Type: text/html; charset=iso-8859-1\r\n"
- "Content-Length: 40\r\n\r\n"
- "first HTTP/1.1 response from alternative1"),
- };
- StaticSocketDataProvider http_data(http_reads, http_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&http_data);
- StaticSocketDataProvider data_refused;
- data_refused.set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_REFUSED));
- session_deps_.socket_factory->AddSocketDataProvider(&data_refused);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- // Set up two QUIC alternative services for server.
- AlternativeServiceInfoVector alternative_service_info_vector;
- base::Time expiration = base::Time::Now() + base::Days(1);
- AlternativeService alternative_service1(kProtoQUIC, alternative1);
- alternative_service_info_vector.push_back(
- AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
- alternative_service1, expiration,
- session->context().quic_context->params()->supported_versions));
- AlternativeService alternative_service2(kProtoQUIC, alternative2);
- alternative_service_info_vector.push_back(
- AlternativeServiceInfo::CreateQuicAlternativeServiceInfo(
- alternative_service2, expiration,
- session->context().quic_context->params()->supported_versions));
- http_server_properties->SetAlternativeServices(
- server, NetworkIsolationKey(), alternative_service_info_vector);
- // Mark one of the QUIC alternative service as broken.
- http_server_properties->MarkAlternativeServiceBroken(alternative_service1,
- NetworkIsolationKey());
- EXPECT_EQ(2u, http_server_properties
- ->GetAlternativeServiceInfos(server, NetworkIsolationKey())
- .size());
- HttpRequestInfo request;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- request.method = "GET";
- request.url = GURL(origin_url);
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- TestCompletionCallback callback;
- NetErrorDetails details;
- EXPECT_FALSE(details.quic_broken);
- trans.Start(&request, callback.callback(), NetLogWithSource());
- trans.PopulateNetErrorDetails(&details);
- EXPECT_FALSE(details.quic_broken);
- }
- TEST_F(HttpNetworkTransactionTest, MarkBrokenAlternateProtocolAndFallback) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED);
- StaticSocketDataProvider first_data;
- first_data.set_connect_data(mock_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&first_data);
- SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider second_data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&second_data);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- const url::SchemeHostPort server(request.url);
- // Port must be < 1024, or the header will be ignored (since initial port was
- // port 80 (another restricted port).
- // Port is ignored by MockConnect anyway.
- const AlternativeService alternative_service(kProtoHTTP2, "www.example.org",
- 666);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetHttp2AlternativeService(
- server, NetworkIsolationKey(), alternative_service, expiration);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- const AlternativeServiceInfoVector alternative_service_info_vector =
- http_server_properties->GetAlternativeServiceInfos(server,
- NetworkIsolationKey());
- ASSERT_EQ(1u, alternative_service_info_vector.size());
- EXPECT_EQ(alternative_service,
- alternative_service_info_vector[0].alternative_service());
- EXPECT_TRUE(http_server_properties->IsAlternativeServiceBroken(
- alternative_service, NetworkIsolationKey()));
- }
- // Ensure that we are not allowed to redirect traffic via an alternate protocol
- // to an unrestricted (port >= 1024) when the original traffic was on a
- // restricted port (port < 1024). Ensure that we can redirect in all other
- // cases.
- TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortRestrictedBlocked) {
- HttpRequestInfo restricted_port_request;
- restricted_port_request.method = "GET";
- restricted_port_request.url = GURL("https://www.example.org:1023/");
- restricted_port_request.load_flags = 0;
- restricted_port_request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED);
- StaticSocketDataProvider first_data;
- first_data.set_connect_data(mock_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&first_data);
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider second_data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&second_data);
- SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- const int kUnrestrictedAlternatePort = 1024;
- AlternativeService alternative_service(kProtoHTTP2, "www.example.org",
- kUnrestrictedAlternatePort);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetHttp2AlternativeService(
- url::SchemeHostPort(restricted_port_request.url), NetworkIsolationKey(),
- alternative_service, expiration);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&restricted_port_request, callback.callback(),
- NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Invalid change to unrestricted port should fail.
- EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_REFUSED));
- }
- // Ensure that we are allowed to redirect traffic via an alternate protocol to
- // an unrestricted (port >= 1024) when the original traffic was on a restricted
- // port (port < 1024) if we set |enable_user_alternate_protocol_ports|.
- TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortRestrictedPermitted) {
- session_deps_.enable_user_alternate_protocol_ports = true;
- HttpRequestInfo restricted_port_request;
- restricted_port_request.method = "GET";
- restricted_port_request.url = GURL("https://www.example.org:1023/");
- restricted_port_request.load_flags = 0;
- restricted_port_request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED);
- StaticSocketDataProvider first_data;
- first_data.set_connect_data(mock_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&first_data);
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider second_data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&second_data);
- SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- const int kUnrestrictedAlternatePort = 1024;
- AlternativeService alternative_service(kProtoHTTP2, "www.example.org",
- kUnrestrictedAlternatePort);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetHttp2AlternativeService(
- url::SchemeHostPort(restricted_port_request.url), NetworkIsolationKey(),
- alternative_service, expiration);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- trans.Start(&restricted_port_request, callback.callback(),
- NetLogWithSource()));
- // Change to unrestricted port should succeed.
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- }
- // Ensure that we are not allowed to redirect traffic via an alternate protocol
- // to an unrestricted (port >= 1024) when the original traffic was on a
- // restricted port (port < 1024). Ensure that we can redirect in all other
- // cases.
- TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortRestrictedAllowed) {
- HttpRequestInfo restricted_port_request;
- restricted_port_request.method = "GET";
- restricted_port_request.url = GURL("https://www.example.org:1023/");
- restricted_port_request.load_flags = 0;
- restricted_port_request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED);
- StaticSocketDataProvider first_data;
- first_data.set_connect_data(mock_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&first_data);
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider second_data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&second_data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- const int kRestrictedAlternatePort = 80;
- AlternativeService alternative_service(kProtoHTTP2, "www.example.org",
- kRestrictedAlternatePort);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetHttp2AlternativeService(
- url::SchemeHostPort(restricted_port_request.url), NetworkIsolationKey(),
- alternative_service, expiration);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&restricted_port_request, callback.callback(),
- NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Valid change to restricted port should pass.
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- }
- // Ensure that we are not allowed to redirect traffic via an alternate protocol
- // to an unrestricted (port >= 1024) when the original traffic was on a
- // restricted port (port < 1024). Ensure that we can redirect in all other
- // cases.
- TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortUnrestrictedAllowed1) {
- HttpRequestInfo unrestricted_port_request;
- unrestricted_port_request.method = "GET";
- unrestricted_port_request.url = GURL("https://www.example.org:1024/");
- unrestricted_port_request.load_flags = 0;
- unrestricted_port_request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED);
- StaticSocketDataProvider first_data;
- first_data.set_connect_data(mock_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&first_data);
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider second_data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&second_data);
- SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- const int kRestrictedAlternatePort = 80;
- AlternativeService alternative_service(kProtoHTTP2, "www.example.org",
- kRestrictedAlternatePort);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetHttp2AlternativeService(
- url::SchemeHostPort(unrestricted_port_request.url), NetworkIsolationKey(),
- alternative_service, expiration);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&unrestricted_port_request, callback.callback(),
- NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Valid change to restricted port should pass.
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- }
- // Ensure that we are not allowed to redirect traffic via an alternate protocol
- // to an unrestricted (port >= 1024) when the original traffic was on a
- // restricted port (port < 1024). Ensure that we can redirect in all other
- // cases.
- TEST_F(HttpNetworkTransactionTest, AlternateProtocolPortUnrestrictedAllowed2) {
- HttpRequestInfo unrestricted_port_request;
- unrestricted_port_request.method = "GET";
- unrestricted_port_request.url = GURL("https://www.example.org:1024/");
- unrestricted_port_request.load_flags = 0;
- unrestricted_port_request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED);
- StaticSocketDataProvider first_data;
- first_data.set_connect_data(mock_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&first_data);
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider second_data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&second_data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- const int kUnrestrictedAlternatePort = 1025;
- AlternativeService alternative_service(kProtoHTTP2, "www.example.org",
- kUnrestrictedAlternatePort);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetHttp2AlternativeService(
- url::SchemeHostPort(unrestricted_port_request.url), NetworkIsolationKey(),
- alternative_service, expiration);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&unrestricted_port_request, callback.callback(),
- NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Valid change to an unrestricted port should pass.
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- }
- // Ensure that we are not allowed to redirect traffic via an alternate protocol
- // to an unsafe port, and that we resume the second HttpStreamFactory::Job once
- // the alternate protocol request fails.
- TEST_F(HttpNetworkTransactionTest, AlternateProtocolUnsafeBlocked) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // The alternate protocol request will error out before we attempt to connect,
- // so only the standard HTTP request will try to connect.
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- const int kUnsafePort = 7;
- AlternativeService alternative_service(kProtoHTTP2, "www.example.org",
- kUnsafePort);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetHttp2AlternativeService(
- url::SchemeHostPort(request.url), NetworkIsolationKey(),
- alternative_service, expiration);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // The HTTP request should succeed.
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- }
- TEST_F(HttpNetworkTransactionTest, UseAlternateProtocolForNpnSpdy) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(kAlternativeServiceHttpHeader),
- MockRead("\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK)};
- StaticSocketDataProvider first_transaction(data_reads,
- base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&first_transaction);
- SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
- AddSSLSocketData();
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet("https://www.example.org/", 1, LOWEST));
- MockWrite spdy_writes[] = {CreateMockWrite(req, 0)};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead spdy_reads[] = {
- CreateMockRead(resp, 1), CreateMockRead(data, 2), MockRead(ASYNC, 0, 3),
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
- StaticSocketDataProvider hanging_non_alternate_protocol_socket;
- hanging_non_alternate_protocol_socket.set_connect_data(
- never_finishing_connect);
- session_deps_.socket_factory->AddSocketDataProvider(
- &hanging_non_alternate_protocol_socket);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- }
- TEST_F(HttpNetworkTransactionTest, AlternateProtocolWithSpdyLateBinding) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // First transaction receives Alt-Svc header over HTTP/1.1.
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(kAlternativeServiceHttpHeader),
- MockRead("\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider http11_data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&http11_data);
- SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
- ASSERT_TRUE(ssl_http11.ssl_info.cert);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
- // Second transaction starts an alternative and a non-alternative Job.
- // Both sockets hang.
- MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
- StaticSocketDataProvider hanging_socket1;
- hanging_socket1.set_connect_data(never_finishing_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&hanging_socket1);
- StaticSocketDataProvider hanging_socket2;
- hanging_socket2.set_connect_data(never_finishing_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&hanging_socket2);
- // Third transaction starts an alternative and a non-alternative job.
- // The non-alternative job hangs, but the alternative one succeeds.
- // The second transaction, still pending, binds to this socket.
- spdy::SpdySerializedFrame req1(
- spdy_util_.ConstructSpdyGet("https://www.example.org/", 1, LOWEST));
- spdy::SpdySerializedFrame req2(
- spdy_util_.ConstructSpdyGet("https://www.example.org/", 3, LOWEST));
- MockWrite spdy_writes[] = {
- CreateMockWrite(req1, 0), CreateMockWrite(req2, 1),
- };
- spdy::SpdySerializedFrame resp1(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame data1(spdy_util_.ConstructSpdyDataFrame(1, true));
- spdy::SpdySerializedFrame resp2(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
- spdy::SpdySerializedFrame data2(spdy_util_.ConstructSpdyDataFrame(3, true));
- MockRead spdy_reads[] = {
- CreateMockRead(resp1, 2), CreateMockRead(data1, 3),
- CreateMockRead(resp2, 4), CreateMockRead(data2, 5),
- MockRead(ASYNC, 0, 6),
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- AddSSLSocketData();
- StaticSocketDataProvider hanging_socket3;
- hanging_socket3.set_connect_data(never_finishing_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&hanging_socket3);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get());
- int rv = trans1.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback1.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans1.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans1, &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- TestCompletionCallback callback2;
- HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- rv = trans2.Start(&request, callback2.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- TestCompletionCallback callback3;
- HttpNetworkTransaction trans3(DEFAULT_PRIORITY, session.get());
- rv = trans3.Start(&request, callback3.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback2.WaitForResult(), IsOk());
- EXPECT_THAT(callback3.WaitForResult(), IsOk());
- response = trans2.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- ASSERT_THAT(ReadTransaction(&trans2, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- response = trans3.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- ASSERT_THAT(ReadTransaction(&trans3, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- }
- TEST_F(HttpNetworkTransactionTest, StallAlternativeServiceForNpnSpdy) {
- session_deps_.host_resolver->set_synchronous_mode(true);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(kAlternativeServiceHttpHeader),
- MockRead("\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider first_transaction(data_reads,
- base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&first_transaction);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
- ASSERT_TRUE(ssl.ssl_info.cert);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
- StaticSocketDataProvider hanging_alternate_protocol_socket;
- hanging_alternate_protocol_socket.set_connect_data(
- never_finishing_connect);
- session_deps_.socket_factory->AddSocketDataProvider(
- &hanging_alternate_protocol_socket);
- // 2nd request is just a copy of the first one, over HTTP/1.1 again.
- StaticSocketDataProvider second_transaction(data_reads,
- base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&second_transaction);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_alpn_negotiated);
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- }
- // Test that proxy is resolved using the origin url,
- // regardless of the alternative server.
- TEST_F(HttpNetworkTransactionTest, UseOriginNotAlternativeForProxy) {
- // Configure proxy to bypass www.example.org, which is the origin URL.
- ProxyConfig proxy_config;
- proxy_config.proxy_rules().ParseFromString("myproxy:70");
- proxy_config.proxy_rules().bypass_rules.AddRuleFromString("www.example.org");
- auto proxy_config_service = std::make_unique<ProxyConfigServiceFixed>(
- ProxyConfigWithAnnotation(proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS));
- CapturingProxyResolver capturing_proxy_resolver;
- auto proxy_resolver_factory = std::make_unique<CapturingProxyResolverFactory>(
- &capturing_proxy_resolver);
- session_deps_.proxy_resolution_service =
- std::make_unique<ConfiguredProxyResolutionService>(
- std::move(proxy_config_service), std::move(proxy_resolver_factory),
- net::NetLog::Get(), /*quick_check_enabled=*/true);
- session_deps_.net_log = net::NetLog::Get();
- // Configure alternative service with a hostname that is not bypassed by the
- // proxy.
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- url::SchemeHostPort server("https", "www.example.org", 443);
- HostPortPair alternative("www.example.com", 443);
- AlternativeService alternative_service(kProtoHTTP2, alternative);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetHttp2AlternativeService(
- server, NetworkIsolationKey(), alternative_service, expiration);
- // Non-alternative job should hang.
- MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
- StaticSocketDataProvider hanging_alternate_protocol_socket;
- hanging_alternate_protocol_socket.set_connect_data(never_finishing_connect);
- session_deps_.socket_factory->AddSocketDataProvider(
- &hanging_alternate_protocol_socket);
- AddSSLSocketData();
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.load_flags = 0;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet("https://www.example.org/", 1, LOWEST));
- MockWrite spdy_writes[] = {CreateMockWrite(req, 0)};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead spdy_reads[] = {
- CreateMockRead(resp, 1), CreateMockRead(data, 2), MockRead(ASYNC, 0, 3),
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- TestCompletionCallback callback;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- // Origin host bypasses proxy, no resolution should have happened.
- ASSERT_TRUE(capturing_proxy_resolver.lookup_info().empty());
- }
- TEST_F(HttpNetworkTransactionTest, UseAlternativeServiceForTunneledNpnSpdy) {
- ProxyConfig proxy_config;
- proxy_config.set_auto_detect(true);
- proxy_config.set_pac_url(GURL("http://fooproxyurl"));
- CapturingProxyResolver capturing_proxy_resolver;
- session_deps_.proxy_resolution_service =
- std::make_unique<ConfiguredProxyResolutionService>(
- std::make_unique<ProxyConfigServiceFixed>(ProxyConfigWithAnnotation(
- proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)),
- std::make_unique<CapturingProxyResolverFactory>(
- &capturing_proxy_resolver),
- nullptr, /*quick_check_enabled=*/true);
- session_deps_.net_log = net::NetLog::Get();
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(kAlternativeServiceHttpHeader),
- MockRead("\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, ERR_TEST_PEER_CLOSE_AFTER_NEXT_MOCK_READ),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider first_transaction(data_reads,
- base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&first_transaction);
- SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
- AddSSLSocketData();
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet("https://www.example.org/", 1, LOWEST));
- MockWrite spdy_writes[] = {
- MockWrite(ASYNC, 0,
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- CreateMockWrite(req, 2),
- };
- const char kCONNECTResponse[] = "HTTP/1.1 200 Connected\r\n\r\n";
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead spdy_reads[] = {
- MockRead(ASYNC, 1, kCONNECTResponse), CreateMockRead(resp, 3),
- CreateMockRead(data, 4), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5),
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
- StaticSocketDataProvider hanging_non_alternate_protocol_socket;
- hanging_non_alternate_protocol_socket.set_connect_data(
- never_finishing_connect);
- session_deps_.socket_factory->AddSocketDataProvider(
- &hanging_non_alternate_protocol_socket);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/0.9 200 OK", response->headers->GetStatusLine());
- EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- std::string response_data;
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- ASSERT_EQ(2u, capturing_proxy_resolver.lookup_info().size());
- EXPECT_EQ("https://www.example.org/",
- capturing_proxy_resolver.lookup_info()[0].url.spec());
- EXPECT_EQ("https://www.example.org/",
- capturing_proxy_resolver.lookup_info()[1].url.spec());
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_SSL_TIMES);
- }
- TEST_F(HttpNetworkTransactionTest,
- UseAlternativeServiceForNpnSpdyWithExistingSpdySession) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(kAlternativeServiceHttpHeader),
- MockRead("\r\n"),
- MockRead("hello world"),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider first_transaction(data_reads,
- base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&first_transaction);
- SSLSocketDataProvider ssl_http11(ASYNC, OK);
- ssl_http11.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_http11);
- AddSSLSocketData();
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet("https://www.example.org/", 1, LOWEST));
- MockWrite spdy_writes[] = {CreateMockWrite(req, 0)};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead spdy_reads[] = {
- CreateMockRead(resp, 1), CreateMockRead(data, 2), MockRead(ASYNC, 0, 3),
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- // Set up an initial SpdySession in the pool to reuse.
- HostPortPair host_port_pair("www.example.org", 443);
- SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
- PRIVACY_MODE_DISABLED,
- SpdySessionKey::IsProxySession::kFalse, SocketTag(),
- NetworkIsolationKey(), SecureDnsPolicy::kAllow);
- base::WeakPtr<SpdySession> spdy_session =
- CreateSpdySession(session.get(), key, NetLogWithSource());
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- }
- // GenerateAuthToken is a mighty big test.
- // It tests all permutation of GenerateAuthToken behavior:
- // - Synchronous and Asynchronous completion.
- // - OK or error on completion.
- // - Direct connection, non-authenticating proxy, and authenticating proxy.
- // - HTTP or HTTPS backend (to include proxy tunneling).
- // - Non-authenticating and authenticating backend.
- //
- // In all, there are 44 reasonable permuations (for example, if there are
- // problems generating an auth token for an authenticating proxy, we don't
- // need to test all permutations of the backend server).
- //
- // The test proceeds by going over each of the configuration cases, and
- // potentially running up to three rounds in each of the tests. The TestConfig
- // specifies both the configuration for the test as well as the expectations
- // for the results.
- TEST_F(HttpNetworkTransactionTest, GenerateAuthToken) {
- static const char kServer[] = "http://www.example.com";
- static const char kSecureServer[] = "https://www.example.com";
- static const char kProxy[] = "myproxy:70";
- enum AuthTiming {
- AUTH_NONE,
- AUTH_SYNC,
- AUTH_ASYNC,
- };
- const MockWrite kGet(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Connection: keep-alive\r\n\r\n");
- const MockWrite kGetProxy(
- "GET http://www.example.com/ HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n");
- const MockWrite kGetAuth(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: auth_token\r\n\r\n");
- const MockWrite kGetProxyAuth(
- "GET http://www.example.com/ HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: auth_token\r\n\r\n");
- const MockWrite kGetAuthThroughProxy(
- "GET http://www.example.com/ HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Authorization: auth_token\r\n\r\n");
- const MockWrite kGetAuthWithProxyAuth(
- "GET http://www.example.com/ HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: auth_token\r\n"
- "Authorization: auth_token\r\n\r\n");
- const MockWrite kConnect(
- "CONNECT www.example.com:443 HTTP/1.1\r\n"
- "Host: www.example.com:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n");
- const MockWrite kConnectProxyAuth(
- "CONNECT www.example.com:443 HTTP/1.1\r\n"
- "Host: www.example.com:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: auth_token\r\n\r\n");
- const MockRead kSuccess(
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/html; charset=iso-8859-1\r\n"
- "Content-Length: 3\r\n\r\n"
- "Yes");
- const MockRead kFailure(
- "Should not be called.");
- const MockRead kServerChallenge(
- "HTTP/1.1 401 Unauthorized\r\n"
- "WWW-Authenticate: Mock realm=server\r\n"
- "Content-Type: text/html; charset=iso-8859-1\r\n"
- "Content-Length: 14\r\n\r\n"
- "Unauthorized\r\n");
- const MockRead kProxyChallenge(
- "HTTP/1.1 407 Unauthorized\r\n"
- "Proxy-Authenticate: Mock realm=proxy\r\n"
- "Proxy-Connection: close\r\n"
- "Content-Type: text/html; charset=iso-8859-1\r\n"
- "Content-Length: 14\r\n\r\n"
- "Unauthorized\r\n");
- const MockRead kProxyConnected(
- "HTTP/1.1 200 Connection Established\r\n\r\n");
- // NOTE(cbentzel): I wanted TestReadWriteRound to be a simple struct with
- // no constructors, but the C++ compiler on Windows warns about
- // unspecified data in compound literals. So, moved to using constructors,
- // and TestRound's created with the default constructor should not be used.
- struct TestRound {
- TestRound()
- : expected_rv(ERR_UNEXPECTED),
- extra_write(nullptr),
- extra_read(nullptr) {}
- TestRound(const MockWrite& write_arg,
- const MockRead& read_arg,
- int expected_rv_arg)
- : write(write_arg),
- read(read_arg),
- expected_rv(expected_rv_arg),
- extra_write(nullptr),
- extra_read(nullptr) {}
- TestRound(const MockWrite& write_arg, const MockRead& read_arg,
- int expected_rv_arg, const MockWrite* extra_write_arg,
- const MockRead* extra_read_arg)
- : write(write_arg),
- read(read_arg),
- expected_rv(expected_rv_arg),
- extra_write(extra_write_arg),
- extra_read(extra_read_arg) {
- }
- MockWrite write;
- MockRead read;
- int expected_rv;
- raw_ptr<const MockWrite> extra_write;
- raw_ptr<const MockRead> extra_read;
- };
- static const int kNoSSL = 500;
- struct TestConfig {
- int line_number;
- const char* const proxy_url;
- AuthTiming proxy_auth_timing;
- int first_generate_proxy_token_rv;
- const char* const server_url;
- AuthTiming server_auth_timing;
- int first_generate_server_token_rv;
- int num_auth_rounds;
- int first_ssl_round;
- TestRound rounds[4];
- } test_configs[] = {
- // Non-authenticating HTTP server with a direct connection.
- {__LINE__,
- nullptr,
- AUTH_NONE,
- OK,
- kServer,
- AUTH_NONE,
- OK,
- 1,
- kNoSSL,
- {TestRound(kGet, kSuccess, OK)}},
- // Authenticating HTTP server with a direct connection.
- {__LINE__,
- nullptr,
- AUTH_NONE,
- OK,
- kServer,
- AUTH_SYNC,
- OK,
- 2,
- kNoSSL,
- {TestRound(kGet, kServerChallenge, OK),
- TestRound(kGetAuth, kSuccess, OK)}},
- {__LINE__,
- nullptr,
- AUTH_NONE,
- OK,
- kServer,
- AUTH_SYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 3,
- kNoSSL,
- {TestRound(kGet, kServerChallenge, OK),
- TestRound(kGet, kServerChallenge, OK),
- TestRound(kGetAuth, kSuccess, OK)}},
- {__LINE__,
- nullptr,
- AUTH_NONE,
- OK,
- kServer,
- AUTH_SYNC,
- ERR_UNSUPPORTED_AUTH_SCHEME,
- 2,
- kNoSSL,
- {TestRound(kGet, kServerChallenge, OK), TestRound(kGet, kSuccess, OK)}},
- {__LINE__,
- nullptr,
- AUTH_NONE,
- OK,
- kServer,
- AUTH_SYNC,
- ERR_UNDOCUMENTED_SECURITY_LIBRARY_STATUS,
- 2,
- kNoSSL,
- {TestRound(kGet, kServerChallenge, OK), TestRound(kGet, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- ERR_FAILED,
- kServer,
- AUTH_NONE,
- OK,
- 2,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxy, kFailure, ERR_FAILED)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- ERR_FAILED,
- kServer,
- AUTH_NONE,
- OK,
- 2,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxy, kFailure, ERR_FAILED)}},
- {__LINE__,
- nullptr,
- AUTH_NONE,
- OK,
- kServer,
- AUTH_SYNC,
- ERR_FAILED,
- 2,
- kNoSSL,
- {TestRound(kGet, kServerChallenge, OK),
- TestRound(kGet, kFailure, ERR_FAILED)}},
- {__LINE__,
- nullptr,
- AUTH_NONE,
- OK,
- kServer,
- AUTH_ASYNC,
- ERR_FAILED,
- 2,
- kNoSSL,
- {TestRound(kGet, kServerChallenge, OK),
- TestRound(kGet, kFailure, ERR_FAILED)}},
- {__LINE__,
- nullptr,
- AUTH_NONE,
- OK,
- kServer,
- AUTH_ASYNC,
- OK,
- 2,
- kNoSSL,
- {TestRound(kGet, kServerChallenge, OK),
- TestRound(kGetAuth, kSuccess, OK)}},
- {__LINE__,
- nullptr,
- AUTH_NONE,
- OK,
- kServer,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 3,
- kNoSSL,
- {TestRound(kGet, kServerChallenge, OK),
- // The second round uses a HttpAuthHandlerMock that always succeeds.
- TestRound(kGet, kServerChallenge, OK),
- TestRound(kGetAuth, kSuccess, OK)}},
- // Non-authenticating HTTP server through a non-authenticating proxy.
- {__LINE__,
- kProxy,
- AUTH_NONE,
- OK,
- kServer,
- AUTH_NONE,
- OK,
- 1,
- kNoSSL,
- {TestRound(kGetProxy, kSuccess, OK)}},
- // Authenticating HTTP server through a non-authenticating proxy.
- {__LINE__,
- kProxy,
- AUTH_NONE,
- OK,
- kServer,
- AUTH_SYNC,
- OK,
- 2,
- kNoSSL,
- {TestRound(kGetProxy, kServerChallenge, OK),
- TestRound(kGetAuthThroughProxy, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_NONE,
- OK,
- kServer,
- AUTH_SYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 3,
- kNoSSL,
- {TestRound(kGetProxy, kServerChallenge, OK),
- TestRound(kGetProxy, kServerChallenge, OK),
- TestRound(kGetAuthThroughProxy, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_NONE,
- OK,
- kServer,
- AUTH_ASYNC,
- OK,
- 2,
- kNoSSL,
- {TestRound(kGetProxy, kServerChallenge, OK),
- TestRound(kGetAuthThroughProxy, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_NONE,
- OK,
- kServer,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 2,
- kNoSSL,
- {TestRound(kGetProxy, kServerChallenge, OK),
- TestRound(kGetProxy, kSuccess, OK)}},
- // Non-authenticating HTTP server through an authenticating proxy.
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- OK,
- kServer,
- AUTH_NONE,
- OK,
- 2,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- kServer,
- AUTH_NONE,
- OK,
- 2,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxy, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- OK,
- kServer,
- AUTH_NONE,
- OK,
- 2,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- kServer,
- AUTH_NONE,
- OK,
- 2,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxy, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- kServer,
- AUTH_NONE,
- OK,
- 3,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kSuccess, OK)}},
- // Authenticating HTTP server through an authenticating proxy.
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- OK,
- kServer,
- AUTH_SYNC,
- OK,
- 3,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kServerChallenge, OK),
- TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- OK,
- kServer,
- AUTH_SYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 3,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kServerChallenge, OK),
- TestRound(kGetProxyAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- OK,
- kServer,
- AUTH_SYNC,
- OK,
- 3,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kServerChallenge, OK),
- TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- OK,
- kServer,
- AUTH_SYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 3,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kServerChallenge, OK),
- TestRound(kGetProxyAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- OK,
- kServer,
- AUTH_ASYNC,
- OK,
- 3,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kServerChallenge, OK),
- TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- kServer,
- AUTH_ASYNC,
- OK,
- 4,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kServerChallenge, OK),
- TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- OK,
- kServer,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 3,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kServerChallenge, OK),
- TestRound(kGetProxyAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- OK,
- kServer,
- AUTH_ASYNC,
- OK,
- 3,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kServerChallenge, OK),
- TestRound(kGetAuthWithProxyAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- OK,
- kServer,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 3,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kServerChallenge, OK),
- TestRound(kGetProxyAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- kServer,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 4,
- kNoSSL,
- {TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxy, kProxyChallenge, OK),
- TestRound(kGetProxyAuth, kServerChallenge, OK),
- TestRound(kGetProxyAuth, kSuccess, OK)}},
- // Non-authenticating HTTPS server with a direct connection.
- {__LINE__,
- nullptr,
- AUTH_NONE,
- OK,
- kSecureServer,
- AUTH_NONE,
- OK,
- 1,
- 0,
- {TestRound(kGet, kSuccess, OK)}},
- // Authenticating HTTPS server with a direct connection.
- {__LINE__,
- nullptr,
- AUTH_NONE,
- OK,
- kSecureServer,
- AUTH_SYNC,
- OK,
- 2,
- 0,
- {TestRound(kGet, kServerChallenge, OK),
- TestRound(kGetAuth, kSuccess, OK)}},
- {__LINE__,
- nullptr,
- AUTH_NONE,
- OK,
- kSecureServer,
- AUTH_SYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 2,
- 0,
- {TestRound(kGet, kServerChallenge, OK), TestRound(kGet, kSuccess, OK)}},
- {__LINE__,
- nullptr,
- AUTH_NONE,
- OK,
- kSecureServer,
- AUTH_ASYNC,
- OK,
- 2,
- 0,
- {TestRound(kGet, kServerChallenge, OK),
- TestRound(kGetAuth, kSuccess, OK)}},
- {__LINE__,
- nullptr,
- AUTH_NONE,
- OK,
- kSecureServer,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 2,
- 0,
- {TestRound(kGet, kServerChallenge, OK), TestRound(kGet, kSuccess, OK)}},
- // Non-authenticating HTTPS server with a non-authenticating proxy.
- {__LINE__,
- kProxy,
- AUTH_NONE,
- OK,
- kSecureServer,
- AUTH_NONE,
- OK,
- 1,
- 0,
- {TestRound(kConnect, kProxyConnected, OK, &kGet, &kSuccess)}},
- // Authenticating HTTPS server through a non-authenticating proxy.
- {__LINE__,
- kProxy,
- AUTH_NONE,
- OK,
- kSecureServer,
- AUTH_SYNC,
- OK,
- 2,
- 0,
- {TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
- TestRound(kGetAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_NONE,
- OK,
- kSecureServer,
- AUTH_SYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 2,
- 0,
- {TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
- TestRound(kGet, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_NONE,
- OK,
- kSecureServer,
- AUTH_ASYNC,
- OK,
- 2,
- 0,
- {TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
- TestRound(kGetAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_NONE,
- OK,
- kSecureServer,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 2,
- 0,
- {TestRound(kConnect, kProxyConnected, OK, &kGet, &kServerChallenge),
- TestRound(kGet, kSuccess, OK)}},
- // Non-Authenticating HTTPS server through an authenticating proxy.
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- OK,
- kSecureServer,
- AUTH_NONE,
- OK,
- 2,
- 1,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet, &kSuccess)}},
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- kSecureServer,
- AUTH_NONE,
- OK,
- 2,
- kNoSSL,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnect, kProxyConnected, OK, &kGet, &kSuccess)}},
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- ERR_UNSUPPORTED_AUTH_SCHEME,
- kSecureServer,
- AUTH_NONE,
- OK,
- 2,
- kNoSSL,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnect, kProxyConnected, OK, &kGet, &kSuccess)}},
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- ERR_UNEXPECTED,
- kSecureServer,
- AUTH_NONE,
- OK,
- 2,
- kNoSSL,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnect, kProxyConnected, ERR_UNEXPECTED)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- OK,
- kSecureServer,
- AUTH_NONE,
- OK,
- 2,
- 1,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet, &kSuccess)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- kSecureServer,
- AUTH_NONE,
- OK,
- 2,
- kNoSSL,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnect, kProxyConnected, OK, &kGet, &kSuccess)}},
- // Authenticating HTTPS server through an authenticating proxy.
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- OK,
- kSecureServer,
- AUTH_SYNC,
- OK,
- 3,
- 1,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
- &kServerChallenge),
- TestRound(kGetAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- OK,
- kSecureServer,
- AUTH_SYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 3,
- 1,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
- &kServerChallenge),
- TestRound(kGet, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- OK,
- kSecureServer,
- AUTH_SYNC,
- OK,
- 3,
- 1,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
- &kServerChallenge),
- TestRound(kGetAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- OK,
- kSecureServer,
- AUTH_SYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 3,
- 1,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
- &kServerChallenge),
- TestRound(kGet, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- OK,
- kSecureServer,
- AUTH_ASYNC,
- OK,
- 3,
- 1,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
- &kServerChallenge),
- TestRound(kGetAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_SYNC,
- OK,
- kSecureServer,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 3,
- 1,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
- &kServerChallenge),
- TestRound(kGet, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- OK,
- kSecureServer,
- AUTH_ASYNC,
- OK,
- 3,
- 1,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
- &kServerChallenge),
- TestRound(kGetAuth, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- OK,
- kSecureServer,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 3,
- 1,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
- &kServerChallenge),
- TestRound(kGet, kSuccess, OK)}},
- {__LINE__,
- kProxy,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- kSecureServer,
- AUTH_ASYNC,
- ERR_INVALID_AUTH_CREDENTIALS,
- 4,
- 2,
- {TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnect, kProxyChallenge, OK),
- TestRound(kConnectProxyAuth, kProxyConnected, OK, &kGet,
- &kServerChallenge),
- TestRound(kGet, kSuccess, OK)}},
- };
- for (const auto& test_config : test_configs) {
- SCOPED_TRACE(::testing::Message() << "Test config at "
- << test_config.line_number);
- auto auth_factory = std::make_unique<HttpAuthHandlerMock::Factory>();
- auto* auth_factory_ptr = auth_factory.get();
- session_deps_.http_auth_handler_factory = std::move(auth_factory);
- SSLInfo empty_ssl_info;
- // Set up authentication handlers as necessary.
- if (test_config.proxy_auth_timing != AUTH_NONE) {
- for (int n = 0; n < 3; n++) {
- auto auth_handler = std::make_unique<HttpAuthHandlerMock>();
- std::string auth_challenge = "Mock realm=proxy";
- url::SchemeHostPort scheme_host_port(GURL(test_config.proxy_url));
- HttpAuthChallengeTokenizer tokenizer(auth_challenge.begin(),
- auth_challenge.end());
- auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_PROXY,
- empty_ssl_info, NetworkIsolationKey(),
- scheme_host_port, NetLogWithSource());
- auth_handler->SetGenerateExpectation(
- test_config.proxy_auth_timing == AUTH_ASYNC,
- n == 0 ? test_config.first_generate_proxy_token_rv : OK);
- auth_factory_ptr->AddMockHandler(std::move(auth_handler),
- HttpAuth::AUTH_PROXY);
- }
- }
- if (test_config.server_auth_timing != AUTH_NONE) {
- auto auth_handler = std::make_unique<HttpAuthHandlerMock>();
- std::string auth_challenge = "Mock realm=server";
- url::SchemeHostPort scheme_host_port(GURL(test_config.server_url));
- HttpAuthChallengeTokenizer tokenizer(auth_challenge.begin(),
- auth_challenge.end());
- auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER,
- empty_ssl_info, NetworkIsolationKey(),
- scheme_host_port, NetLogWithSource());
- auth_handler->SetGenerateExpectation(
- test_config.server_auth_timing == AUTH_ASYNC,
- test_config.first_generate_server_token_rv);
- auth_factory_ptr->AddMockHandler(std::move(auth_handler),
- HttpAuth::AUTH_SERVER);
- // The second handler always succeeds. It should only be used where there
- // are multiple auth sessions for server auth in the same network
- // transaction using the same auth scheme.
- std::unique_ptr<HttpAuthHandlerMock> second_handler =
- std::make_unique<HttpAuthHandlerMock>();
- second_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER,
- empty_ssl_info, NetworkIsolationKey(),
- scheme_host_port, NetLogWithSource());
- second_handler->SetGenerateExpectation(true, OK);
- auth_factory_ptr->AddMockHandler(std::move(second_handler),
- HttpAuth::AUTH_SERVER);
- }
- if (test_config.proxy_url) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- test_config.proxy_url, TRAFFIC_ANNOTATION_FOR_TESTS);
- } else {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateDirect();
- }
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL(test_config.server_url);
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- SSLSocketDataProvider ssl_socket_data_provider(SYNCHRONOUS, OK);
- std::vector<std::vector<MockRead>> mock_reads(1);
- std::vector<std::vector<MockWrite>> mock_writes(1);
- for (int round = 0; round < test_config.num_auth_rounds; ++round) {
- SCOPED_TRACE(round);
- const TestRound& read_write_round = test_config.rounds[round];
- // Set up expected reads and writes.
- mock_reads.back().push_back(read_write_round.read);
- mock_writes.back().push_back(read_write_round.write);
- // kProxyChallenge uses Proxy-Connection: close which means that the
- // socket is closed and a new one will be created for the next request.
- if (read_write_round.read.data == kProxyChallenge.data) {
- mock_reads.emplace_back();
- mock_writes.emplace_back();
- }
- if (read_write_round.extra_read) {
- mock_reads.back().push_back(*read_write_round.extra_read);
- }
- if (read_write_round.extra_write) {
- mock_writes.back().push_back(*read_write_round.extra_write);
- }
- // Add an SSL sequence if necessary.
- if (round >= test_config.first_ssl_round)
- session_deps_.socket_factory->AddSSLSocketDataProvider(
- &ssl_socket_data_provider);
- }
- std::vector<std::unique_ptr<StaticSocketDataProvider>> data_providers;
- for (size_t i = 0; i < mock_reads.size(); ++i) {
- data_providers.push_back(std::make_unique<StaticSocketDataProvider>(
- mock_reads[i], mock_writes[i]));
- session_deps_.socket_factory->AddSocketDataProvider(
- data_providers.back().get());
- }
- // Transaction must be created after DataProviders, so it's destroyed before
- // they are as well.
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- for (int round = 0; round < test_config.num_auth_rounds; ++round) {
- SCOPED_TRACE(round);
- const TestRound& read_write_round = test_config.rounds[round];
- // Start or restart the transaction.
- TestCompletionCallback callback;
- int rv;
- if (round == 0) {
- rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- } else {
- rv = trans.RestartWithAuth(
- AuthCredentials(kFoo, kBar), callback.callback());
- }
- if (rv == ERR_IO_PENDING)
- rv = callback.WaitForResult();
- // Compare results with expected data.
- EXPECT_THAT(rv, IsError(read_write_round.expected_rv));
- const HttpResponseInfo* response = trans.GetResponseInfo();
- if (read_write_round.expected_rv != OK) {
- EXPECT_EQ(round + 1, test_config.num_auth_rounds);
- continue;
- }
- if (round + 1 < test_config.num_auth_rounds) {
- EXPECT_TRUE(response->auth_challenge.has_value());
- } else {
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_FALSE(trans.IsReadyToRestartForAuth());
- }
- }
- }
- }
- TEST_F(HttpNetworkTransactionTest, MultiRoundAuth) {
- // Do multi-round authentication and make sure it works correctly.
- auto auth_factory = std::make_unique<HttpAuthHandlerMock::Factory>();
- auto* auth_factory_ptr = auth_factory.get();
- session_deps_.http_auth_handler_factory = std::move(auth_factory);
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateDirect();
- session_deps_.host_resolver->rules()->AddRule("www.example.com", "10.0.0.1");
- auto auth_handler = std::make_unique<HttpAuthHandlerMock>();
- auto* auth_handler_ptr = auth_handler.get();
- auth_handler->set_connection_based(true);
- std::string auth_challenge = "Mock realm=server";
- GURL url("http://www.example.com");
- HttpAuthChallengeTokenizer tokenizer(auth_challenge.begin(),
- auth_challenge.end());
- SSLInfo empty_ssl_info;
- auth_handler->InitFromChallenge(&tokenizer, HttpAuth::AUTH_SERVER,
- empty_ssl_info, NetworkIsolationKey(),
- url::SchemeHostPort(url), NetLogWithSource());
- auth_factory_ptr->AddMockHandler(std::move(auth_handler),
- HttpAuth::AUTH_SERVER);
- int rv = OK;
- const HttpResponseInfo* response = nullptr;
- HttpRequestInfo request;
- request.method = "GET";
- request.url = url;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Use a TCP Socket Pool with only one connection per group. This is used
- // to validate that the TCP socket is not released to the pool between
- // each round of multi-round authentication.
- HttpNetworkSessionPeer session_peer(session.get());
- CommonConnectJobParams common_connect_job_params(
- session->CreateCommonConnectJobParams());
- auto transport_pool = std::make_unique<TransportClientSocketPool>(
- 50, // Max sockets for pool
- 1, // Max sockets per group
- base::Seconds(10), // unused_idle_socket_timeout
- ProxyServer::Direct(), false, // is_for_websockets
- &common_connect_job_params);
- auto* transport_pool_ptr = transport_pool.get();
- auto mock_pool_manager = std::make_unique<MockClientSocketPoolManager>();
- mock_pool_manager->SetSocketPool(ProxyServer::Direct(),
- std::move(transport_pool));
- session_peer.SetClientSocketPoolManager(std::move(mock_pool_manager));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- const MockWrite kGet(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Connection: keep-alive\r\n\r\n");
- const MockWrite kGetAuth(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: auth_token\r\n\r\n");
- const MockRead kServerChallenge(
- "HTTP/1.1 401 Unauthorized\r\n"
- "WWW-Authenticate: Mock realm=server\r\n"
- "Content-Type: text/html; charset=iso-8859-1\r\n"
- "Content-Length: 14\r\n\r\n"
- "Unauthorized\r\n");
- const MockRead kSuccess(
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/html; charset=iso-8859-1\r\n"
- "Content-Length: 3\r\n\r\n"
- "Yes");
- MockWrite writes[] = {
- // First round
- kGet,
- // Second round
- kGetAuth,
- // Third round
- kGetAuth,
- // Fourth round
- kGetAuth,
- // Competing request
- kGet,
- };
- MockRead reads[] = {
- // First round
- kServerChallenge,
- // Second round
- kServerChallenge,
- // Third round
- kServerChallenge,
- // Fourth round
- kSuccess,
- // Competing response
- kSuccess,
- };
- StaticSocketDataProvider data_provider(reads, writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data_provider);
- const ClientSocketPool::GroupId kSocketGroup(
- url::SchemeHostPort(url::kHttpScheme, "www.example.com", 80),
- PrivacyMode::PRIVACY_MODE_DISABLED, NetworkIsolationKey(),
- SecureDnsPolicy::kAllow);
- // First round of authentication.
- auth_handler_ptr->SetGenerateExpectation(false, OK);
- rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- if (rv == ERR_IO_PENDING)
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->auth_challenge.has_value());
- EXPECT_EQ(0u, transport_pool_ptr->IdleSocketCountInGroup(kSocketGroup));
- EXPECT_EQ(HttpAuthHandlerMock::State::WAIT_FOR_GENERATE_AUTH_TOKEN,
- auth_handler_ptr->state());
- // In between rounds, another request comes in for the same domain.
- // It should not be able to grab the TCP socket that trans has already
- // claimed.
- HttpNetworkTransaction trans_compete(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback_compete;
- rv = trans_compete.Start(&request, callback_compete.callback(),
- NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // callback_compete.WaitForResult at this point would stall forever,
- // since the HttpNetworkTransaction does not release the request back to
- // the pool until after authentication completes.
- // Second round of authentication.
- auth_handler_ptr->SetGenerateExpectation(false, OK);
- rv = trans.RestartWithAuth(AuthCredentials(kFoo, kBar), callback.callback());
- if (rv == ERR_IO_PENDING)
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(0u, transport_pool_ptr->IdleSocketCountInGroup(kSocketGroup));
- EXPECT_EQ(HttpAuthHandlerMock::State::WAIT_FOR_GENERATE_AUTH_TOKEN,
- auth_handler_ptr->state());
- // Third round of authentication.
- auth_handler_ptr->SetGenerateExpectation(false, OK);
- rv = trans.RestartWithAuth(AuthCredentials(), callback.callback());
- if (rv == ERR_IO_PENDING)
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(0u, transport_pool_ptr->IdleSocketCountInGroup(kSocketGroup));
- EXPECT_EQ(HttpAuthHandlerMock::State::WAIT_FOR_GENERATE_AUTH_TOKEN,
- auth_handler_ptr->state());
- // Fourth round of authentication, which completes successfully.
- auth_handler_ptr->SetGenerateExpectation(false, OK);
- rv = trans.RestartWithAuth(AuthCredentials(), callback.callback());
- if (rv == ERR_IO_PENDING)
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_FALSE(response->auth_challenge.has_value());
- EXPECT_EQ(0u, transport_pool_ptr->IdleSocketCountInGroup(kSocketGroup));
- // In WAIT_FOR_CHALLENGE, although in reality the auth handler is done. A real
- // auth handler should transition to a DONE state in concert with the remote
- // server. But that's not something we can test here with a mock handler.
- EXPECT_EQ(HttpAuthHandlerMock::State::WAIT_FOR_CHALLENGE,
- auth_handler_ptr->state());
- // Read the body since the fourth round was successful. This will also
- // release the socket back to the pool.
- scoped_refptr<IOBufferWithSize> io_buf =
- base::MakeRefCounted<IOBufferWithSize>(50);
- rv = trans.Read(io_buf.get(), io_buf->size(), callback.callback());
- if (rv == ERR_IO_PENDING)
- rv = callback.WaitForResult();
- EXPECT_EQ(3, rv);
- rv = trans.Read(io_buf.get(), io_buf->size(), callback.callback());
- EXPECT_EQ(0, rv);
- // There are still 0 idle sockets, since the trans_compete transaction
- // will be handed it immediately after trans releases it to the group.
- EXPECT_EQ(0u, transport_pool_ptr->IdleSocketCountInGroup(kSocketGroup));
- // The competing request can now finish. Wait for the headers and then
- // read the body.
- rv = callback_compete.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- rv = trans_compete.Read(io_buf.get(), io_buf->size(), callback.callback());
- if (rv == ERR_IO_PENDING)
- rv = callback.WaitForResult();
- EXPECT_EQ(3, rv);
- rv = trans_compete.Read(io_buf.get(), io_buf->size(), callback.callback());
- EXPECT_EQ(0, rv);
- // Finally, the socket is released to the group.
- EXPECT_EQ(1u, transport_pool_ptr->IdleSocketCountInGroup(kSocketGroup));
- }
- // This tests the case that a request is issued via http instead of spdy after
- // npn is negotiated.
- TEST_F(HttpNetworkTransactionTest, NpnWithHttpOverSSL) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead(kAlternativeServiceHttpHeader),
- MockRead("\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- }
- // Simulate the SSL handshake completing with a ALPN negotiation followed by an
- // immediate server closing of the socket.
- // Regression test for https://crbug.com/46369.
- TEST_F(HttpNetworkTransactionTest, SpdyPostALPNServerHangup) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
- MockWrite spdy_writes[] = {CreateMockWrite(req, 1)};
- MockRead spdy_reads[] = {
- MockRead(SYNCHRONOUS, 0, 0) // Not async - return 0 immediately.
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- TestCompletionCallback callback;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
- }
- // A subclass of HttpAuthHandlerMock that records the request URL when
- // it gets it. This is needed since the auth handler may get destroyed
- // before we get a chance to query it.
- class UrlRecordingHttpAuthHandlerMock : public HttpAuthHandlerMock {
- public:
- explicit UrlRecordingHttpAuthHandlerMock(GURL* url) : url_(url) {}
- ~UrlRecordingHttpAuthHandlerMock() override = default;
- protected:
- int GenerateAuthTokenImpl(const AuthCredentials* credentials,
- const HttpRequestInfo* request,
- CompletionOnceCallback callback,
- std::string* auth_token) override {
- *url_ = request->url;
- return HttpAuthHandlerMock::GenerateAuthTokenImpl(
- credentials, request, std::move(callback), auth_token);
- }
- private:
- raw_ptr<GURL> url_;
- };
- // Test that if we cancel the transaction as the connection is completing, that
- // everything tears down correctly.
- TEST_F(HttpNetworkTransactionTest, SimpleCancel) {
- // Setup everything about the connection to complete synchronously, so that
- // after calling HttpNetworkTransaction::Start, the only thing we're waiting
- // for is the callback from the HttpStreamRequest.
- // Then cancel the transaction.
- // Verify that we don't crash.
- MockConnect mock_connect(SYNCHRONOUS, OK);
- MockRead data_reads[] = {
- MockRead(SYNCHRONOUS, "HTTP/1.0 200 OK\r\n\r\n"),
- MockRead(SYNCHRONOUS, "hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- data.set_connect_data(mock_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- trans.reset(); // Cancel the transaction here.
- base::RunLoop().RunUntilIdle();
- }
- // Test that if a transaction is cancelled after receiving the headers, the
- // stream is drained properly and added back to the socket pool. The main
- // purpose of this test is to make sure that an HttpStreamParser can be read
- // from after the HttpNetworkTransaction and the objects it owns have been
- // deleted.
- // See http://crbug.com/368418
- TEST_F(HttpNetworkTransactionTest, CancelAfterHeaders) {
- MockRead data_reads[] = {
- MockRead(ASYNC, "HTTP/1.1 200 OK\r\n"),
- MockRead(ASYNC, "Content-Length: 2\r\n"),
- MockRead(ASYNC, "Connection: Keep-Alive\r\n\r\n"),
- MockRead(ASYNC, "1"),
- // 2 async reads are necessary to trigger a ReadResponseBody call after the
- // HttpNetworkTransaction has been deleted.
- MockRead(ASYNC, "2"),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING), // Should never read this.
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- callback.WaitForResult();
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- // The transaction and HttpRequestInfo are deleted.
- }
- // Let the HttpResponseBodyDrainer drain the socket.
- base::RunLoop().RunUntilIdle();
- // Socket should now be idle, waiting to be reused.
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- // Test a basic GET request through a proxy.
- TEST_F(HttpNetworkTransactionTest, ProxyGet) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes1[] = {
- MockWrite(
- "GET http://www.example.org/ HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- ConnectedHandler connected_handler;
- trans.SetConnectedCallback(connected_handler.Callback());
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(100, response->headers->GetContentLength());
- EXPECT_TRUE(response->was_fetched_via_proxy);
- EXPECT_EQ(ProxyServer(ProxyServer::SCHEME_HTTP,
- HostPortPair::FromString("myproxy:70")),
- response->proxy_server);
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- TransportInfo expected_transport;
- expected_transport.type = TransportType::kProxied;
- expected_transport.endpoint = IPEndPoint(IPAddress::IPv4Localhost(), 70);
- EXPECT_THAT(connected_handler.transports(), ElementsAre(expected_transport));
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- }
- // Test a basic HTTPS GET request through a proxy.
- TEST_F(HttpNetworkTransactionTest, ProxyTunnelGet) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- RecordingNetLogObserver net_log_observer;
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- ConnectedHandler connected_handler;
- trans.SetConnectedCallback(connected_handler.Callback());
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- auto entries = net_log_observer.GetEntries();
- size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLogEventPhase::NONE);
- ExpectLogContainsSomewhere(
- entries, pos,
- NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLogEventPhase::NONE);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(100, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(response->was_fetched_via_proxy);
- EXPECT_EQ(ProxyServer(ProxyServer::SCHEME_HTTP,
- HostPortPair::FromString("myproxy:70")),
- response->proxy_server);
- TransportInfo expected_transport;
- expected_transport.type = TransportType::kProxied;
- expected_transport.endpoint = IPEndPoint(IPAddress::IPv4Localhost(), 70);
- EXPECT_THAT(connected_handler.transports(), ElementsAre(expected_transport));
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_SSL_TIMES);
- }
- // Test a basic HTTPS GET request through a proxy, connecting to an IPv6
- // literal host.
- TEST_F(HttpNetworkTransactionTest, ProxyTunnelGetIPv6) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- RecordingNetLogObserver net_log_observer;
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://[::2]:443/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT [::2]:443 HTTP/1.1\r\n"
- "Host: [::2]:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: [::2]\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- auto entries = net_log_observer.GetEntries();
- size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLogEventPhase::NONE);
- ExpectLogContainsSomewhere(
- entries, pos,
- NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLogEventPhase::NONE);
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers->IsKeepAlive());
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(100, response->headers->GetContentLength());
- EXPECT_TRUE(HttpVersion(1, 1) == response->headers->GetHttpVersion());
- EXPECT_TRUE(response->was_fetched_via_proxy);
- EXPECT_EQ(ProxyServer(ProxyServer::SCHEME_HTTP,
- HostPortPair::FromString("myproxy:70")),
- response->proxy_server);
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans.GetLoadTimingInfo(&load_timing_info));
- TestLoadTimingNotReusedWithPac(load_timing_info,
- CONNECT_TIMING_HAS_SSL_TIMES);
- }
- // Test a basic HTTPS GET request through a proxy, but the server hangs up
- // while establishing the tunnel.
- TEST_F(HttpNetworkTransactionTest, ProxyTunnelGetHangup) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- RecordingNetLogObserver net_log_observer;
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- MockRead(ASYNC, 0, 0), // EOF
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_EMPTY_RESPONSE));
- auto entries = net_log_observer.GetEntries();
- size_t pos = ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_TUNNEL_HEADERS,
- NetLogEventPhase::NONE);
- ExpectLogContainsSomewhere(
- entries, pos,
- NetLogEventType::HTTP_TRANSACTION_READ_TUNNEL_RESPONSE_HEADERS,
- NetLogEventPhase::NONE);
- }
- // Test for crbug.com/55424.
- TEST_F(HttpNetworkTransactionTest, PreconnectWithExistingSpdySession) {
- spdy::SpdySerializedFrame req(
- spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
- MockWrite spdy_writes[] = {CreateMockWrite(req, 0)};
- spdy::SpdySerializedFrame resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame data(spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead spdy_reads[] = {
- CreateMockRead(resp, 1), CreateMockRead(data, 2), MockRead(ASYNC, 0, 3),
- };
- SequencedSocketData spdy_data(spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Set up an initial SpdySession in the pool to reuse.
- HostPortPair host_port_pair("www.example.org", 443);
- SpdySessionKey key(host_port_pair, ProxyServer::Direct(),
- PRIVACY_MODE_DISABLED,
- SpdySessionKey::IsProxySession::kFalse, SocketTag(),
- NetworkIsolationKey(), SecureDnsPolicy::kAllow);
- base::WeakPtr<SpdySession> spdy_session =
- CreateSpdySession(session.get(), key, NetLogWithSource());
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- }
- // Given a net error, cause that error to be returned from the first Write()
- // call and verify that the HttpNetworkTransaction fails with that error.
- void HttpNetworkTransactionTest::CheckErrorIsPassedBack(
- int error, IoMode mode) {
- HttpRequestInfo request_info;
- request_info.url = GURL("https://www.example.com/");
- request_info.method = "GET";
- request_info.load_flags = LOAD_NORMAL;
- request_info.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- SSLSocketDataProvider ssl_data(mode, OK);
- MockWrite data_writes[] = {
- MockWrite(mode, error),
- };
- StaticSocketDataProvider data(base::span<MockRead>(), data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request_info, callback.callback(), NetLogWithSource());
- if (rv == ERR_IO_PENDING)
- rv = callback.WaitForResult();
- ASSERT_EQ(error, rv);
- }
- TEST_F(HttpNetworkTransactionTest, SSLWriteCertError) {
- // Just check a grab bag of cert errors.
- static const int kErrors[] = {
- ERR_CERT_COMMON_NAME_INVALID,
- ERR_CERT_AUTHORITY_INVALID,
- ERR_CERT_DATE_INVALID,
- };
- for (int error : kErrors) {
- CheckErrorIsPassedBack(error, ASYNC);
- CheckErrorIsPassedBack(error, SYNCHRONOUS);
- }
- }
- // Ensure that a client certificate is removed from the SSL client auth
- // cache when:
- // 1) No proxy is involved.
- // 2) TLS False Start is disabled.
- // 3) The initial TLS handshake requests a client certificate.
- // 4) The client supplies an invalid/unacceptable certificate.
- TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Direct_NoFalseStart) {
- HttpRequestInfo request_info;
- request_info.url = GURL("https://www.example.com/");
- request_info.method = "GET";
- request_info.load_flags = LOAD_NORMAL;
- request_info.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto cert_request = base::MakeRefCounted<SSLCertRequestInfo>();
- cert_request->host_and_port = HostPortPair("www.example.com", 443);
- // [ssl_]data1 contains the data for the first SSL handshake. When a
- // CertificateRequest is received for the first time, the handshake will
- // be aborted to allow the caller to provide a certificate.
- SSLSocketDataProvider ssl_data1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
- ssl_data1.cert_request_info = cert_request.get();
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data1);
- StaticSocketDataProvider data1;
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- // [ssl_]data2 contains the data for the second SSL handshake. When TLS
- // False Start is not being used, the result of the SSL handshake will be
- // returned as part of the SSLClientSocket::Connect() call. This test
- // matches the result of a server sending a handshake_failure alert,
- // rather than a Finished message, because it requires a client
- // certificate and none was supplied.
- SSLSocketDataProvider ssl_data2(ASYNC, ERR_SSL_PROTOCOL_ERROR);
- ssl_data2.cert_request_info = cert_request.get();
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data2);
- StaticSocketDataProvider data2;
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- // [ssl_]data3 contains the data for the third SSL handshake. When a
- // connection to a server fails during an SSL handshake,
- // HttpNetworkTransaction will attempt to fallback with legacy cryptography
- // enabled on some errors. This is transparent to the caller
- // of the HttpNetworkTransaction. Because this test failure is due to
- // requiring a client certificate, this fallback handshake should also
- // fail.
- SSLSocketDataProvider ssl_data3(ASYNC, ERR_SSL_PROTOCOL_ERROR);
- ssl_data3.expected_disable_legacy_crypto = false;
- ssl_data3.cert_request_info = cert_request.get();
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data3);
- StaticSocketDataProvider data3;
- session_deps_.socket_factory->AddSocketDataProvider(&data3);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Begin the SSL handshake with the peer. This consumes ssl_data1.
- TestCompletionCallback callback;
- int rv = trans.Start(&request_info, callback.callback(), NetLogWithSource());
- ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
- // Complete the SSL handshake, which should abort due to requiring a
- // client certificate.
- rv = callback.WaitForResult();
- ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
- // Indicate that no certificate should be supplied. From the perspective
- // of SSLClientCertCache, NULL is just as meaningful as a real
- // certificate, so this is the same as supply a
- // legitimate-but-unacceptable certificate.
- rv = trans.RestartWithCertificate(nullptr, nullptr, callback.callback());
- ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
- // Ensure the certificate was added to the client auth cache before
- // allowing the connection to continue restarting.
- scoped_refptr<X509Certificate> client_cert;
- scoped_refptr<SSLPrivateKey> client_private_key;
- ASSERT_TRUE(session->ssl_client_context()->GetClientCertificate(
- HostPortPair("www.example.com", 443), &client_cert, &client_private_key));
- ASSERT_FALSE(client_cert);
- // Restart the handshake. This will consume ssl_data2, which fails, and
- // then consume ssl_data3 and ssl_data4, both of which should also fail.
- // The result code is checked against what ssl_data4 should return.
- rv = callback.WaitForResult();
- ASSERT_THAT(rv, IsError(ERR_SSL_PROTOCOL_ERROR));
- // Ensure that the client certificate is removed from the cache on a
- // handshake failure.
- ASSERT_FALSE(session->ssl_client_context()->GetClientCertificate(
- HostPortPair("www.example.com", 443), &client_cert, &client_private_key));
- }
- // Ensure that a client certificate is removed from the SSL client auth
- // cache when:
- // 1) No proxy is involved.
- // 2) TLS False Start is enabled.
- // 3) The initial TLS handshake requests a client certificate.
- // 4) The client supplies an invalid/unacceptable certificate.
- TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Direct_FalseStart) {
- HttpRequestInfo request_info;
- request_info.url = GURL("https://www.example.com/");
- request_info.method = "GET";
- request_info.load_flags = LOAD_NORMAL;
- request_info.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto cert_request = base::MakeRefCounted<SSLCertRequestInfo>();
- cert_request->host_and_port = HostPortPair("www.example.com", 443);
- // When TLS False Start is used, SSLClientSocket::Connect() calls will
- // return successfully after reading up to the peer's Certificate message.
- // This is to allow the caller to call SSLClientSocket::Write(), which can
- // enqueue application data to be sent in the same packet as the
- // ChangeCipherSpec and Finished messages.
- // The actual handshake will be finished when SSLClientSocket::Read() is
- // called, which expects to process the peer's ChangeCipherSpec and
- // Finished messages. If there was an error negotiating with the peer,
- // such as due to the peer requiring a client certificate when none was
- // supplied, the alert sent by the peer won't be processed until Read() is
- // called.
- // Like the non-False Start case, when a client certificate is requested by
- // the peer, the handshake is aborted during the Connect() call.
- // [ssl_]data1 represents the initial SSL handshake with the peer.
- SSLSocketDataProvider ssl_data1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
- ssl_data1.cert_request_info = cert_request.get();
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data1);
- StaticSocketDataProvider data1;
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- // When a client certificate is supplied, Connect() will not be aborted
- // when the peer requests the certificate. Instead, the handshake will
- // artificially succeed, allowing the caller to write the HTTP request to
- // the socket. The handshake messages are not processed until Read() is
- // called, which then detects that the handshake was aborted, due to the
- // peer sending a handshake_failure because it requires a client
- // certificate.
- SSLSocketDataProvider ssl_data2(ASYNC, OK);
- ssl_data2.cert_request_info = cert_request.get();
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data2);
- MockRead data2_reads[] = {
- MockRead(ASYNC /* async */, ERR_SSL_PROTOCOL_ERROR),
- };
- StaticSocketDataProvider data2(data2_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- // As described in ClientAuthCertCache_Direct_NoFalseStart, [ssl_]data3 is
- // the data for the SSL handshake once the TLSv1.1 connection falls back to
- // TLSv1. It has the same behaviour as [ssl_]data2.
- SSLSocketDataProvider ssl_data3(ASYNC, OK);
- ssl_data3.cert_request_info = cert_request.get();
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data3);
- StaticSocketDataProvider data3(data2_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data3);
- // [ssl_]data4 is the data for the SSL handshake once the TLSv1 connection
- // falls back to SSLv3. It has the same behaviour as [ssl_]data2.
- SSLSocketDataProvider ssl_data4(ASYNC, OK);
- ssl_data4.cert_request_info = cert_request.get();
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data4);
- StaticSocketDataProvider data4(data2_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data4);
- // Need one more if TLSv1.2 is enabled.
- SSLSocketDataProvider ssl_data5(ASYNC, OK);
- ssl_data5.cert_request_info = cert_request.get();
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data5);
- StaticSocketDataProvider data5(data2_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data5);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Begin the initial SSL handshake.
- TestCompletionCallback callback;
- int rv = trans.Start(&request_info, callback.callback(), NetLogWithSource());
- ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
- // Complete the SSL handshake, which should abort due to requiring a
- // client certificate.
- rv = callback.WaitForResult();
- ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
- // Indicate that no certificate should be supplied. From the perspective
- // of SSLClientCertCache, NULL is just as meaningful as a real
- // certificate, so this is the same as supply a
- // legitimate-but-unacceptable certificate.
- rv = trans.RestartWithCertificate(nullptr, nullptr, callback.callback());
- ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
- // Ensure the certificate was added to the client auth cache before
- // allowing the connection to continue restarting.
- scoped_refptr<X509Certificate> client_cert;
- scoped_refptr<SSLPrivateKey> client_private_key;
- ASSERT_TRUE(session->ssl_client_context()->GetClientCertificate(
- HostPortPair("www.example.com", 443), &client_cert, &client_private_key));
- ASSERT_FALSE(client_cert);
- // Restart the handshake. This will consume ssl_data2, which fails, and
- // then consume ssl_data3 and ssl_data4, both of which should also fail.
- // The result code is checked against what ssl_data4 should return.
- rv = callback.WaitForResult();
- ASSERT_THAT(rv, IsError(ERR_SSL_PROTOCOL_ERROR));
- // Ensure that the client certificate is removed from the cache on a
- // handshake failure.
- ASSERT_FALSE(session->ssl_client_context()->GetClientCertificate(
- HostPortPair("www.example.com", 443), &client_cert, &client_private_key));
- }
- // Ensure that a client certificate is removed from the SSL client auth
- // cache when:
- // 1) An HTTPS proxy is involved.
- // 3) The HTTPS proxy requests a client certificate.
- // 4) The client supplies an invalid/unacceptable certificate for the
- // proxy.
- TEST_F(HttpNetworkTransactionTest, ClientAuthCertCache_Proxy_Fail) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = NetLog::Get();
- auto cert_request = base::MakeRefCounted<SSLCertRequestInfo>();
- cert_request->host_and_port = HostPortPair("proxy", 70);
- // Repeat the test for connecting to an HTTPS endpoint, then for connecting to
- // an HTTP endpoint.
- HttpRequestInfo requests[2];
- requests[0].url = GURL("https://www.example.com/");
- requests[0].method = "GET";
- requests[0].load_flags = LOAD_NORMAL;
- requests[0].traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // HTTPS requests are tunneled.
- MockWrite https_writes[] = {
- MockWrite("CONNECT www.example.com:443 HTTP/1.1\r\n"
- "Host: www.example.com:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- requests[1].url = GURL("http://www.example.com/");
- requests[1].method = "GET";
- requests[1].load_flags = LOAD_NORMAL;
- requests[1].traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // HTTP requests are not.
- MockWrite http_writes[] = {
- MockWrite("GET http://www.example.com/ HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // When the server rejects the client certificate, it will close the
- // connection. In TLS 1.2, this is signaled out of Connect(). In TLS 1.3 (or
- // TLS 1.2 with False Start), the error is returned out of the first Read().
- for (bool reject_in_connect : {true, false}) {
- SCOPED_TRACE(reject_in_connect);
- // Client certificate errors are typically signaled with
- // ERR_BAD_SSL_CLIENT_AUTH_CERT, but sometimes the server gives an arbitrary
- // protocol error.
- for (Error reject_error :
- {ERR_SSL_PROTOCOL_ERROR, ERR_BAD_SSL_CLIENT_AUTH_CERT}) {
- SCOPED_TRACE(reject_error);
- // Tunneled and non-tunneled requests are handled differently. Test both.
- for (const HttpRequestInfo& request : requests) {
- SCOPED_TRACE(request.url);
- session_deps_.socket_factory =
- std::make_unique<MockClientSocketFactory>();
- // See ClientAuthCertCache_Direct_NoFalseStart for the explanation of
- // [ssl_]data[1-3].
- SSLSocketDataProvider ssl_data1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
- ssl_data1.cert_request_info = cert_request.get();
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data1);
- StaticSocketDataProvider data1;
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- absl::optional<SSLSocketDataProvider> ssl_data2;
- absl::optional<StaticSocketDataProvider> data2;
- MockRead error_in_read[] = {MockRead(ASYNC, reject_error)};
- if (reject_in_connect) {
- ssl_data2.emplace(ASYNC, reject_error);
- // There are no reads or writes.
- data2.emplace();
- } else {
- ssl_data2.emplace(ASYNC, OK);
- // We will get one Write() in before observing the error in Read().
- if (request.url.SchemeIsCryptographic()) {
- data2.emplace(error_in_read, https_writes);
- } else {
- data2.emplace(error_in_read, http_writes);
- }
- }
- ssl_data2->cert_request_info = cert_request.get();
- session_deps_.socket_factory->AddSSLSocketDataProvider(
- &ssl_data2.value());
- session_deps_.socket_factory->AddSocketDataProvider(&data2.value());
- // If the handshake returns ERR_SSL_PROTOCOL_ERROR, we attempt to
- // connect twice.
- absl::optional<SSLSocketDataProvider> ssl_data3;
- absl::optional<StaticSocketDataProvider> data3;
- if (reject_in_connect && reject_error == ERR_SSL_PROTOCOL_ERROR) {
- ssl_data3.emplace(ASYNC, reject_error);
- data3.emplace(); // There are no reads or writes.
- ssl_data3->cert_request_info = cert_request.get();
- session_deps_.socket_factory->AddSSLSocketDataProvider(
- &ssl_data3.value());
- session_deps_.socket_factory->AddSocketDataProvider(&data3.value());
- }
- std::unique_ptr<HttpNetworkSession> session =
- CreateSession(&session_deps_);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Begin the SSL handshake with the proxy.
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
- // Complete the SSL handshake, which should abort due to requiring a
- // client certificate.
- rv = callback.WaitForResult();
- ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
- // Indicate that no certificate should be supplied. From the
- // perspective of SSLClientCertCache, NULL is just as meaningful as a
- // real certificate, so this is the same as supply a
- // legitimate-but-unacceptable certificate.
- rv =
- trans.RestartWithCertificate(nullptr, nullptr, callback.callback());
- ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
- // Ensure the certificate was added to the client auth cache before
- // allowing the connection to continue restarting.
- scoped_refptr<X509Certificate> client_cert;
- scoped_refptr<SSLPrivateKey> client_private_key;
- ASSERT_TRUE(session->ssl_client_context()->GetClientCertificate(
- HostPortPair("proxy", 70), &client_cert, &client_private_key));
- ASSERT_FALSE(client_cert);
- // Ensure the certificate was NOT cached for the endpoint. This only
- // applies to HTTPS requests, but is fine to check for HTTP requests.
- ASSERT_FALSE(session->ssl_client_context()->GetClientCertificate(
- HostPortPair("www.example.com", 443), &client_cert,
- &client_private_key));
- // Restart the handshake. This will consume ssl_data2. The result code
- // is checked against what ssl_data2 should return.
- rv = callback.WaitForResult();
- ASSERT_THAT(rv, AnyOf(IsError(ERR_PROXY_CONNECTION_FAILED),
- IsError(reject_error)));
- // Now that the new handshake has failed, ensure that the client
- // certificate was removed from the client auth cache.
- ASSERT_FALSE(session->ssl_client_context()->GetClientCertificate(
- HostPortPair("proxy", 70), &client_cert, &client_private_key));
- ASSERT_FALSE(session->ssl_client_context()->GetClientCertificate(
- HostPortPair("www.example.com", 443), &client_cert,
- &client_private_key));
- }
- }
- }
- }
- // Test that HttpNetworkTransaction correctly handles (mocked) certificate
- // requests during a TLS renegotiation.
- TEST_F(HttpNetworkTransactionTest, CertificateRequestInRenego) {
- HttpRequestInfo request_info;
- request_info.url = GURL("https://www.example.com/");
- request_info.method = "GET";
- request_info.load_flags = LOAD_NORMAL;
- request_info.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto cert_request = base::MakeRefCounted<SSLCertRequestInfo>();
- cert_request->host_and_port = HostPortPair("www.example.com", 443);
- std::unique_ptr<FakeClientCertIdentity> identity =
- FakeClientCertIdentity::CreateFromCertAndKeyFiles(
- GetTestCertsDirectory(), "client_1.pem", "client_1.pk8");
- ASSERT_TRUE(identity);
- // The first connection's handshake succeeds, but we get
- // ERR_SSL_CLIENT_AUTH_CERT_NEEDED instead of an HTTP response.
- SSLSocketDataProvider ssl_data1(ASYNC, OK);
- ssl_data1.cert_request_info = cert_request.get();
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data1);
- MockWrite data1_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data1_reads[] = {
- MockRead(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED),
- };
- StaticSocketDataProvider data1(data1_reads, data1_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- // After supplying with certificate, we restart the request from the top,
- // which succeeds this time.
- SSLSocketDataProvider ssl_data2(ASYNC, OK);
- ssl_data2.expected_send_client_cert = true;
- ssl_data2.expected_client_cert = identity->certificate();
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data2);
- MockWrite data2_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data2_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Content-Length: 0\r\n\r\n"),
- };
- StaticSocketDataProvider data2(data2_reads, data2_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = callback.GetResult(
- trans.Start(&request_info, callback.callback(), NetLogWithSource()));
- ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
- rv = trans.RestartWithCertificate(identity->certificate(),
- identity->ssl_private_key(),
- callback.callback());
- ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
- // Ensure the certificate was added to the client auth cache
- // allowing the connection to continue restarting.
- scoped_refptr<X509Certificate> client_cert;
- scoped_refptr<SSLPrivateKey> client_private_key;
- ASSERT_TRUE(session->ssl_client_context()->GetClientCertificate(
- HostPortPair("www.example.com", 443), &client_cert, &client_private_key));
- EXPECT_TRUE(client_cert->EqualsIncludingChain(identity->certificate()));
- // Complete the handshake. The request now succeeds.
- rv = callback.WaitForResult();
- ASSERT_THAT(rv, IsError(OK));
- EXPECT_EQ(200, trans.GetResponseInfo()->headers->response_code());
- // The client certificate remains in the cache.
- ASSERT_TRUE(session->ssl_client_context()->GetClientCertificate(
- HostPortPair("www.example.com", 443), &client_cert, &client_private_key));
- EXPECT_TRUE(client_cert->EqualsIncludingChain(identity->certificate()));
- }
- TEST_F(HttpNetworkTransactionTest, UseIPConnectionPooling) {
- // Set up a special HttpNetworkSession with a MockCachingHostResolver.
- session_deps_.host_resolver = std::make_unique<MockCachingHostResolver>();
- session_deps_.host_resolver->rules()->AddRule("www.example.org", "1.2.3.4");
- session_deps_.host_resolver->rules()->AddRule("mail.example.com", "1.2.3.4");
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- AddSSLSocketData();
- spdy::SpdySerializedFrame host1_req(
- spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
- spdy_util_.UpdateWithStreamDestruction(1);
- spdy::SpdySerializedFrame host2_req(
- spdy_util_.ConstructSpdyGet("https://mail.example.com", 3, LOWEST));
- MockWrite spdy_writes[] = {
- CreateMockWrite(host1_req, 0), CreateMockWrite(host2_req, 3),
- };
- spdy::SpdySerializedFrame host1_resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame host1_resp_body(
- spdy_util_.ConstructSpdyDataFrame(1, true));
- spdy::SpdySerializedFrame host2_resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
- spdy::SpdySerializedFrame host2_resp_body(
- spdy_util_.ConstructSpdyDataFrame(3, true));
- MockRead spdy_reads[] = {
- CreateMockRead(host1_resp, 1), CreateMockRead(host1_resp_body, 2),
- CreateMockRead(host2_resp, 4), CreateMockRead(host2_resp_body, 5),
- MockRead(ASYNC, 0, 6),
- };
- IPEndPoint peer_addr(IPAddress::IPv4Localhost(), 443);
- MockConnect connect(ASYNC, OK, peer_addr);
- SequencedSocketData spdy_data(connect, spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- TestCompletionCallback callback;
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://www.example.org/");
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get());
- int rv = trans1.Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans1.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans1, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- // Preload mail.example.com into HostCache.
- rv = session_deps_.host_resolver->LoadIntoCache(
- HostPortPair("mail.example.com", 443), NetworkIsolationKey(),
- absl::nullopt);
- EXPECT_THAT(rv, IsOk());
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://mail.example.com/");
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- rv = trans2.Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- response = trans2.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- ASSERT_THAT(ReadTransaction(&trans2, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- }
- TEST_F(HttpNetworkTransactionTest, UseIPConnectionPoolingAfterResolution) {
- // Set up a special HttpNetworkSession with a MockCachingHostResolver.
- session_deps_.host_resolver = std::make_unique<MockCachingHostResolver>();
- session_deps_.host_resolver->rules()->AddRule("www.example.org", "1.2.3.4");
- session_deps_.host_resolver->rules()->AddRule("mail.example.com", "1.2.3.4");
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- AddSSLSocketData();
- spdy::SpdySerializedFrame host1_req(
- spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
- spdy_util_.UpdateWithStreamDestruction(1);
- spdy::SpdySerializedFrame host2_req(
- spdy_util_.ConstructSpdyGet("https://mail.example.com", 3, LOWEST));
- MockWrite spdy_writes[] = {
- CreateMockWrite(host1_req, 0), CreateMockWrite(host2_req, 3),
- };
- spdy::SpdySerializedFrame host1_resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame host1_resp_body(
- spdy_util_.ConstructSpdyDataFrame(1, true));
- spdy::SpdySerializedFrame host2_resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
- spdy::SpdySerializedFrame host2_resp_body(
- spdy_util_.ConstructSpdyDataFrame(3, true));
- MockRead spdy_reads[] = {
- CreateMockRead(host1_resp, 1), CreateMockRead(host1_resp_body, 2),
- CreateMockRead(host2_resp, 4), CreateMockRead(host2_resp_body, 5),
- MockRead(ASYNC, 0, 6),
- };
- IPEndPoint peer_addr(IPAddress::IPv4Localhost(), 443);
- MockConnect connect(ASYNC, OK, peer_addr);
- SequencedSocketData spdy_data(connect, spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- TestCompletionCallback callback;
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://www.example.org/");
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get());
- int rv = trans1.Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans1.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans1, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://mail.example.com/");
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- rv = trans2.Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- response = trans2.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- ASSERT_THAT(ReadTransaction(&trans2, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- }
- // Regression test for https://crbug.com/546991.
- // The server might not be able to serve an IP pooled request, and might send a
- // 421 Misdirected Request response status to indicate this.
- // HttpNetworkTransaction should reset the request and retry without IP pooling.
- TEST_F(HttpNetworkTransactionTest, RetryWithoutConnectionPooling) {
- // Two hosts resolve to the same IP address.
- const std::string ip_addr = "1.2.3.4";
- IPAddress ip;
- ASSERT_TRUE(ip.AssignFromIPLiteral(ip_addr));
- IPEndPoint peer_addr = IPEndPoint(ip, 443);
- session_deps_.host_resolver = std::make_unique<MockCachingHostResolver>();
- session_deps_.host_resolver->rules()->AddRule("www.example.org", ip_addr);
- session_deps_.host_resolver->rules()->AddRule("mail.example.org", ip_addr);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Two requests on the first connection.
- spdy::SpdySerializedFrame req1(
- spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
- spdy_util_.UpdateWithStreamDestruction(1);
- spdy::SpdySerializedFrame req2(
- spdy_util_.ConstructSpdyGet("https://mail.example.org", 3, LOWEST));
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(3, spdy::ERROR_CODE_CANCEL));
- MockWrite writes1[] = {
- CreateMockWrite(req1, 0), CreateMockWrite(req2, 3),
- CreateMockWrite(rst, 6),
- };
- // The first one succeeds, the second gets error 421 Misdirected Request.
- spdy::SpdySerializedFrame resp1(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
- spdy::Http2HeaderBlock response_headers;
- response_headers[spdy::kHttp2StatusHeader] = "421";
- spdy::SpdySerializedFrame resp2(
- spdy_util_.ConstructSpdyReply(3, std::move(response_headers)));
- MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
- CreateMockRead(resp2, 4), MockRead(ASYNC, 0, 5)};
- MockConnect connect1(ASYNC, OK, peer_addr);
- SequencedSocketData data1(connect1, reads1, writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- AddSSLSocketData();
- // Retry the second request on a second connection.
- SpdyTestUtil spdy_util2;
- spdy::SpdySerializedFrame req3(
- spdy_util2.ConstructSpdyGet("https://mail.example.org", 1, LOWEST));
- MockWrite writes2[] = {
- CreateMockWrite(req3, 0),
- };
- spdy::SpdySerializedFrame resp3(
- spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame body3(spdy_util2.ConstructSpdyDataFrame(1, true));
- MockRead reads2[] = {CreateMockRead(resp3, 1), CreateMockRead(body3, 2),
- MockRead(ASYNC, 0, 3)};
- MockConnect connect2(ASYNC, OK, peer_addr);
- SequencedSocketData data2(connect2, reads2, writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- AddSSLSocketData();
- // Preload mail.example.org into HostCache.
- int rv = session_deps_.host_resolver->LoadIntoCache(
- HostPortPair("mail.example.org", 443), NetworkIsolationKey(),
- absl::nullopt);
- EXPECT_THAT(rv, IsOk());
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://www.example.org/");
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- rv = trans1.Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans1.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans1, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://mail.example.org/");
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- RecordingNetLogObserver net_log_observer;
- rv = trans2.Start(&request2, callback.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- response = trans2.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- ASSERT_THAT(ReadTransaction(&trans2, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- auto entries = net_log_observer.GetEntries();
- ExpectLogContainsSomewhere(
- entries, 0, NetLogEventType::HTTP_TRANSACTION_RESTART_MISDIRECTED_REQUEST,
- NetLogEventPhase::NONE);
- }
- // Test that HTTP 421 responses are properly returned to the caller if received
- // on the retry as well. HttpNetworkTransaction should not infinite loop or lose
- // portions of the response.
- TEST_F(HttpNetworkTransactionTest, ReturnHTTP421OnRetry) {
- // Two hosts resolve to the same IP address.
- const std::string ip_addr = "1.2.3.4";
- IPAddress ip;
- ASSERT_TRUE(ip.AssignFromIPLiteral(ip_addr));
- IPEndPoint peer_addr = IPEndPoint(ip, 443);
- session_deps_.host_resolver = std::make_unique<MockCachingHostResolver>();
- session_deps_.host_resolver->rules()->AddRule("www.example.org", ip_addr);
- session_deps_.host_resolver->rules()->AddRule("mail.example.org", ip_addr);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Two requests on the first connection.
- spdy::SpdySerializedFrame req1(
- spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
- spdy_util_.UpdateWithStreamDestruction(1);
- spdy::SpdySerializedFrame req2(
- spdy_util_.ConstructSpdyGet("https://mail.example.org", 3, LOWEST));
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(3, spdy::ERROR_CODE_CANCEL));
- MockWrite writes1[] = {
- CreateMockWrite(req1, 0), CreateMockWrite(req2, 3),
- CreateMockWrite(rst, 6),
- };
- // The first one succeeds, the second gets error 421 Misdirected Request.
- spdy::SpdySerializedFrame resp1(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
- spdy::Http2HeaderBlock response_headers;
- response_headers[spdy::kHttp2StatusHeader] = "421";
- spdy::SpdySerializedFrame resp2(
- spdy_util_.ConstructSpdyReply(3, response_headers.Clone()));
- MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
- CreateMockRead(resp2, 4), MockRead(ASYNC, 0, 5)};
- MockConnect connect1(ASYNC, OK, peer_addr);
- SequencedSocketData data1(connect1, reads1, writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- AddSSLSocketData();
- // Retry the second request on a second connection. It returns 421 Misdirected
- // Retry again.
- SpdyTestUtil spdy_util2;
- spdy::SpdySerializedFrame req3(
- spdy_util2.ConstructSpdyGet("https://mail.example.org", 1, LOWEST));
- MockWrite writes2[] = {
- CreateMockWrite(req3, 0),
- };
- spdy::SpdySerializedFrame resp3(
- spdy_util2.ConstructSpdyReply(1, std::move(response_headers)));
- spdy::SpdySerializedFrame body3(spdy_util2.ConstructSpdyDataFrame(1, true));
- MockRead reads2[] = {CreateMockRead(resp3, 1), CreateMockRead(body3, 2),
- MockRead(ASYNC, 0, 3)};
- MockConnect connect2(ASYNC, OK, peer_addr);
- SequencedSocketData data2(connect2, reads2, writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- AddSSLSocketData();
- // Preload mail.example.org into HostCache.
- int rv = session_deps_.host_resolver->LoadIntoCache(
- HostPortPair("mail.example.org", 443), NetworkIsolationKey(),
- absl::nullopt);
- EXPECT_THAT(rv, IsOk());
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://www.example.org/");
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- rv = trans1.Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans1.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans1, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://mail.example.org/");
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- rv = trans2.Start(&request2, callback.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- // After a retry, the 421 Misdirected Request is reported back up to the
- // caller.
- response = trans2.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 421", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- EXPECT_TRUE(response->ssl_info.cert);
- ASSERT_THAT(ReadTransaction(&trans2, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- }
- TEST_F(HttpNetworkTransactionTest,
- Response421WithStreamingBodyWithNonNullSource) {
- const std::string ip_addr = "1.2.3.4";
- IPAddress ip;
- ASSERT_TRUE(ip.AssignFromIPLiteral(ip_addr));
- IPEndPoint peer_addr = IPEndPoint(ip, 443);
- session_deps_.host_resolver = std::make_unique<MockCachingHostResolver>();
- session_deps_.host_resolver->rules()->AddRule("www.example.org", ip_addr);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- const std::string request_body = "hello";
- spdy::SpdySerializedFrame req1 = spdy_util_.ConstructChunkedSpdyPost({}, 0);
- spdy::SpdySerializedFrame req1_body =
- spdy_util_.ConstructSpdyDataFrame(1, request_body, /*fin=*/true);
- spdy::SpdySerializedFrame rst =
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL);
- MockWrite writes1[] = {
- CreateMockWrite(req1, 0),
- CreateMockWrite(req1_body, 1),
- CreateMockWrite(rst, 4),
- };
- spdy::Http2HeaderBlock response_headers;
- response_headers[spdy::kHttp2StatusHeader] = "421";
- spdy::SpdySerializedFrame resp1 =
- spdy_util_.ConstructSpdyReply(1, std::move(response_headers));
- MockRead reads1[] = {CreateMockRead(resp1, 2), MockRead(ASYNC, 0, 3)};
- MockConnect connect1(ASYNC, OK, peer_addr);
- SequencedSocketData data1(connect1, reads1, writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- AddSSLSocketData();
- SpdyTestUtil spdy_util2;
- spdy::SpdySerializedFrame req2 = spdy_util2.ConstructChunkedSpdyPost({}, 0);
- spdy::SpdySerializedFrame req2_body =
- spdy_util2.ConstructSpdyDataFrame(1, request_body, /*fin=*/true);
- MockWrite writes2[] = {
- CreateMockWrite(req2, 0),
- CreateMockWrite(req2_body, 1),
- };
- spdy::Http2HeaderBlock resp2_headers;
- resp2_headers[spdy::kHttp2StatusHeader] = "200";
- spdy::SpdySerializedFrame resp2 =
- spdy_util2.ConstructSpdyReply(1, std::move(resp2_headers));
- spdy::SpdySerializedFrame resp2_body(
- spdy_util2.ConstructSpdyDataFrame(1, true));
- MockRead reads2[] = {CreateMockRead(resp2, 2), CreateMockRead(resp2_body, 3),
- MockRead(ASYNC, 0, 4)};
- MockConnect connect2(ASYNC, OK, peer_addr);
- SequencedSocketData data2(connect2, reads2, writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- AddSSLSocketData();
- TestCompletionCallback callback;
- HttpRequestInfo request;
- ChunkedUploadDataStream upload_data_stream(0, /*has_null_source=*/false);
- upload_data_stream.AppendData(request_body.data(), request_body.size(),
- /*is_done=*/true);
- request.method = "POST";
- request.url = GURL("https://www.example.org");
- request.load_flags = 0;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request.upload_data_stream = &upload_data_stream;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- std::string response_data;
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- EXPECT_TRUE(response->ssl_info.cert);
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- }
- TEST_F(HttpNetworkTransactionTest, Response421WithStreamingBodyWithNullSource) {
- const std::string ip_addr = "1.2.3.4";
- IPAddress ip;
- ASSERT_TRUE(ip.AssignFromIPLiteral(ip_addr));
- IPEndPoint peer_addr = IPEndPoint(ip, 443);
- session_deps_.host_resolver = std::make_unique<MockCachingHostResolver>();
- session_deps_.host_resolver->rules()->AddRule("www.example.org", ip_addr);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- const std::string request_body = "hello";
- spdy::SpdySerializedFrame req1 = spdy_util_.ConstructChunkedSpdyPost({}, 0);
- spdy::SpdySerializedFrame req1_body =
- spdy_util_.ConstructSpdyDataFrame(1, request_body, /*fin=*/true);
- spdy::SpdySerializedFrame rst =
- spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL);
- MockWrite writes1[] = {
- CreateMockWrite(req1, 0),
- CreateMockWrite(req1_body, 1),
- CreateMockWrite(rst, 5),
- };
- spdy::Http2HeaderBlock response_headers;
- response_headers[spdy::kHttp2StatusHeader] = "421";
- spdy::SpdySerializedFrame resp1 =
- spdy_util_.ConstructSpdyReply(1, std::move(response_headers));
- spdy::SpdySerializedFrame resp1_body(
- spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead reads1[] = {CreateMockRead(resp1, 2), CreateMockRead(resp1_body, 3),
- MockRead(ASYNC, 0, 4)};
- MockConnect connect1(ASYNC, OK, peer_addr);
- SequencedSocketData data1(connect1, reads1, writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- AddSSLSocketData();
- TestCompletionCallback callback;
- HttpRequestInfo request;
- ChunkedUploadDataStream upload_data_stream(0, /*has_null_source=*/true);
- upload_data_stream.AppendData(request_body.data(), request_body.size(),
- /*is_done=*/true);
- request.method = "POST";
- request.url = GURL("https://www.example.org");
- request.load_flags = 0;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request.upload_data_stream = &upload_data_stream;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- std::string response_data;
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 421", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- EXPECT_TRUE(response->ssl_info.cert);
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- }
- TEST_F(HttpNetworkTransactionTest,
- UseIPConnectionPoolingWithHostCacheExpiration) {
- // Set up HostResolver to invalidate cached entries after 1 cached resolve.
- session_deps_.host_resolver =
- std::make_unique<MockCachingHostResolver>(1 /* cache_invalidation_num */);
- session_deps_.host_resolver->rules()->AddRule("www.example.org", "1.2.3.4");
- session_deps_.host_resolver->rules()->AddRule("mail.example.com", "1.2.3.4");
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- AddSSLSocketData();
- spdy::SpdySerializedFrame host1_req(
- spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
- spdy_util_.UpdateWithStreamDestruction(1);
- spdy::SpdySerializedFrame host2_req(
- spdy_util_.ConstructSpdyGet("https://mail.example.com", 3, LOWEST));
- MockWrite spdy_writes[] = {
- CreateMockWrite(host1_req, 0), CreateMockWrite(host2_req, 3),
- };
- spdy::SpdySerializedFrame host1_resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame host1_resp_body(
- spdy_util_.ConstructSpdyDataFrame(1, true));
- spdy::SpdySerializedFrame host2_resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
- spdy::SpdySerializedFrame host2_resp_body(
- spdy_util_.ConstructSpdyDataFrame(3, true));
- MockRead spdy_reads[] = {
- CreateMockRead(host1_resp, 1), CreateMockRead(host1_resp_body, 2),
- CreateMockRead(host2_resp, 4), CreateMockRead(host2_resp_body, 5),
- MockRead(ASYNC, 0, 6),
- };
- IPEndPoint peer_addr(IPAddress::IPv4Localhost(), 443);
- MockConnect connect(ASYNC, OK, peer_addr);
- SequencedSocketData spdy_data(connect, spdy_reads, spdy_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy_data);
- TestCompletionCallback callback;
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://www.example.org/");
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get());
- int rv = trans1.Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans1.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans1, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- // Preload cache entries into HostCache.
- rv = session_deps_.host_resolver->LoadIntoCache(
- HostPortPair("mail.example.com", 443), NetworkIsolationKey(),
- absl::nullopt);
- EXPECT_THAT(rv, IsOk());
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://mail.example.com/");
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- rv = trans2.Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- response = trans2.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- ASSERT_THAT(ReadTransaction(&trans2, &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- }
- TEST_F(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttp) {
- const std::string https_url = "https://www.example.org:8080/";
- const std::string http_url = "http://www.example.org:8080/";
- // SPDY GET for HTTPS URL
- spdy::SpdySerializedFrame req1(
- spdy_util_.ConstructSpdyGet(https_url.c_str(), 1, LOWEST));
- MockWrite writes1[] = {
- CreateMockWrite(req1, 0),
- };
- spdy::SpdySerializedFrame resp1(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
- SequencedSocketData data1(reads1, writes1);
- MockConnect connect_data1(ASYNC, OK);
- data1.set_connect_data(connect_data1);
- // HTTP GET for the HTTP URL
- MockWrite writes2[] = {
- MockWrite(ASYNC, 0,
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org:8080\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead reads2[] = {
- MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
- MockRead(ASYNC, 2, "hello"),
- MockRead(ASYNC, OK, 3),
- };
- SequencedSocketData data2(reads2, writes2);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Start the first transaction to set up the SpdySession
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL(https_url);
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans1(LOWEST, session.get());
- TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING,
- trans1.Start(&request1, callback1.callback(), NetLogWithSource()));
- base::RunLoop().RunUntilIdle();
- EXPECT_THAT(callback1.WaitForResult(), IsOk());
- EXPECT_TRUE(trans1.GetResponseInfo()->was_fetched_via_spdy);
- // Now, start the HTTP request
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL(http_url);
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans2(MEDIUM, session.get());
- TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING,
- trans2.Start(&request2, callback2.callback(), NetLogWithSource()));
- base::RunLoop().RunUntilIdle();
- EXPECT_THAT(callback2.WaitForResult(), IsOk());
- EXPECT_FALSE(trans2.GetResponseInfo()->was_fetched_via_spdy);
- }
- // Alternative service requires HTTP/2 (or SPDY), but HTTP/1.1 is negotiated
- // with the alternative server. That connection should not be used.
- TEST_F(HttpNetworkTransactionTest, AlternativeServiceNotOnHttp11) {
- url::SchemeHostPort server("https", "www.example.org", 443);
- HostPortPair alternative("www.example.org", 444);
- // Negotiate HTTP/1.1 with alternative.
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- // No data should be read from the alternative, because HTTP/1.1 is
- // negotiated.
- StaticSocketDataProvider data;
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- // This test documents that an alternate Job should not be used if HTTP/1.1 is
- // negotiated. In order to test this, a failed connection to the server is
- // mocked. This way the request relies on the alternate Job.
- StaticSocketDataProvider data_refused;
- data_refused.set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_REFUSED));
- session_deps_.socket_factory->AddSocketDataProvider(&data_refused);
- // Set up alternative service for server.
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- AlternativeService alternative_service(kProtoHTTP2, alternative);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetHttp2AlternativeService(
- server, NetworkIsolationKey(), alternative_service, expiration);
- HttpRequestInfo request;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- request.method = "GET";
- request.url = GURL("https://www.example.org:443");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- TestCompletionCallback callback;
- // HTTP/2 (or SPDY) is required for alternative service, if HTTP/1.1 is
- // negotiated, the alternate Job should fail with ERR_ALPN_NEGOTIATION_FAILED.
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_ALPN_NEGOTIATION_FAILED));
- }
- // A request to a server with an alternative service fires two Jobs: one to the
- // server, and an alternate one to the alternative server. If the former
- // succeeds, the request should succeed, even if the latter fails because
- // HTTP/1.1 is negotiated which is insufficient for alternative service.
- TEST_F(HttpNetworkTransactionTest, FailedAlternativeServiceIsNotUserVisible) {
- url::SchemeHostPort server("https", "www.example.org", 443);
- HostPortPair alternative("www.example.org", 444);
- // Negotiate HTTP/1.1 with alternative.
- SSLSocketDataProvider alternative_ssl(ASYNC, OK);
- alternative_ssl.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&alternative_ssl);
- // No data should be read from the alternative, because HTTP/1.1 is
- // negotiated.
- StaticSocketDataProvider data;
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- // Negotiate HTTP/1.1 with server.
- SSLSocketDataProvider origin_ssl(ASYNC, OK);
- origin_ssl.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&origin_ssl);
- MockWrite http_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- MockWrite("GET /second HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html\r\n"),
- MockRead("Content-Length: 6\r\n\r\n"),
- MockRead("foobar"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html\r\n"),
- MockRead("Content-Length: 7\r\n\r\n"),
- MockRead("another"),
- };
- StaticSocketDataProvider http_data(http_reads, http_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&http_data);
- // Set up alternative service for server.
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- AlternativeService alternative_service(kProtoHTTP2, alternative);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetHttp2AlternativeService(
- server, NetworkIsolationKey(), alternative_service, expiration);
- HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get());
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://www.example.org:443");
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- TestCompletionCallback callback1;
- int rv = trans1.Start(&request1, callback1.callback(), NetLogWithSource());
- rv = callback1.GetResult(rv);
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response1 = trans1.GetResponseInfo();
- ASSERT_TRUE(response1);
- ASSERT_TRUE(response1->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response1->headers->GetStatusLine());
- std::string response_data1;
- ASSERT_THAT(ReadTransaction(&trans1, &response_data1), IsOk());
- EXPECT_EQ("foobar", response_data1);
- // Alternative should be marked as broken, because HTTP/1.1 is not sufficient
- // for alternative service.
- EXPECT_TRUE(http_server_properties->IsAlternativeServiceBroken(
- alternative_service, NetworkIsolationKey()));
- // Since |alternative_service| is broken, a second transaction to server
- // should not start an alternate Job. It should pool to existing connection
- // to server.
- HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://www.example.org:443/second");
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- TestCompletionCallback callback2;
- rv = trans2.Start(&request2, callback2.callback(), NetLogWithSource());
- rv = callback2.GetResult(rv);
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response2 = trans2.GetResponseInfo();
- ASSERT_TRUE(response2);
- ASSERT_TRUE(response2->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response2->headers->GetStatusLine());
- std::string response_data2;
- ASSERT_THAT(ReadTransaction(&trans2, &response_data2), IsOk());
- EXPECT_EQ("another", response_data2);
- }
- // Alternative service requires HTTP/2 (or SPDY), but there is already a
- // HTTP/1.1 socket open to the alternative server. That socket should not be
- // used.
- TEST_F(HttpNetworkTransactionTest, AlternativeServiceShouldNotPoolToHttp11) {
- url::SchemeHostPort server("https", "origin.example.org", 443);
- HostPortPair alternative("alternative.example.org", 443);
- std::string origin_url = "https://origin.example.org:443";
- std::string alternative_url = "https://alternative.example.org:443";
- // Negotiate HTTP/1.1 with alternative.example.org.
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.next_proto = kProtoHTTP11;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- // HTTP/1.1 data for |request1| and |request2|.
- MockWrite http_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: alternative.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: alternative.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead http_reads[] = {
- MockRead(
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/html; charset=iso-8859-1\r\n"
- "Content-Length: 40\r\n\r\n"
- "first HTTP/1.1 response from alternative"),
- MockRead(
- "HTTP/1.1 200 OK\r\n"
- "Content-Type: text/html; charset=iso-8859-1\r\n"
- "Content-Length: 41\r\n\r\n"
- "second HTTP/1.1 response from alternative"),
- };
- StaticSocketDataProvider http_data(http_reads, http_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&http_data);
- // This test documents that an alternate Job should not pool to an already
- // existing HTTP/1.1 connection. In order to test this, a failed connection
- // to the server is mocked. This way |request2| relies on the alternate Job.
- StaticSocketDataProvider data_refused;
- data_refused.set_connect_data(MockConnect(ASYNC, ERR_CONNECTION_REFUSED));
- session_deps_.socket_factory->AddSocketDataProvider(&data_refused);
- // Set up alternative service for server.
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpServerProperties* http_server_properties =
- session->http_server_properties();
- AlternativeService alternative_service(kProtoHTTP2, alternative);
- base::Time expiration = base::Time::Now() + base::Days(1);
- http_server_properties->SetHttp2AlternativeService(
- server, NetworkIsolationKey(), alternative_service, expiration);
- // First transaction to alternative to open an HTTP/1.1 socket.
- HttpRequestInfo request1;
- HttpNetworkTransaction trans1(DEFAULT_PRIORITY, session.get());
- request1.method = "GET";
- request1.url = GURL(alternative_url);
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- TestCompletionCallback callback1;
- int rv = trans1.Start(&request1, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(callback1.GetResult(rv), IsOk());
- const HttpResponseInfo* response1 = trans1.GetResponseInfo();
- ASSERT_TRUE(response1);
- ASSERT_TRUE(response1->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response1->headers->GetStatusLine());
- EXPECT_TRUE(response1->was_alpn_negotiated);
- EXPECT_FALSE(response1->was_fetched_via_spdy);
- std::string response_data1;
- ASSERT_THAT(ReadTransaction(&trans1, &response_data1), IsOk());
- EXPECT_EQ("first HTTP/1.1 response from alternative", response_data1);
- // Request for origin.example.org, which has an alternative service. This
- // will start two Jobs: the alternative looks for connections to pool to,
- // finds one which is HTTP/1.1, and should ignore it, and should not try to
- // open other connections to alternative server. The Job to server fails, so
- // this request fails.
- HttpRequestInfo request2;
- HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- request2.method = "GET";
- request2.url = GURL(origin_url);
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- TestCompletionCallback callback2;
- rv = trans2.Start(&request2, callback2.callback(), NetLogWithSource());
- EXPECT_THAT(callback2.GetResult(rv), IsError(ERR_CONNECTION_REFUSED));
- // Another transaction to alternative. This is to test that the HTTP/1.1
- // socket is still open and in the pool.
- HttpRequestInfo request3;
- HttpNetworkTransaction trans3(DEFAULT_PRIORITY, session.get());
- request3.method = "GET";
- request3.url = GURL(alternative_url);
- request3.load_flags = 0;
- request3.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- TestCompletionCallback callback3;
- rv = trans3.Start(&request3, callback3.callback(), NetLogWithSource());
- EXPECT_THAT(callback3.GetResult(rv), IsOk());
- const HttpResponseInfo* response3 = trans3.GetResponseInfo();
- ASSERT_TRUE(response3);
- ASSERT_TRUE(response3->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response3->headers->GetStatusLine());
- EXPECT_TRUE(response3->was_alpn_negotiated);
- EXPECT_FALSE(response3->was_fetched_via_spdy);
- std::string response_data3;
- ASSERT_THAT(ReadTransaction(&trans3, &response_data3), IsOk());
- EXPECT_EQ("second HTTP/1.1 response from alternative", response_data3);
- }
- TEST_F(HttpNetworkTransactionTest, DoNotUseSpdySessionForHttpOverTunnel) {
- const std::string https_url = "https://www.example.org:8080/";
- const std::string http_url = "http://www.example.org:8080/";
- // Separate SPDY util instance for naked and wrapped requests.
- SpdyTestUtil spdy_util_wrapped;
- // SPDY GET for HTTPS URL (through CONNECT tunnel)
- const HostPortPair host_port_pair("www.example.org", 8080);
- spdy::SpdySerializedFrame connect(spdy_util_.ConstructSpdyConnect(
- nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
- host_port_pair));
- spdy::SpdySerializedFrame req1(
- spdy_util_wrapped.ConstructSpdyGet(https_url.c_str(), 1, LOWEST));
- spdy::SpdySerializedFrame wrapped_req1(
- spdy_util_.ConstructWrappedSpdyFrame(req1, 1));
- // SPDY GET for HTTP URL (through the proxy, but not the tunnel).
- spdy::Http2HeaderBlock req2_block;
- req2_block[spdy::kHttp2MethodHeader] = "GET";
- req2_block[spdy::kHttp2AuthorityHeader] = "www.example.org:8080";
- req2_block[spdy::kHttp2SchemeHeader] = "http";
- req2_block[spdy::kHttp2PathHeader] = "/";
- spdy::SpdySerializedFrame req2(
- spdy_util_.ConstructSpdyHeaders(3, std::move(req2_block), MEDIUM, true));
- MockWrite writes1[] = {
- CreateMockWrite(connect, 0), CreateMockWrite(wrapped_req1, 2),
- CreateMockWrite(req2, 6),
- };
- spdy::SpdySerializedFrame conn_resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame resp1(
- spdy_util_wrapped.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame body1(
- spdy_util_wrapped.ConstructSpdyDataFrame(1, true));
- spdy::SpdySerializedFrame wrapped_resp1(
- spdy_util_wrapped.ConstructWrappedSpdyFrame(resp1, 1));
- spdy::SpdySerializedFrame wrapped_body1(
- spdy_util_wrapped.ConstructWrappedSpdyFrame(body1, 1));
- spdy::SpdySerializedFrame resp2(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
- spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
- MockRead reads1[] = {
- CreateMockRead(conn_resp, 1),
- MockRead(ASYNC, ERR_IO_PENDING, 3),
- CreateMockRead(wrapped_resp1, 4),
- CreateMockRead(wrapped_body1, 5),
- MockRead(ASYNC, ERR_IO_PENDING, 7),
- CreateMockRead(resp2, 8),
- CreateMockRead(body2, 9),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 10),
- };
- SequencedSocketData data1(reads1, writes1);
- MockConnect connect_data1(ASYNC, OK);
- data1.set_connect_data(connect_data1);
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "HTTPS proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = net::NetLog::Get();
- SSLSocketDataProvider ssl1(ASYNC, OK); // to the proxy
- ssl1.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- SSLSocketDataProvider ssl2(ASYNC, OK); // to the server
- ssl2.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- // Start the first transaction to set up the SpdySession
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL(https_url);
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans1(LOWEST, session.get());
- TestCompletionCallback callback1;
- int rv = trans1.Start(&request1, callback1.callback(), NetLogWithSource());
- // This pause is a hack to avoid running into https://crbug.com/497228.
- data1.RunUntilPaused();
- base::RunLoop().RunUntilIdle();
- data1.Resume();
- EXPECT_THAT(callback1.GetResult(rv), IsOk());
- EXPECT_TRUE(trans1.GetResponseInfo()->was_fetched_via_spdy);
- LoadTimingInfo load_timing_info1;
- EXPECT_TRUE(trans1.GetLoadTimingInfo(&load_timing_info1));
- TestLoadTimingNotReusedWithPac(load_timing_info1,
- CONNECT_TIMING_HAS_SSL_TIMES);
- // Now, start the HTTP request.
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL(http_url);
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans2(MEDIUM, session.get());
- TestCompletionCallback callback2;
- rv = trans2.Start(&request2, callback2.callback(), NetLogWithSource());
- // This pause is a hack to avoid running into https://crbug.com/497228.
- data1.RunUntilPaused();
- base::RunLoop().RunUntilIdle();
- data1.Resume();
- EXPECT_THAT(callback2.GetResult(rv), IsOk());
- EXPECT_TRUE(trans2.GetResponseInfo()->was_fetched_via_spdy);
- LoadTimingInfo load_timing_info2;
- EXPECT_TRUE(trans2.GetLoadTimingInfo(&load_timing_info2));
- // The established SPDY sessions is considered reused by the HTTP request.
- TestLoadTimingReusedWithPac(load_timing_info2);
- // HTTP requests over a SPDY session should have a different connection
- // socket_log_id than requests over a tunnel.
- EXPECT_NE(load_timing_info1.socket_log_id, load_timing_info2.socket_log_id);
- }
- // Test that in the case where we have a SPDY session to a SPDY proxy
- // that we do not pool other origins that resolve to the same IP when
- // the certificate does not match the new origin.
- // http://crbug.com/134690
- TEST_F(HttpNetworkTransactionTest, DoNotUseSpdySessionIfCertDoesNotMatch) {
- const std::string url1 = "http://www.example.org/";
- const std::string url2 = "https://news.example.org/";
- const std::string ip_addr = "1.2.3.4";
- // Second SpdyTestUtil instance for the second socket.
- SpdyTestUtil spdy_util_secure;
- // SPDY GET for HTTP URL (through SPDY proxy)
- spdy::Http2HeaderBlock headers(
- spdy_util_.ConstructGetHeaderBlockForProxy("http://www.example.org/"));
- spdy::SpdySerializedFrame req1(
- spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
- MockWrite writes1[] = {
- CreateMockWrite(req1, 0),
- };
- spdy::SpdySerializedFrame resp1(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead reads1[] = {
- MockRead(ASYNC, ERR_IO_PENDING, 1), CreateMockRead(resp1, 2),
- CreateMockRead(body1, 3), MockRead(ASYNC, OK, 4), // EOF
- };
- SequencedSocketData data1(reads1, writes1);
- IPAddress ip;
- ASSERT_TRUE(ip.AssignFromIPLiteral(ip_addr));
- IPEndPoint peer_addr = IPEndPoint(ip, 443);
- MockConnect connect_data1(ASYNC, OK, peer_addr);
- data1.set_connect_data(connect_data1);
- // SPDY GET for HTTPS URL (direct)
- spdy::SpdySerializedFrame req2(
- spdy_util_secure.ConstructSpdyGet(url2.c_str(), 1, MEDIUM));
- MockWrite writes2[] = {
- CreateMockWrite(req2, 0),
- };
- spdy::SpdySerializedFrame resp2(
- spdy_util_secure.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame body2(
- spdy_util_secure.ConstructSpdyDataFrame(1, true));
- MockRead reads2[] = {CreateMockRead(resp2, 1), CreateMockRead(body2, 2),
- MockRead(ASYNC, OK, 3)};
- SequencedSocketData data2(reads2, writes2);
- MockConnect connect_data2(ASYNC, OK);
- data2.set_connect_data(connect_data2);
- // Set up a proxy config that sends HTTP requests to a proxy, and
- // all others direct.
- ProxyConfig proxy_config;
- proxy_config.proxy_rules().ParseFromString("http=https://proxy:443");
- session_deps_.proxy_resolution_service =
- std::make_unique<ConfiguredProxyResolutionService>(
- std::make_unique<ProxyConfigServiceFixed>(ProxyConfigWithAnnotation(
- proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)),
- nullptr, nullptr, /*quick_check_enabled=*/true);
- SSLSocketDataProvider ssl1(ASYNC, OK); // to the proxy
- ssl1.next_proto = kProtoHTTP2;
- // Load a valid cert. Note, that this does not need to
- // be valid for proxy because the MockSSLClientSocket does
- // not actually verify it. But SpdySession will use this
- // to see if it is valid for the new origin
- ssl1.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem");
- ASSERT_TRUE(ssl1.ssl_info.cert);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl2(ASYNC, OK); // to the server
- ssl2.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- session_deps_.host_resolver = std::make_unique<MockCachingHostResolver>();
- session_deps_.host_resolver->rules()->AddRule("news.example.org", ip_addr);
- session_deps_.host_resolver->rules()->AddRule("proxy", ip_addr);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- // Start the first transaction to set up the SpdySession
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL(url1);
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans1(LOWEST, session.get());
- TestCompletionCallback callback1;
- ASSERT_EQ(ERR_IO_PENDING,
- trans1.Start(&request1, callback1.callback(), NetLogWithSource()));
- // This pause is a hack to avoid running into https://crbug.com/497228.
- data1.RunUntilPaused();
- base::RunLoop().RunUntilIdle();
- data1.Resume();
- EXPECT_THAT(callback1.WaitForResult(), IsOk());
- EXPECT_TRUE(trans1.GetResponseInfo()->was_fetched_via_spdy);
- // Now, start the HTTP request
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL(url2);
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans2(MEDIUM, session.get());
- TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING,
- trans2.Start(&request2, callback2.callback(), NetLogWithSource()));
- base::RunLoop().RunUntilIdle();
- ASSERT_TRUE(callback2.have_result());
- EXPECT_THAT(callback2.WaitForResult(), IsOk());
- EXPECT_TRUE(trans2.GetResponseInfo()->was_fetched_via_spdy);
- }
- // Test to verify that a failed socket read (due to an ERR_CONNECTION_CLOSED
- // error) in SPDY session, removes the socket from pool and closes the SPDY
- // session. Verify that new url's from the same HttpNetworkSession (and a new
- // SpdySession) do work. http://crbug.com/224701
- TEST_F(HttpNetworkTransactionTest, ErrorSocketNotConnected) {
- const std::string https_url = "https://www.example.org/";
- MockRead reads1[] = {
- MockRead(SYNCHRONOUS, ERR_CONNECTION_CLOSED, 0)
- };
- SequencedSocketData data1(reads1, base::span<MockWrite>());
- spdy::SpdySerializedFrame req2(
- spdy_util_.ConstructSpdyGet(https_url.c_str(), 1, MEDIUM));
- MockWrite writes2[] = {
- CreateMockWrite(req2, 0),
- };
- spdy::SpdySerializedFrame resp2(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead reads2[] = {
- CreateMockRead(resp2, 1), CreateMockRead(body2, 2),
- MockRead(ASYNC, OK, 3) // EOF
- };
- SequencedSocketData data2(reads2, writes2);
- SSLSocketDataProvider ssl1(ASYNC, OK);
- ssl1.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- ssl2.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- std::unique_ptr<HttpNetworkSession> session(
- SpdySessionDependencies::SpdyCreateSession(&session_deps_));
- // Start the first transaction to set up the SpdySession and verify that
- // connection was closed.
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL(https_url);
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans1(MEDIUM, session.get());
- TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING,
- trans1.Start(&request1, callback1.callback(), NetLogWithSource()));
- EXPECT_THAT(callback1.WaitForResult(), IsError(ERR_CONNECTION_CLOSED));
- // Now, start the second request and make sure it succeeds.
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL(https_url);
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans2(MEDIUM, session.get());
- TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING,
- trans2.Start(&request2, callback2.callback(), NetLogWithSource()));
- ASSERT_THAT(callback2.WaitForResult(), IsOk());
- EXPECT_TRUE(trans2.GetResponseInfo()->was_fetched_via_spdy);
- }
- TEST_F(HttpNetworkTransactionTest, CloseIdleSpdySessionToOpenNewOne) {
- ClientSocketPoolManager::set_max_sockets_per_group(
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
- ClientSocketPoolManager::set_max_sockets_per_pool(
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
- // Use two different hosts with different IPs so they don't get pooled.
- session_deps_.host_resolver->rules()->AddRule("www.a.com", "10.0.0.1");
- session_deps_.host_resolver->rules()->AddRule("www.b.com", "10.0.0.2");
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- SSLSocketDataProvider ssl1(ASYNC, OK);
- ssl1.next_proto = kProtoHTTP2;
- SSLSocketDataProvider ssl2(ASYNC, OK);
- ssl2.next_proto = kProtoHTTP2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- spdy::SpdySerializedFrame host1_req(
- spdy_util_.ConstructSpdyGet("https://www.a.com", 1, DEFAULT_PRIORITY));
- MockWrite spdy1_writes[] = {
- CreateMockWrite(host1_req, 0),
- };
- spdy::SpdySerializedFrame host1_resp(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame host1_resp_body(
- spdy_util_.ConstructSpdyDataFrame(1, true));
- MockRead spdy1_reads[] = {
- CreateMockRead(host1_resp, 1), CreateMockRead(host1_resp_body, 2),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3),
- };
- // Use a separate test instance for the separate SpdySession that will be
- // created.
- SpdyTestUtil spdy_util_2;
- SequencedSocketData spdy1_data(spdy1_reads, spdy1_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy1_data);
- spdy::SpdySerializedFrame host2_req(
- spdy_util_2.ConstructSpdyGet("https://www.b.com", 1, DEFAULT_PRIORITY));
- MockWrite spdy2_writes[] = {
- CreateMockWrite(host2_req, 0),
- };
- spdy::SpdySerializedFrame host2_resp(
- spdy_util_2.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame host2_resp_body(
- spdy_util_2.ConstructSpdyDataFrame(1, true));
- MockRead spdy2_reads[] = {
- CreateMockRead(host2_resp, 1), CreateMockRead(host2_resp_body, 2),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3),
- };
- SequencedSocketData spdy2_data(spdy2_reads, spdy2_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&spdy2_data);
- MockWrite http_write[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.a.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead http_read[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 6\r\n\r\n"),
- MockRead("hello!"),
- };
- StaticSocketDataProvider http_data(http_read, http_write);
- session_deps_.socket_factory->AddSocketDataProvider(&http_data);
- HostPortPair host_port_pair_a("www.a.com", 443);
- SpdySessionKey spdy_session_key_a(
- host_port_pair_a, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
- SpdySessionKey::IsProxySession::kFalse, SocketTag(),
- NetworkIsolationKey(), SecureDnsPolicy::kAllow);
- EXPECT_FALSE(
- HasSpdySession(session->spdy_session_pool(), spdy_session_key_a));
- TestCompletionCallback callback;
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://www.a.com/");
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- std::string response_data;
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- trans.reset();
- EXPECT_TRUE(
- HasSpdySession(session->spdy_session_pool(), spdy_session_key_a));
- HostPortPair host_port_pair_b("www.b.com", 443);
- SpdySessionKey spdy_session_key_b(
- host_port_pair_b, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
- SpdySessionKey::IsProxySession::kFalse, SocketTag(),
- NetworkIsolationKey(), SecureDnsPolicy::kAllow);
- EXPECT_FALSE(
- HasSpdySession(session->spdy_session_pool(), spdy_session_key_b));
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://www.b.com/");
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans->Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- EXPECT_FALSE(
- HasSpdySession(session->spdy_session_pool(), spdy_session_key_a));
- EXPECT_TRUE(
- HasSpdySession(session->spdy_session_pool(), spdy_session_key_b));
- HostPortPair host_port_pair_a1("www.a.com", 80);
- SpdySessionKey spdy_session_key_a1(
- host_port_pair_a1, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
- SpdySessionKey::IsProxySession::kFalse, SocketTag(),
- NetworkIsolationKey(), SecureDnsPolicy::kAllow);
- EXPECT_FALSE(
- HasSpdySession(session->spdy_session_pool(), spdy_session_key_a1));
- HttpRequestInfo request3;
- request3.method = "GET";
- request3.url = GURL("http://www.a.com/");
- request3.load_flags = 0;
- request3.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans->Start(&request3, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
- EXPECT_FALSE(response->was_fetched_via_spdy);
- EXPECT_FALSE(response->was_alpn_negotiated);
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- EXPECT_FALSE(
- HasSpdySession(session->spdy_session_pool(), spdy_session_key_a));
- EXPECT_FALSE(
- HasSpdySession(session->spdy_session_pool(), spdy_session_key_b));
- }
- TEST_F(HttpNetworkTransactionTest, HttpSyncConnectError) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockConnect mock_connect(SYNCHRONOUS, ERR_NAME_NOT_RESOLVED);
- StaticSocketDataProvider data;
- data.set_connect_data(mock_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_NAME_NOT_RESOLVED));
- ConnectionAttempts attempts = trans.GetConnectionAttempts();
- ASSERT_EQ(1u, attempts.size());
- EXPECT_THAT(attempts[0].result, IsError(ERR_NAME_NOT_RESOLVED));
- IPEndPoint endpoint;
- EXPECT_FALSE(trans.GetRemoteEndpoint(&endpoint));
- EXPECT_TRUE(endpoint.address().empty());
- }
- TEST_F(HttpNetworkTransactionTest, HttpAsyncConnectError) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockConnect mock_connect(ASYNC, ERR_NAME_NOT_RESOLVED);
- StaticSocketDataProvider data;
- data.set_connect_data(mock_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_NAME_NOT_RESOLVED));
- ConnectionAttempts attempts = trans.GetConnectionAttempts();
- ASSERT_EQ(1u, attempts.size());
- EXPECT_THAT(attempts[0].result, IsError(ERR_NAME_NOT_RESOLVED));
- IPEndPoint endpoint;
- EXPECT_FALSE(trans.GetRemoteEndpoint(&endpoint));
- EXPECT_TRUE(endpoint.address().empty());
- }
- TEST_F(HttpNetworkTransactionTest, HttpSyncWriteError) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
- };
- MockRead data_reads[] = {
- MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached.
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
- }
- TEST_F(HttpNetworkTransactionTest, HttpAsyncWriteError) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite(ASYNC, ERR_CONNECTION_RESET),
- };
- MockRead data_reads[] = {
- MockRead(SYNCHRONOUS, ERR_UNEXPECTED), // Should not be reached.
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
- }
- TEST_F(HttpNetworkTransactionTest, HttpSyncReadError) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead(SYNCHRONOUS, ERR_CONNECTION_RESET),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
- }
- TEST_F(HttpNetworkTransactionTest, HttpAsyncReadError) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead(ASYNC, ERR_CONNECTION_RESET),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
- }
- // Tests that when a used socket is returned to the SSL socket pool, it's closed
- // if the transport socket pool is stalled on the global socket limit.
- TEST_F(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest) {
- ClientSocketPoolManager::set_max_sockets_per_group(
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
- ClientSocketPoolManager::set_max_sockets_per_pool(
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
- // Set up SSL request.
- HttpRequestInfo ssl_request;
- ssl_request.method = "GET";
- ssl_request.url = GURL("https://www.example.org/");
- ssl_request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite ssl_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead ssl_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 11\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider ssl_data(ssl_reads, ssl_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&ssl_data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- // Set up HTTP request.
- HttpRequestInfo http_request;
- http_request.method = "GET";
- http_request.url = GURL("http://www.example.org/");
- http_request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite http_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 7\r\n\r\n"),
- MockRead("falafel"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider http_data(http_reads, http_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&http_data);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Start the SSL request.
- TestCompletionCallback ssl_callback;
- HttpNetworkTransaction ssl_trans(DEFAULT_PRIORITY, session.get());
- ASSERT_EQ(ERR_IO_PENDING,
- ssl_trans.Start(&ssl_request, ssl_callback.callback(),
- NetLogWithSource()));
- // Start the HTTP request. Pool should stall.
- TestCompletionCallback http_callback;
- HttpNetworkTransaction http_trans(DEFAULT_PRIORITY, session.get());
- ASSERT_EQ(ERR_IO_PENDING,
- http_trans.Start(&http_request, http_callback.callback(),
- NetLogWithSource()));
- EXPECT_TRUE(IsTransportSocketPoolStalled(session.get()));
- // Wait for response from SSL request.
- ASSERT_THAT(ssl_callback.WaitForResult(), IsOk());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&ssl_trans, &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- // The SSL socket should automatically be closed, so the HTTP request can
- // start.
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- ASSERT_FALSE(IsTransportSocketPoolStalled(session.get()));
- // The HTTP request can now complete.
- ASSERT_THAT(http_callback.WaitForResult(), IsOk());
- ASSERT_THAT(ReadTransaction(&http_trans, &response_data), IsOk());
- EXPECT_EQ("falafel", response_data);
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- // Tests that when a SSL connection is established but there's no corresponding
- // request that needs it, the new socket is closed if the transport socket pool
- // is stalled on the global socket limit.
- TEST_F(HttpNetworkTransactionTest, CloseSSLSocketOnIdleForHttpRequest2) {
- ClientSocketPoolManager::set_max_sockets_per_group(
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
- ClientSocketPoolManager::set_max_sockets_per_pool(
- HttpNetworkSession::NORMAL_SOCKET_POOL, 1);
- // Set up an ssl request.
- HttpRequestInfo ssl_request;
- ssl_request.method = "GET";
- ssl_request.url = GURL("https://www.foopy.com/");
- ssl_request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // No data will be sent on the SSL socket.
- StaticSocketDataProvider ssl_data;
- session_deps_.socket_factory->AddSocketDataProvider(&ssl_data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- // Set up HTTP request.
- HttpRequestInfo http_request;
- http_request.method = "GET";
- http_request.url = GURL("http://www.example.org/");
- http_request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite http_writes[] = {
- MockWrite(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead http_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 7\r\n\r\n"),
- MockRead("falafel"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider http_data(http_reads, http_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&http_data);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Preconnect an SSL socket. A preconnect is needed because connect jobs are
- // cancelled when a normal transaction is cancelled.
- HttpStreamFactory* http_stream_factory = session->http_stream_factory();
- http_stream_factory->PreconnectStreams(1, ssl_request);
- EXPECT_EQ(0, GetIdleSocketCountInTransportSocketPool(session.get()));
- // Start the HTTP request. Pool should stall.
- TestCompletionCallback http_callback;
- HttpNetworkTransaction http_trans(DEFAULT_PRIORITY, session.get());
- ASSERT_EQ(ERR_IO_PENDING,
- http_trans.Start(&http_request, http_callback.callback(),
- NetLogWithSource()));
- EXPECT_TRUE(IsTransportSocketPoolStalled(session.get()));
- // The SSL connection will automatically be closed once the connection is
- // established, to let the HTTP request start.
- ASSERT_THAT(http_callback.WaitForResult(), IsOk());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&http_trans, &response_data), IsOk());
- EXPECT_EQ("falafel", response_data);
- EXPECT_EQ(1, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- TEST_F(HttpNetworkTransactionTest, PostReadsErrorResponseAfterReset) {
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(
- std::make_unique<UploadBytesElementReader>("foo", 3));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.foo.com/");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Send headers successfully, but get an error while sending the body.
- MockWrite data_writes[] = {
- MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 3\r\n\r\n"),
- MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 400 Not OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.0 400 Not OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- }
- // This test makes sure the retry logic doesn't trigger when reading an error
- // response from a server that rejected a POST with a CONNECTION_RESET.
- TEST_F(HttpNetworkTransactionTest,
- PostReadsErrorResponseAfterResetOnReusedSocket) {
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 3\r\n\r\n"),
- MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 Peachy\r\n"
- "Content-Length: 14\r\n\r\n"),
- MockRead("first response"),
- MockRead("HTTP/1.1 400 Not OK\r\n"
- "Content-Length: 15\r\n\r\n"),
- MockRead("second response"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("http://www.foo.com/");
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto trans1 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response1 = trans1->GetResponseInfo();
- ASSERT_TRUE(response1);
- EXPECT_TRUE(response1->headers);
- EXPECT_EQ("HTTP/1.1 200 Peachy", response1->headers->GetStatusLine());
- std::string response_data1;
- rv = ReadTransaction(trans1.get(), &response_data1);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("first response", response_data1);
- // Delete the transaction to release the socket back into the socket pool.
- trans1.reset();
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(
- std::make_unique<UploadBytesElementReader>("foo", 3));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request2;
- request2.method = "POST";
- request2.url = GURL("http://www.foo.com/");
- request2.upload_data_stream = &upload_data_stream;
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpNetworkTransaction trans2(DEFAULT_PRIORITY, session.get());
- rv = trans2.Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response2 = trans2.GetResponseInfo();
- ASSERT_TRUE(response2);
- EXPECT_TRUE(response2->headers);
- EXPECT_EQ("HTTP/1.1 400 Not OK", response2->headers->GetStatusLine());
- std::string response_data2;
- rv = ReadTransaction(&trans2, &response_data2);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("second response", response_data2);
- }
- TEST_F(HttpNetworkTransactionTest,
- PostReadsErrorResponseAfterResetPartialBodySent) {
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(
- std::make_unique<UploadBytesElementReader>("foo", 3));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.foo.com/");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Send headers successfully, but get an error while sending the body.
- MockWrite data_writes[] = {
- MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 3\r\n\r\n"
- "fo"),
- MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 400 Not OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.0 400 Not OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- }
- // This tests the more common case than the previous test, where headers and
- // body are not merged into a single request.
- TEST_F(HttpNetworkTransactionTest, ChunkedPostReadsErrorResponseAfterReset) {
- ChunkedUploadDataStream upload_data_stream(0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.foo.com/");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Send headers successfully, but get an error while sending the body.
- MockWrite data_writes[] = {
- MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n"
- "Transfer-Encoding: chunked\r\n\r\n"),
- MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 400 Not OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Make sure the headers are sent before adding a chunk. This ensures that
- // they can't be merged with the body in a single send. Not currently
- // necessary since a chunked body is never merged with headers, but this makes
- // the test more future proof.
- base::RunLoop().RunUntilIdle();
- upload_data_stream.AppendData("last chunk", 10, true);
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.0 400 Not OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- }
- TEST_F(HttpNetworkTransactionTest, PostReadsErrorResponseAfterResetAnd100) {
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(
- std::make_unique<UploadBytesElementReader>("foo", 3));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.foo.com/");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 3\r\n\r\n"),
- MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 100 Continue\r\n\r\n"),
- MockRead("HTTP/1.0 400 Not OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.0 400 Not OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello world", response_data);
- }
- TEST_F(HttpNetworkTransactionTest, PostIgnoresNonErrorResponseAfterReset) {
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(
- std::make_unique<UploadBytesElementReader>("foo", 3));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.foo.com/");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Send headers successfully, but get an error while sending the body.
- MockWrite data_writes[] = {
- MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 3\r\n\r\n"),
- MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 Just Dandy\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
- }
- TEST_F(HttpNetworkTransactionTest,
- PostIgnoresNonErrorResponseAfterResetAnd100) {
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(
- std::make_unique<UploadBytesElementReader>("foo", 3));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.foo.com/");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Send headers successfully, but get an error while sending the body.
- MockWrite data_writes[] = {
- MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 3\r\n\r\n"),
- MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 100 Continue\r\n\r\n"),
- MockRead("HTTP/1.0 302 Redirect\r\n"),
- MockRead("Location: http://somewhere-else.com/\r\n"),
- MockRead("Content-Length: 0\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
- }
- TEST_F(HttpNetworkTransactionTest, PostIgnoresHttp09ResponseAfterReset) {
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(
- std::make_unique<UploadBytesElementReader>("foo", 3));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.foo.com/");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Send headers successfully, but get an error while sending the body.
- MockWrite data_writes[] = {
- MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 3\r\n\r\n"),
- MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
- };
- MockRead data_reads[] = {
- MockRead("HTTP 0.9 rocks!"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
- }
- TEST_F(HttpNetworkTransactionTest, PostIgnoresPartial400HeadersAfterReset) {
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(
- std::make_unique<UploadBytesElementReader>("foo", 3));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.foo.com/");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Send headers successfully, but get an error while sending the body.
- MockWrite data_writes[] = {
- MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 3\r\n\r\n"),
- MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 400 Not a Full Response\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_CONNECTION_RESET));
- }
- #if BUILDFLAG(ENABLE_WEBSOCKETS)
- namespace {
- void AddWebSocketHeaders(HttpRequestHeaders* headers) {
- headers->SetHeader("Connection", "Upgrade");
- headers->SetHeader("Upgrade", "websocket");
- headers->SetHeader("Origin", "http://www.example.org");
- headers->SetHeader("Sec-WebSocket-Version", "13");
- }
- } // namespace
- TEST_F(HttpNetworkTransactionTest, CreateWebSocketHandshakeStream) {
- for (bool secure : {true, false}) {
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: Upgrade\r\n"
- "Upgrade: websocket\r\n"
- "Origin: http://www.example.org\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Sec-WebSocket-Extensions: permessage-deflate; "
- "client_max_window_bits\r\n\r\n")};
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- if (secure)
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- HttpRequestInfo request;
- request.method = "GET";
- request.url =
- GURL(secure ? "ws://www.example.org/" : "wss://www.example.org/");
- AddWebSocketHeaders(&request.extra_headers);
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- TestWebSocketHandshakeStreamCreateHelper
- websocket_handshake_stream_create_helper;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(LOW, session.get());
- trans.SetWebSocketHandshakeStreamCreateHelper(
- &websocket_handshake_stream_create_helper);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- const HttpStreamRequest* stream_request = trans.stream_request_.get();
- ASSERT_TRUE(stream_request);
- EXPECT_EQ(&websocket_handshake_stream_create_helper,
- stream_request->websocket_handshake_stream_create_helper());
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- EXPECT_TRUE(data.AllReadDataConsumed());
- EXPECT_TRUE(data.AllWriteDataConsumed());
- }
- }
- // Verify that proxy headers are not sent to the destination server when
- // establishing a tunnel for a secure WebSocket connection.
- TEST_F(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWssTunnel) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("wss://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- AddWebSocketHeaders(&request.extra_headers);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since a proxy is configured, try to establish a tunnel.
- MockWrite data_writes[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- // After calling trans->RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: Upgrade\r\n"
- "Upgrade: websocket\r\n"
- "Origin: http://www.example.org\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Sec-WebSocket-Extensions: permessage-deflate; "
- "client_max_window_bits\r\n\r\n")};
- // The proxy responds to the connect with a 407, using a persistent
- // connection.
- MockRead data_reads[] = {
- // No credentials.
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"
- "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Content-Length: 0\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- MockRead("HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- trans->SetWebSocketHandshakeStreamCreateHelper(
- &websocket_stream_create_helper);
- {
- TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- }
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(407, response->headers->response_code());
- {
- TestCompletionCallback callback;
- int rv = trans->RestartWithAuth(AuthCredentials(kFoo, kBar),
- callback.callback());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- }
- response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(101, response->headers->response_code());
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Verify that proxy headers are not sent to the destination server when
- // establishing a tunnel for an insecure WebSocket connection.
- // This requires the authentication info to be injected into the auth cache
- // due to crbug.com/395064
- // TODO(ricea): Change to use a 407 response once issue 395064 is fixed.
- TEST_F(HttpNetworkTransactionTest, ProxyHeadersNotSentOverWsTunnel) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("ws://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- AddWebSocketHeaders(&request.extra_headers);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- MockWrite data_writes[] = {
- // Try to establish a tunnel for the WebSocket connection, with
- // credentials. Because WebSockets have a separate set of socket pools,
- // they cannot and will not use the same TCP/IP connection as the
- // preflight HTTP request.
- MockWrite("CONNECT www.example.org:80 HTTP/1.1\r\n"
- "Host: www.example.org:80\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: Upgrade\r\n"
- "Upgrade: websocket\r\n"
- "Origin: http://www.example.org\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Sec-WebSocket-Extensions: permessage-deflate; "
- "client_max_window_bits\r\n\r\n")};
- MockRead data_reads[] = {
- // HTTP CONNECT with credentials.
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- // WebSocket connection established inside tunnel.
- MockRead("HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- session->http_auth_cache()->Add(
- url::SchemeHostPort(GURL("http://myproxy:70/")), HttpAuth::AUTH_PROXY,
- "MyRealm1", HttpAuth::AUTH_SCHEME_BASIC, NetworkIsolationKey(),
- "Basic realm=MyRealm1", AuthCredentials(kFoo, kBar), "/");
- TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- trans->SetWebSocketHandshakeStreamCreateHelper(
- &websocket_stream_create_helper);
- TestCompletionCallback callback;
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(101, response->headers->response_code());
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // WebSockets over QUIC is not supported, including over QUIC proxies.
- TEST_F(HttpNetworkTransactionTest, WebSocketNotSentOverQuicProxy) {
- for (bool secure : {true, false}) {
- SCOPED_TRACE(secure);
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "QUIC myproxy.org:443", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.enable_quic = true;
- HttpRequestInfo request;
- request.url =
- GURL(secure ? "ws://www.example.org/" : "wss://www.example.org/");
- AddWebSocketHeaders(&request.extra_headers);
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- TestWebSocketHandshakeStreamCreateHelper
- websocket_handshake_stream_create_helper;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(LOW, session.get());
- trans.SetWebSocketHandshakeStreamCreateHelper(
- &websocket_handshake_stream_create_helper);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_NO_SUPPORTED_PROXIES));
- }
- }
- #endif // BUILDFLAG(ENABLE_WEBSOCKETS)
- TEST_F(HttpNetworkTransactionTest, TotalNetworkBytesPost) {
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(
- std::make_unique<UploadBytesElementReader>("foo", 3));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.foo.com/");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 3\r\n\r\n"),
- MockWrite("foo"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- trans.Start(&request, callback.callback(), NetLogWithSource()));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- std::string response_data;
- EXPECT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ(CountWriteBytes(data_writes), trans.GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(data_reads), trans.GetTotalReceivedBytes());
- }
- TEST_F(HttpNetworkTransactionTest, TotalNetworkBytesPost100Continue) {
- std::vector<std::unique_ptr<UploadElementReader>> element_readers;
- element_readers.push_back(
- std::make_unique<UploadBytesElementReader>("foo", 3));
- ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.foo.com/");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- MockWrite data_writes[] = {
- MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 3\r\n\r\n"),
- MockWrite("foo"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 100 Continue\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- trans.Start(&request, callback.callback(), NetLogWithSource()));
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- std::string response_data;
- EXPECT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ(CountWriteBytes(data_writes), trans.GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(data_reads), trans.GetTotalReceivedBytes());
- }
- TEST_F(HttpNetworkTransactionTest, TotalNetworkBytesChunkedPost) {
- ChunkedUploadDataStream upload_data_stream(0);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("http://www.foo.com/");
- request.upload_data_stream = &upload_data_stream;
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Send headers successfully, but get an error while sending the body.
- MockWrite data_writes[] = {
- MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n"
- "Transfer-Encoding: chunked\r\n\r\n"),
- MockWrite("1\r\nf\r\n"), MockWrite("2\r\noo\r\n"), MockWrite("0\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n\r\n"), MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- trans.Start(&request, callback.callback(), NetLogWithSource()));
- base::RunLoop().RunUntilIdle();
- upload_data_stream.AppendData("f", 1, false);
- base::RunLoop().RunUntilIdle();
- upload_data_stream.AppendData("oo", 2, true);
- EXPECT_THAT(callback.WaitForResult(), IsOk());
- std::string response_data;
- EXPECT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ(CountWriteBytes(data_writes), trans.GetTotalSentBytes());
- EXPECT_EQ(CountReadBytes(data_reads), trans.GetTotalReceivedBytes());
- }
- void CheckContentEncodingMatching(SpdySessionDependencies* session_deps,
- const std::string& accept_encoding,
- const std::string& content_encoding,
- const std::string& location,
- bool should_match) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.foo.com/");
- request.extra_headers.SetHeader(HttpRequestHeaders::kAcceptEncoding,
- accept_encoding);
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(session_deps));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Send headers successfully, but get an error while sending the body.
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n"
- "Accept-Encoding: "),
- MockWrite(accept_encoding.data()), MockWrite("\r\n\r\n"),
- };
- std::string response_code = "200 OK";
- std::string extra;
- if (!location.empty()) {
- response_code = "301 Redirect\r\nLocation: ";
- response_code.append(location);
- }
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 "),
- MockRead(response_code.data()),
- MockRead("\r\nContent-Encoding: "),
- MockRead(content_encoding.data()),
- MockRead("\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps->socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- if (should_match) {
- EXPECT_THAT(rv, IsOk());
- } else {
- EXPECT_THAT(rv, IsError(ERR_CONTENT_DECODING_FAILED));
- }
- }
- TEST_F(HttpNetworkTransactionTest, MatchContentEncoding1) {
- CheckContentEncodingMatching(&session_deps_, "gzip,sdch", "br", "", false);
- }
- TEST_F(HttpNetworkTransactionTest, MatchContentEncoding2) {
- CheckContentEncodingMatching(&session_deps_, "identity;q=1, *;q=0", "", "",
- true);
- }
- TEST_F(HttpNetworkTransactionTest, MatchContentEncoding3) {
- CheckContentEncodingMatching(&session_deps_, "identity;q=1, *;q=0", "gzip",
- "", false);
- }
- TEST_F(HttpNetworkTransactionTest, MatchContentEncoding4) {
- CheckContentEncodingMatching(&session_deps_, "identity;q=1, *;q=0", "gzip",
- "www.foo.com/other", true);
- }
- TEST_F(HttpNetworkTransactionTest, ProxyResolutionFailsSync) {
- ProxyConfig proxy_config;
- proxy_config.set_pac_url(GURL("http://fooproxyurl"));
- proxy_config.set_pac_mandatory(true);
- MockAsyncProxyResolver resolver;
- session_deps_.proxy_resolution_service =
- std::make_unique<ConfiguredProxyResolutionService>(
- std::make_unique<ProxyConfigServiceFixed>(ProxyConfigWithAnnotation(
- proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)),
- std::make_unique<FailingProxyResolverFactory>(), nullptr,
- /*quick_check_enabled=*/true);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(),
- IsError(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
- }
- TEST_F(HttpNetworkTransactionTest, ProxyResolutionFailsAsync) {
- ProxyConfig proxy_config;
- proxy_config.set_pac_url(GURL("http://fooproxyurl"));
- proxy_config.set_pac_mandatory(true);
- auto proxy_resolver_factory =
- std::make_unique<MockAsyncProxyResolverFactory>(false);
- auto* proxy_resolver_factory_ptr = proxy_resolver_factory.get();
- MockAsyncProxyResolver resolver;
- session_deps_.proxy_resolution_service =
- std::make_unique<ConfiguredProxyResolutionService>(
- std::make_unique<ProxyConfigServiceFixed>(ProxyConfigWithAnnotation(
- proxy_config, TRAFFIC_ANNOTATION_FOR_TESTS)),
- std::move(proxy_resolver_factory), nullptr,
- /*quick_check_enabled=*/true);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- proxy_resolver_factory_ptr->pending_requests()[0]->CompleteNowWithForwarder(
- ERR_FAILED, &resolver);
- EXPECT_THAT(callback.WaitForResult(),
- IsError(ERR_MANDATORY_PROXY_CONFIGURATION_FAILED));
- }
- TEST_F(HttpNetworkTransactionTest, NoSupportedProxies) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "QUIC myproxy.org:443", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.enable_quic = false;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- TestCompletionCallback callback;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- EXPECT_THAT(callback.WaitForResult(), IsError(ERR_NO_SUPPORTED_PROXIES));
- }
- //-----------------------------------------------------------------------------
- // Reporting tests
- #if BUILDFLAG(ENABLE_REPORTING)
- class HttpNetworkTransactionReportingTest
- : public HttpNetworkTransactionTest,
- public ::testing::WithParamInterface<bool> {
- protected:
- HttpNetworkTransactionReportingTest() {
- std::vector<base::Feature> required_features = {
- features::kPartitionNelAndReportingByNetworkIsolationKey};
- if (UseDocumentReporting()) {
- required_features.push_back(features::kDocumentReporting);
- }
- feature_list_.InitWithFeatures(required_features, {});
- }
- void SetUp() override {
- HttpNetworkTransactionTest::SetUp();
- auto test_reporting_context = std::make_unique<TestReportingContext>(
- &clock_, &tick_clock_, ReportingPolicy());
- test_reporting_context_ = test_reporting_context.get();
- session_deps_.reporting_service =
- ReportingService::CreateForTesting(std::move(test_reporting_context));
- }
- TestReportingContext* reporting_context() const {
- return test_reporting_context_;
- }
- void clear_reporting_service() {
- session_deps_.reporting_service.reset();
- test_reporting_context_ = nullptr;
- }
- // Makes an HTTPS request that should install a valid Reporting policy
- // using Report-To header.
- void RequestPolicy(CertStatus cert_status = 0) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL(url_);
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request.network_isolation_key = kNetworkIsolationKey;
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead reporting_header;
- reporting_header = MockRead(
- "Report-To: {\"group\": \"nel\", \"max_age\": 86400, "
- "\"endpoints\": [{\"url\": "
- "\"https://www.example.org/upload/\"}]}\r\n");
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- std::move(reporting_header),
- MockRead("\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider reads(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&reads);
- SSLSocketDataProvider ssl(ASYNC, OK);
- if (request.url.SchemeIsCryptographic()) {
- ssl.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
- ASSERT_TRUE(ssl.ssl_info.cert);
- ssl.ssl_info.cert_status = cert_status;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- }
- TestCompletionCallback callback;
- auto session = CreateSession(&session_deps_);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- }
- protected:
- bool UseDocumentReporting() const { return GetParam(); }
- std::string url_ = "https://www.example.org/";
- private:
- base::test::ScopedFeatureList feature_list_;
- raw_ptr<TestReportingContext> test_reporting_context_;
- };
- TEST_P(HttpNetworkTransactionReportingTest,
- DontProcessReportToHeaderNoService) {
- clear_reporting_service();
- RequestPolicy();
- // No crash.
- }
- TEST_P(HttpNetworkTransactionReportingTest, DontProcessReportToHeaderHttp) {
- url_ = "http://www.example.org/";
- RequestPolicy();
- EXPECT_EQ(0u, reporting_context()->cache()->GetEndpointCount());
- }
- TEST_P(HttpNetworkTransactionReportingTest, ProcessReportToHeaderHttps) {
- RequestPolicy();
- ASSERT_EQ(1u, reporting_context()->cache()->GetEndpointCount());
- const ReportingEndpoint endpoint =
- reporting_context()->cache()->GetEndpointForTesting(
- ReportingEndpointGroupKey(
- kNetworkIsolationKey,
- url::Origin::Create(GURL("https://www.example.org/")), "nel"),
- GURL("https://www.example.org/upload/"));
- EXPECT_TRUE(endpoint);
- }
- TEST_P(HttpNetworkTransactionReportingTest,
- DontProcessReportToHeaderInvalidHttps) {
- CertStatus cert_status = CERT_STATUS_COMMON_NAME_INVALID;
- RequestPolicy(cert_status);
- EXPECT_EQ(0u, reporting_context()->cache()->GetEndpointCount());
- }
- INSTANTIATE_TEST_SUITE_P(All,
- HttpNetworkTransactionReportingTest,
- ::testing::Bool());
- #endif // BUILDFLAG(ENABLE_REPORTING)
- //-----------------------------------------------------------------------------
- // Network Error Logging tests
- #if BUILDFLAG(ENABLE_REPORTING)
- namespace {
- const char kUserAgent[] = "Mozilla/1.0";
- const char kReferrer[] = "https://www.referrer.org/";
- } // namespace
- class HttpNetworkTransactionNetworkErrorLoggingTest
- : public HttpNetworkTransactionTest {
- protected:
- void SetUp() override {
- HttpNetworkTransactionTest::SetUp();
- auto network_error_logging_service =
- std::make_unique<TestNetworkErrorLoggingService>();
- test_network_error_logging_service_ = network_error_logging_service.get();
- session_deps_.network_error_logging_service =
- std::move(network_error_logging_service);
- extra_headers_.SetHeader("User-Agent", kUserAgent);
- extra_headers_.SetHeader("Referer", kReferrer);
- request_.method = "GET";
- request_.url = GURL(url_);
- request_.network_isolation_key = kNetworkIsolationKey;
- request_.extra_headers = extra_headers_;
- request_.reporting_upload_depth = reporting_upload_depth_;
- request_.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- }
- TestNetworkErrorLoggingService* network_error_logging_service() const {
- return test_network_error_logging_service_;
- }
- void clear_network_error_logging_service() {
- session_deps_.network_error_logging_service.reset();
- test_network_error_logging_service_ = nullptr;
- }
- // Makes an HTTPS request that should install a valid NEL policy.
- void RequestPolicy(CertStatus cert_status = 0) {
- std::string extra_header_string = extra_headers_.ToString();
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"),
- MockWrite(ASYNC, extra_header_string.data(),
- extra_header_string.size()),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("NEL: {\"report_to\": \"nel\", \"max_age\": 86400}\r\n"),
- MockRead("\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider reads(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&reads);
- SSLSocketDataProvider ssl(ASYNC, OK);
- if (request_.url.SchemeIsCryptographic()) {
- ssl.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
- ASSERT_TRUE(ssl.ssl_info.cert);
- ssl.ssl_info.cert_status = cert_status;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- }
- TestCompletionCallback callback;
- auto session = CreateSession(&session_deps_);
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request_, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- }
- void CheckReport(size_t index,
- int status_code,
- int error_type,
- IPAddress server_ip = IPAddress::IPv4Localhost()) {
- ASSERT_LT(index, network_error_logging_service()->errors().size());
- const NetworkErrorLoggingService::RequestDetails& error =
- network_error_logging_service()->errors()[index];
- EXPECT_EQ(url_, error.uri);
- EXPECT_EQ(kNetworkIsolationKey, error.network_isolation_key);
- EXPECT_EQ(kReferrer, error.referrer);
- EXPECT_EQ(kUserAgent, error.user_agent);
- EXPECT_EQ(server_ip, error.server_ip);
- EXPECT_EQ("http/1.1", error.protocol);
- EXPECT_EQ("GET", error.method);
- EXPECT_EQ(status_code, error.status_code);
- EXPECT_EQ(error_type, error.type);
- EXPECT_EQ(0, error.reporting_upload_depth);
- }
- protected:
- std::string url_ = "https://www.example.org/";
- CertStatus cert_status_ = 0;
- HttpRequestInfo request_;
- HttpRequestHeaders extra_headers_;
- int reporting_upload_depth_ = 0;
- private:
- raw_ptr<TestNetworkErrorLoggingService> test_network_error_logging_service_;
- };
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- DontProcessNelHeaderNoService) {
- clear_network_error_logging_service();
- RequestPolicy();
- // No crash.
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- DontProcessNelHeaderHttp) {
- url_ = "http://www.example.org/";
- request_.url = GURL(url_);
- RequestPolicy();
- EXPECT_EQ(0u, network_error_logging_service()->headers().size());
- }
- // Don't set NEL policies received on a proxied connection.
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- DontProcessNelHeaderProxy) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- session_deps_.net_log = NetLog::Get();
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("NEL: {\"report_to\": \"nel\", \"max_age\": 86400}\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl(ASYNC, OK);
- ssl.ssl_info.cert =
- ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
- ASSERT_TRUE(ssl.ssl_info.cert);
- ssl.ssl_info.cert_status = 0;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback1;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback1.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback1.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_TRUE(response->was_fetched_via_proxy);
- // No NEL header was set.
- EXPECT_EQ(0u, network_error_logging_service()->headers().size());
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, ProcessNelHeaderHttps) {
- RequestPolicy();
- ASSERT_EQ(1u, network_error_logging_service()->headers().size());
- const auto& header = network_error_logging_service()->headers()[0];
- EXPECT_EQ(kNetworkIsolationKey, header.network_isolation_key);
- EXPECT_EQ(url::Origin::Create(GURL("https://www.example.org/")),
- header.origin);
- EXPECT_EQ(IPAddress::IPv4Localhost(), header.received_ip_address);
- EXPECT_EQ("{\"report_to\": \"nel\", \"max_age\": 86400}", header.value);
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- DontProcessNelHeaderInvalidHttps) {
- CertStatus cert_status = CERT_STATUS_COMMON_NAME_INVALID;
- RequestPolicy(cert_status);
- EXPECT_EQ(0u, network_error_logging_service()->headers().size());
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, CreateReportSuccess) {
- RequestPolicy();
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- CheckReport(0 /* index */, 200 /* status_code */, OK);
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- CreateReportDNSErrorAfterStartSync) {
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- session_deps_.host_resolver->set_synchronous_mode(true);
- session_deps_.host_resolver->rules()->AddRule(GURL(url_).host(),
- ERR_NAME_NOT_RESOLVED);
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_NAME_NOT_RESOLVED));
- trans.reset();
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- CheckReport(0 /* index */, 0 /* status_code */, ERR_NAME_NOT_RESOLVED,
- IPAddress() /* server_ip */);
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- CreateReportDNSErrorAfterStartAsync) {
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- session_deps_.host_resolver->set_synchronous_mode(false);
- session_deps_.host_resolver->rules()->AddRule(GURL(url_).host(),
- ERR_NAME_NOT_RESOLVED);
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_NAME_NOT_RESOLVED));
- trans.reset();
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- CheckReport(0 /* index */, 0 /* status_code */, ERR_NAME_NOT_RESOLVED,
- IPAddress() /* server_ip */);
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- CreateReportErrorAfterStart) {
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- MockConnect mock_connect(SYNCHRONOUS, ERR_CONNECTION_REFUSED);
- StaticSocketDataProvider data;
- data.set_connect_data(mock_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_CONNECTION_REFUSED));
- trans.reset();
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- CheckReport(0 /* index */, 0 /* status_code */, ERR_CONNECTION_REFUSED,
- IPAddress::IPv4Localhost() /* server_ip */);
- }
- // Same as above except the error is ASYNC
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- CreateReportErrorAfterStartAsync) {
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED);
- StaticSocketDataProvider data;
- data.set_connect_data(mock_connect);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_CONNECTION_REFUSED));
- trans.reset();
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- CheckReport(0 /* index */, 0 /* status_code */, ERR_CONNECTION_REFUSED,
- IPAddress::IPv4Localhost() /* server_ip */);
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- CreateReportReadBodyError) {
- std::string extra_header_string = extra_headers_.ToString();
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"),
- MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"), // wrong content length
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider reads(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&reads);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- // Log start time
- base::TimeTicks start_time = base::TimeTicks::Now();
- TestCompletionCallback callback;
- auto session = CreateSession(&session_deps_);
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_THAT(rv, IsError(ERR_CONTENT_LENGTH_MISMATCH));
- trans.reset();
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- CheckReport(0 /* index */, 200 /* status_code */,
- ERR_CONTENT_LENGTH_MISMATCH);
- const NetworkErrorLoggingService::RequestDetails& error =
- network_error_logging_service()->errors()[0];
- EXPECT_LE(error.elapsed_time, base::TimeTicks::Now() - start_time);
- }
- // Same as above except the final read is ASYNC.
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- CreateReportReadBodyErrorAsync) {
- std::string extra_header_string = extra_headers_.ToString();
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"),
- MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"), // wrong content length
- MockRead("hello world"),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider reads(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&reads);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- // Log start time
- base::TimeTicks start_time = base::TimeTicks::Now();
- TestCompletionCallback callback;
- auto session = CreateSession(&session_deps_);
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
- std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_THAT(rv, IsError(ERR_CONTENT_LENGTH_MISMATCH));
- trans.reset();
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- CheckReport(0 /* index */, 200 /* status_code */,
- ERR_CONTENT_LENGTH_MISMATCH);
- const NetworkErrorLoggingService::RequestDetails& error =
- network_error_logging_service()->errors()[0];
- EXPECT_LE(error.elapsed_time, base::TimeTicks::Now() - start_time);
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- CreateReportRestartWithAuth) {
- std::string extra_header_string = extra_headers_.ToString();
- static const base::TimeDelta kSleepDuration = base::Milliseconds(10);
- MockWrite data_writes1[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"),
- MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- // Give a couple authenticate options (only the middle one is actually
- // supported).
- MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed.
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- // Large content-length -- won't matter, as connection will be reset.
- MockRead("Content-Length: 10000\r\n\r\n"),
- MockRead(SYNCHRONOUS, ERR_FAILED),
- };
- // After calling trans->RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite data_writes2[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n"),
- MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 200 OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl1(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- base::TimeTicks start_time = base::TimeTicks::Now();
- base::TimeTicks restart_time;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback1;
- int rv = trans->Start(&request_, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(callback1.GetResult(rv), IsOk());
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- TestCompletionCallback callback2;
- // Wait 10 ms then restart with auth
- FastForwardBy(kSleepDuration);
- restart_time = base::TimeTicks::Now();
- rv =
- trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(callback2.GetResult(rv), IsOk());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- trans.reset();
- // One 401 report for the auth challenge, then a 200 report for the successful
- // retry. Note that we don't report the error draining the body, as the first
- // request already generated a report for the auth challenge.
- ASSERT_EQ(2u, network_error_logging_service()->errors().size());
- // Check error report contents
- CheckReport(0 /* index */, 401 /* status_code */, OK);
- CheckReport(1 /* index */, 200 /* status_code */, OK);
- const NetworkErrorLoggingService::RequestDetails& error1 =
- network_error_logging_service()->errors()[0];
- const NetworkErrorLoggingService::RequestDetails& error2 =
- network_error_logging_service()->errors()[1];
- // Sanity-check elapsed time values
- EXPECT_EQ(error1.elapsed_time, restart_time - start_time - kSleepDuration);
- // Check that the start time is refreshed when restarting with auth.
- EXPECT_EQ(error2.elapsed_time, base::TimeTicks::Now() - restart_time);
- }
- // Same as above, except draining the body before restarting fails
- // asynchronously.
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- CreateReportRestartWithAuthAsync) {
- std::string extra_header_string = extra_headers_.ToString();
- static const base::TimeDelta kSleepDuration = base::Milliseconds(10);
- MockWrite data_writes1[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"),
- MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.0 401 Unauthorized\r\n"),
- // Give a couple authenticate options (only the middle one is actually
- // supported).
- MockRead("WWW-Authenticate: Basic invalid\r\n"), // Malformed.
- MockRead("WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("WWW-Authenticate: UNSUPPORTED realm=\"FOO\"\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- // Large content-length -- won't matter, as connection will be reset.
- MockRead("Content-Length: 10000\r\n\r\n"),
- MockRead(ASYNC, ERR_FAILED),
- };
- // After calling trans->RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite data_writes2[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Authorization: Basic Zm9vOmJhcg==\r\n"),
- MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()),
- };
- // Lastly, the server responds with the actual content.
- MockRead data_reads2[] = {
- MockRead("HTTP/1.0 200 OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl1(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- base::TimeTicks start_time = base::TimeTicks::Now();
- base::TimeTicks restart_time;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback1;
- int rv = trans->Start(&request_, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(callback1.GetResult(rv), IsOk());
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- TestCompletionCallback callback2;
- // Wait 10 ms then restart with auth
- FastForwardBy(kSleepDuration);
- restart_time = base::TimeTicks::Now();
- rv =
- trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(callback2.GetResult(rv), IsOk());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- trans.reset();
- // One 401 report for the auth challenge, then a 200 report for the successful
- // retry. Note that we don't report the error draining the body, as the first
- // request already generated a report for the auth challenge.
- ASSERT_EQ(2u, network_error_logging_service()->errors().size());
- // Check error report contents
- CheckReport(0 /* index */, 401 /* status_code */, OK);
- CheckReport(1 /* index */, 200 /* status_code */, OK);
- const NetworkErrorLoggingService::RequestDetails& error1 =
- network_error_logging_service()->errors()[0];
- const NetworkErrorLoggingService::RequestDetails& error2 =
- network_error_logging_service()->errors()[1];
- // Sanity-check elapsed time values
- EXPECT_EQ(error1.elapsed_time, restart_time - start_time - kSleepDuration);
- // Check that the start time is refreshed when restarting with auth.
- EXPECT_EQ(error2.elapsed_time, base::TimeTicks::Now() - restart_time);
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- CreateReportRetryKeepAliveConnectionReset) {
- std::string extra_header_string = extra_headers_.ToString();
- MockWrite data_writes1[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"),
- MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"),
- MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
- MockRead("hello"),
- // Connection is reset
- MockRead(ASYNC, ERR_CONNECTION_RESET),
- };
- // Successful retry
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
- MockRead("world"),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl1(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans1 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback1;
- int rv = trans1->Start(&request_, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(callback1.GetResult(rv), IsOk());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(trans1.get(), &response_data), IsOk());
- EXPECT_EQ("hello", response_data);
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- auto trans2 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback2;
- rv = trans2->Start(&request_, callback2.callback(), NetLogWithSource());
- EXPECT_THAT(callback2.GetResult(rv), IsOk());
- ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
- EXPECT_EQ("world", response_data);
- trans1.reset();
- trans2.reset();
- // One OK report from first request, then a ERR_CONNECTION_RESET report from
- // the second request, then an OK report from the successful retry.
- ASSERT_EQ(3u, network_error_logging_service()->errors().size());
- // Check error report contents
- CheckReport(0 /* index */, 200 /* status_code */, OK);
- CheckReport(1 /* index */, 0 /* status_code */, ERR_CONNECTION_RESET);
- CheckReport(2 /* index */, 200 /* status_code */, OK);
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- CreateReportRetryKeepAlive408) {
- std::string extra_header_string = extra_headers_.ToString();
- MockWrite data_writes1[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"),
- MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"),
- MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
- MockRead("hello"),
- // 408 Request Timeout
- MockRead(SYNCHRONOUS,
- "HTTP/1.1 408 Request Timeout\r\n"
- "Connection: Keep-Alive\r\n"
- "Content-Length: 6\r\n\r\n"
- "Pickle"),
- };
- // Successful retry
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"),
- MockRead("world"),
- MockRead(ASYNC, OK),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- StaticSocketDataProvider data2(data_reads2, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl1(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans1 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback1;
- int rv = trans1->Start(&request_, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(callback1.GetResult(rv), IsOk());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(trans1.get(), &response_data), IsOk());
- EXPECT_EQ("hello", response_data);
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- auto trans2 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback2;
- rv = trans2->Start(&request_, callback2.callback(), NetLogWithSource());
- EXPECT_THAT(callback2.GetResult(rv), IsOk());
- ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
- EXPECT_EQ("world", response_data);
- trans1.reset();
- trans2.reset();
- // One 200 report from first request, then a 408 report from
- // the second request, then a 200 report from the successful retry.
- ASSERT_EQ(3u, network_error_logging_service()->errors().size());
- // Check error report contents
- CheckReport(0 /* index */, 200 /* status_code */, OK);
- CheckReport(1 /* index */, 408 /* status_code */, OK);
- CheckReport(2 /* index */, 200 /* status_code */, OK);
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- CreateReportRetry421WithoutConnectionPooling) {
- // Two hosts resolve to the same IP address.
- const std::string ip_addr = "1.2.3.4";
- IPAddress ip;
- ASSERT_TRUE(ip.AssignFromIPLiteral(ip_addr));
- IPEndPoint peer_addr = IPEndPoint(ip, 443);
- session_deps_.host_resolver = std::make_unique<MockCachingHostResolver>();
- session_deps_.host_resolver->rules()->AddRule("www.example.org", ip_addr);
- session_deps_.host_resolver->rules()->AddRule("mail.example.org", ip_addr);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Two requests on the first connection.
- spdy::SpdySerializedFrame req1(
- spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
- spdy_util_.UpdateWithStreamDestruction(1);
- spdy::SpdySerializedFrame req2(
- spdy_util_.ConstructSpdyGet("https://mail.example.org", 3, LOWEST));
- spdy::SpdySerializedFrame rst(
- spdy_util_.ConstructSpdyRstStream(3, spdy::ERROR_CODE_CANCEL));
- MockWrite writes1[] = {
- CreateMockWrite(req1, 0),
- CreateMockWrite(req2, 3),
- CreateMockWrite(rst, 6),
- };
- // The first one succeeds, the second gets error 421 Misdirected Request.
- spdy::SpdySerializedFrame resp1(
- spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
- spdy::Http2HeaderBlock response_headers;
- response_headers[spdy::kHttp2StatusHeader] = "421";
- spdy::SpdySerializedFrame resp2(
- spdy_util_.ConstructSpdyReply(3, std::move(response_headers)));
- MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
- CreateMockRead(resp2, 4), MockRead(ASYNC, 0, 5)};
- MockConnect connect1(ASYNC, OK, peer_addr);
- SequencedSocketData data1(connect1, reads1, writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- AddSSLSocketData();
- // Retry the second request on a second connection.
- SpdyTestUtil spdy_util2;
- spdy::SpdySerializedFrame req3(
- spdy_util2.ConstructSpdyGet("https://mail.example.org", 1, LOWEST));
- MockWrite writes2[] = {
- CreateMockWrite(req3, 0),
- };
- spdy::SpdySerializedFrame resp3(
- spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame body3(spdy_util2.ConstructSpdyDataFrame(1, true));
- MockRead reads2[] = {CreateMockRead(resp3, 1), CreateMockRead(body3, 2),
- MockRead(ASYNC, 0, 3)};
- MockConnect connect2(ASYNC, OK, peer_addr);
- SequencedSocketData data2(connect2, reads2, writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- AddSSLSocketData();
- // Preload mail.example.org into HostCache.
- int rv = session_deps_.host_resolver->LoadIntoCache(
- HostPortPair("mail.example.org", 443), NetworkIsolationKey(),
- absl::nullopt);
- EXPECT_THAT(rv, IsOk());
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://www.example.org/");
- request1.load_flags = 0;
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto trans1 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans1->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- std::string response_data;
- ASSERT_THAT(ReadTransaction(trans1.get(), &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- trans1.reset();
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://mail.example.org/");
- request2.load_flags = 0;
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- auto trans2 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans2->Start(&request2, callback.callback(),
- NetLogWithSource::Make(NetLogSourceType::NONE));
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- response = trans2->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
- EXPECT_TRUE(response->was_fetched_via_spdy);
- EXPECT_TRUE(response->was_alpn_negotiated);
- ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
- EXPECT_EQ("hello!", response_data);
- trans2.reset();
- // One 200 report from the first request, then a 421 report from the
- // second request, then a 200 report from the successful retry.
- ASSERT_EQ(3u, network_error_logging_service()->errors().size());
- // Check error report contents
- const NetworkErrorLoggingService::RequestDetails& error1 =
- network_error_logging_service()->errors()[0];
- EXPECT_EQ(GURL("https://www.example.org/"), error1.uri);
- EXPECT_TRUE(error1.referrer.is_empty());
- EXPECT_EQ("", error1.user_agent);
- EXPECT_EQ(ip, error1.server_ip);
- EXPECT_EQ("h2", error1.protocol);
- EXPECT_EQ("GET", error1.method);
- EXPECT_EQ(200, error1.status_code);
- EXPECT_EQ(OK, error1.type);
- EXPECT_EQ(0, error1.reporting_upload_depth);
- const NetworkErrorLoggingService::RequestDetails& error2 =
- network_error_logging_service()->errors()[1];
- EXPECT_EQ(GURL("https://mail.example.org/"), error2.uri);
- EXPECT_TRUE(error2.referrer.is_empty());
- EXPECT_EQ("", error2.user_agent);
- EXPECT_EQ(ip, error2.server_ip);
- EXPECT_EQ("h2", error2.protocol);
- EXPECT_EQ("GET", error2.method);
- EXPECT_EQ(421, error2.status_code);
- EXPECT_EQ(OK, error2.type);
- EXPECT_EQ(0, error2.reporting_upload_depth);
- const NetworkErrorLoggingService::RequestDetails& error3 =
- network_error_logging_service()->errors()[2];
- EXPECT_EQ(GURL("https://mail.example.org/"), error3.uri);
- EXPECT_TRUE(error3.referrer.is_empty());
- EXPECT_EQ("", error3.user_agent);
- EXPECT_EQ(ip, error3.server_ip);
- EXPECT_EQ("h2", error3.protocol);
- EXPECT_EQ("GET", error3.method);
- EXPECT_EQ(200, error3.status_code);
- EXPECT_EQ(OK, error3.type);
- EXPECT_EQ(0, error3.reporting_upload_depth);
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- CreateReportCancelAfterStart) {
- StaticSocketDataProvider data;
- data.set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- auto session = CreateSession(&session_deps_);
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
- EXPECT_EQ(rv, ERR_IO_PENDING);
- // Cancel after start.
- trans.reset();
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- CheckReport(0 /* index */, 0 /* status_code */, ERR_ABORTED,
- IPAddress() /* server_ip */);
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- CreateReportCancelBeforeReadingBody) {
- std::string extra_header_string = extra_headers_.ToString();
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"),
- MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"), // Body is never read.
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback;
- auto session = CreateSession(&session_deps_);
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- EXPECT_TRUE(response->headers);
- EXPECT_EQ("HTTP/1.0 200 OK", response->headers->GetStatusLine());
- // Cancel before reading the body.
- trans.reset();
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- CheckReport(0 /* index */, 200 /* status_code */, ERR_ABORTED);
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, DontCreateReportHttp) {
- RequestPolicy();
- EXPECT_EQ(1u, network_error_logging_service()->headers().size());
- EXPECT_EQ(1u, network_error_logging_service()->errors().size());
- // Make HTTP request
- std::string extra_header_string = extra_headers_.ToString();
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n\r\n"),
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"),
- MockWrite(ASYNC, extra_header_string.data(), extra_header_string.size()),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- // Insecure url
- url_ = "http://www.example.org/";
- request_.url = GURL(url_);
- TestCompletionCallback callback;
- auto session = CreateSession(&session_deps_);
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- // Insecure request does not generate a report
- EXPECT_EQ(1u, network_error_logging_service()->errors().size());
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- DontCreateReportHttpError) {
- RequestPolicy();
- EXPECT_EQ(1u, network_error_logging_service()->headers().size());
- EXPECT_EQ(1u, network_error_logging_service()->errors().size());
- // Make HTTP request that fails
- MockRead data_reads[] = {
- MockRead("hello world"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, base::span<MockWrite>());
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- url_ = "http://www.originwithoutpolicy.com:2000/";
- request_.url = GURL(url_);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_INVALID_HTTP_RESPONSE));
- // Insecure request does not generate a report, regardless of existence of a
- // policy for the origin.
- EXPECT_EQ(1u, network_error_logging_service()->errors().size());
- }
- // Don't report on proxy auth challenges, don't report if connecting through a
- // proxy.
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, DontCreateReportProxy) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Configure against proxy server "myproxy:70".
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Since we have proxy, should try to establish tunnel.
- MockWrite data_writes1[] = {
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- // The proxy responds to the connect with a 407, using a non-persistent
- // connection.
- MockRead data_reads1[] = {
- // No credentials.
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("Proxy-Connection: close\r\n\r\n"),
- };
- MockWrite data_writes2[] = {
- // After calling trans->RestartWithAuth(), this is the request we should
- // be issuing -- the final header line contains the credentials.
- MockWrite("CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 5\r\n\r\n"),
- MockRead(SYNCHRONOUS, "hello"),
- };
- StaticSocketDataProvider data1(data_reads1, data_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- StaticSocketDataProvider data2(data_reads2, data_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- TestCompletionCallback callback1;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(callback1.GetResult(rv), IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- EXPECT_EQ(407, response->headers->response_code());
- std::string response_data;
- rv = ReadTransaction(trans.get(), &response_data);
- EXPECT_THAT(rv, IsError(ERR_TUNNEL_CONNECTION_FAILED));
- // No NEL report is generated for the 407.
- EXPECT_EQ(0u, network_error_logging_service()->errors().size());
- TestCompletionCallback callback2;
- rv =
- trans->RestartWithAuth(AuthCredentials(kFoo, kBar), callback2.callback());
- EXPECT_THAT(callback2.GetResult(rv), IsOk());
- response = trans->GetResponseInfo();
- EXPECT_EQ(200, response->headers->response_code());
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello", response_data);
- trans.reset();
- // No NEL report is generated because we are behind a proxy.
- EXPECT_EQ(0u, network_error_logging_service()->errors().size());
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest,
- ReportContainsUploadDepth) {
- reporting_upload_depth_ = 7;
- request_.reporting_upload_depth = reporting_upload_depth_;
- RequestPolicy();
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- const NetworkErrorLoggingService::RequestDetails& error =
- network_error_logging_service()->errors()[0];
- EXPECT_EQ(7, error.reporting_upload_depth);
- }
- TEST_F(HttpNetworkTransactionNetworkErrorLoggingTest, ReportElapsedTime) {
- std::string extra_header_string = extra_headers_.ToString();
- static const base::TimeDelta kSleepDuration = base::Milliseconds(10);
- std::vector<MockWrite> data_writes = {
- MockWrite(ASYNC, 0,
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"),
- MockWrite(ASYNC, 1, extra_header_string.data()),
- };
- std::vector<MockRead> data_reads = {
- // Write one byte of the status line, followed by a pause.
- MockRead(ASYNC, 2, "H"),
- MockRead(ASYNC, ERR_IO_PENDING, 3),
- MockRead(ASYNC, 4, "TTP/1.1 200 OK\r\n\r\n"),
- MockRead(ASYNC, 5, "hello world"),
- MockRead(SYNCHRONOUS, OK, 6),
- };
- SequencedSocketData data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(ASYNC, OK);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback;
- int rv = trans->Start(&request_, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- data.RunUntilPaused();
- ASSERT_TRUE(data.IsPaused());
- FastForwardBy(kSleepDuration);
- data.Resume();
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data;
- ASSERT_THAT(ReadTransaction(trans.get(), &response_data), IsOk());
- EXPECT_EQ("hello world", response_data);
- trans.reset();
- ASSERT_EQ(1u, network_error_logging_service()->errors().size());
- CheckReport(0 /* index */, 200 /* status_code */, OK);
- const NetworkErrorLoggingService::RequestDetails& error =
- network_error_logging_service()->errors()[0];
- // Sanity-check elapsed time in error report
- EXPECT_EQ(kSleepDuration, error.elapsed_time);
- }
- #endif // BUILDFLAG(ENABLE_REPORTING)
- TEST_F(HttpNetworkTransactionTest, AlwaysFailRequestToCache) {
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://example.org/");
- request.load_flags = LOAD_ONLY_FROM_CACHE;
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- TestCompletionCallback callback1;
- int rv = trans.Start(&request, callback1.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_CACHE_MISS));
- }
- TEST_F(HttpNetworkTransactionTest, ZeroRTTDoesntConfirm) {
- static const base::TimeDelta kDelay = base::Milliseconds(10);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 1\r\n\r\n"),
- MockRead(SYNCHRONOUS, "1"),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- ssl.connect_callback = FastForwardByCallback(kDelay);
- ssl.confirm = MockConfirm(SYNCHRONOUS, OK);
- ssl.confirm_callback = FastForwardByCallback(kDelay);
- session_deps_.enable_early_data = true;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- base::TimeTicks start_time = base::TimeTicks::Now();
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(1, response->headers->GetContentLength());
- // Check that ConfirmHandshake wasn't called.
- ASSERT_FALSE(ssl.ConfirmDataConsumed());
- ASSERT_TRUE(ssl.WriteBeforeConfirm());
- // The handshake time should include the time it took to run Connect(), but
- // not ConfirmHandshake().
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
- EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
- EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
- EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + kDelay);
- EXPECT_EQ(load_timing_info.connect_timing.connect_end, start_time + kDelay);
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- TEST_F(HttpNetworkTransactionTest, ZeroRTTSyncConfirmSyncWrite) {
- static const base::TimeDelta kDelay = base::Milliseconds(10);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite(SYNCHRONOUS,
- "POST / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 0\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 1\r\n\r\n"),
- MockRead(SYNCHRONOUS, "1"),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- ssl.connect_callback = FastForwardByCallback(kDelay);
- ssl.confirm = MockConfirm(SYNCHRONOUS, OK);
- ssl.confirm_callback = FastForwardByCallback(kDelay);
- session_deps_.enable_early_data = true;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- base::TimeTicks start_time = base::TimeTicks::Now();
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(1, response->headers->GetContentLength());
- // Check that the Write didn't get called before ConfirmHandshake completed.
- ASSERT_FALSE(ssl.WriteBeforeConfirm());
- // The handshake time should include the time it took to run Connect(), but
- // not ConfirmHandshake(). If ConfirmHandshake() returns synchronously, we
- // assume the connection did not negotiate 0-RTT or the handshake was already
- // confirmed.
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
- EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
- EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
- EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + kDelay);
- EXPECT_EQ(load_timing_info.connect_timing.connect_end, start_time + kDelay);
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- TEST_F(HttpNetworkTransactionTest, ZeroRTTSyncConfirmAsyncWrite) {
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite(ASYNC,
- "POST / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 0\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 1\r\n\r\n"),
- MockRead(SYNCHRONOUS, "1"),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- ssl.confirm = MockConfirm(SYNCHRONOUS, OK);
- session_deps_.enable_early_data = true;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(1, response->headers->GetContentLength());
- // Check that the Write didn't get called before ConfirmHandshake completed.
- ASSERT_FALSE(ssl.WriteBeforeConfirm());
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- TEST_F(HttpNetworkTransactionTest, ZeroRTTAsyncConfirmSyncWrite) {
- static const base::TimeDelta kDelay = base::Milliseconds(10);
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite(SYNCHRONOUS,
- "POST / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 0\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 1\r\n\r\n"),
- MockRead(SYNCHRONOUS, "1"),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- ssl.connect_callback = FastForwardByCallback(kDelay);
- ssl.confirm = MockConfirm(ASYNC, OK);
- ssl.confirm_callback = FastForwardByCallback(kDelay);
- session_deps_.enable_early_data = true;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- base::TimeTicks start_time = base::TimeTicks::Now();
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(1, response->headers->GetContentLength());
- // Check that the Write didn't get called before ConfirmHandshake completed.
- ASSERT_FALSE(ssl.WriteBeforeConfirm());
- // The handshake time should include the time it took to run Connect() and
- // ConfirmHandshake().
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
- EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
- EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
- EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + 2 * kDelay);
- EXPECT_EQ(load_timing_info.connect_timing.connect_end,
- start_time + 2 * kDelay);
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- TEST_F(HttpNetworkTransactionTest, ZeroRTTAsyncConfirmAsyncWrite) {
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite(ASYNC,
- "POST / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 0\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 1\r\n\r\n"),
- MockRead(SYNCHRONOUS, "1"),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- ssl.confirm = MockConfirm(ASYNC, OK);
- session_deps_.enable_early_data = true;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(1, response->headers->GetContentLength());
- // Check that the Write didn't get called before ConfirmHandshake completed.
- ASSERT_FALSE(ssl.WriteBeforeConfirm());
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // 0-RTT rejects are handled at HttpNetworkTransaction.
- TEST_F(HttpNetworkTransactionTest, ZeroRTTReject) {
- enum class RejectType {
- kRead,
- kWrite,
- kConfirm,
- };
- for (RejectType type :
- {RejectType::kRead, RejectType::kWrite, RejectType::kConfirm}) {
- SCOPED_TRACE(static_cast<int>(type));
- for (Error reject_error :
- {ERR_EARLY_DATA_REJECTED, ERR_WRONG_VERSION_ON_EARLY_DATA}) {
- SCOPED_TRACE(reject_error);
- session_deps_.socket_factory =
- std::make_unique<MockClientSocketFactory>();
- HttpRequestInfo request;
- request.method = type == RejectType::kConfirm ? "POST" : "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // The first request fails.
- std::vector<MockWrite> data1_writes;
- std::vector<MockRead> data1_reads;
- SSLSocketDataProvider ssl1(SYNCHRONOUS, OK);
- switch (type) {
- case RejectType::kRead:
- data1_writes.emplace_back(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n");
- data1_reads.emplace_back(ASYNC, reject_error);
- // Cause ConfirmHandshake to hang (it should not be called).
- ssl1.confirm = MockConfirm(SYNCHRONOUS, ERR_IO_PENDING);
- break;
- case RejectType::kWrite:
- data1_writes.emplace_back(ASYNC, reject_error);
- // Cause ConfirmHandshake to hang (it should not be called).
- ssl1.confirm = MockConfirm(SYNCHRONOUS, ERR_IO_PENDING);
- break;
- case RejectType::kConfirm:
- // The request never gets far enough to read or write.
- ssl1.confirm = MockConfirm(ASYNC, reject_error);
- break;
- }
- StaticSocketDataProvider data1(data1_reads, data1_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.enable_early_data = true;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- // The retry succeeds.
- //
- // TODO(https://crbug.com/950705): If |reject_error| is
- // ERR_EARLY_DATA_REJECTED, the retry should happen over the same socket.
- MockWrite data2_writes[] = {
- request.method == "POST"
- ? MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 0\r\n\r\n")
- : MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead data2_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 1\r\n\r\n"),
- MockRead(SYNCHRONOUS, "1"),
- };
- StaticSocketDataProvider data2(data2_reads, data2_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl2(SYNCHRONOUS, OK);
- ssl2.confirm = MockConfirm(ASYNC, OK);
- session_deps_.enable_early_data = true;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- std::unique_ptr<HttpNetworkSession> session(
- CreateSession(&session_deps_));
- TestCompletionCallback callback;
- auto trans = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
- session.get());
- EXPECT_THAT(callback.GetResult(trans->Start(&request, callback.callback(),
- NetLogWithSource())),
- IsOk());
- const HttpResponseInfo* response = trans->GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(200, response->headers->response_code());
- EXPECT_EQ(1, response->headers->GetContentLength());
- }
- }
- }
- TEST_F(HttpNetworkTransactionTest, ZeroRTTConfirmErrorSync) {
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 0\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 1\r\n\r\n"),
- MockRead(SYNCHRONOUS, "1"),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- ssl.confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
- session_deps_.enable_early_data = true;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_SSL_PROTOCOL_ERROR));
- // Check that the Write didn't get called before ConfirmHandshake completed.
- ASSERT_FALSE(ssl.WriteBeforeConfirm());
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- TEST_F(HttpNetworkTransactionTest, ZeroRTTConfirmErrorAsync) {
- HttpRequestInfo request;
- request.method = "POST";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- MockWrite data_writes[] = {
- MockWrite("POST / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 0\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"),
- MockRead("Content-Length: 1\r\n\r\n"),
- MockRead(SYNCHRONOUS, "1"),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- ssl.confirm = MockConfirm(ASYNC, ERR_SSL_PROTOCOL_ERROR);
- session_deps_.enable_early_data = true;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsError(ERR_SSL_PROTOCOL_ERROR));
- // Check that the Write didn't get called before ConfirmHandshake completed.
- ASSERT_FALSE(ssl.WriteBeforeConfirm());
- trans.reset();
- session->CloseAllConnections(ERR_FAILED, "Very good reason");
- }
- // Test the proxy and origin server each requesting both TLS client certificates
- // and HTTP auth. This is a regression test for https://crbug.com/946406.
- TEST_F(HttpNetworkTransactionTest, AuthEverything) {
- // Note these hosts must match the CheckBasic*Auth() functions.
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- auto cert_request_info_proxy = base::MakeRefCounted<SSLCertRequestInfo>();
- cert_request_info_proxy->host_and_port = HostPortPair("myproxy", 70);
- std::unique_ptr<FakeClientCertIdentity> identity_proxy =
- FakeClientCertIdentity::CreateFromCertAndKeyFiles(
- GetTestCertsDirectory(), "client_1.pem", "client_1.pk8");
- ASSERT_TRUE(identity_proxy);
- auto cert_request_info_origin = base::MakeRefCounted<SSLCertRequestInfo>();
- cert_request_info_origin->host_and_port =
- HostPortPair("www.example.org", 443);
- std::unique_ptr<FakeClientCertIdentity> identity_origin =
- FakeClientCertIdentity::CreateFromCertAndKeyFiles(
- GetTestCertsDirectory(), "client_2.pem", "client_2.pk8");
- ASSERT_TRUE(identity_origin);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // First, the client connects to the proxy, which requests a client
- // certificate.
- SSLSocketDataProvider ssl_proxy1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
- ssl_proxy1.cert_request_info = cert_request_info_proxy.get();
- ssl_proxy1.expected_send_client_cert = false;
- StaticSocketDataProvider data1;
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy1);
- // The client responds with a certificate on a new connection. The handshake
- // succeeds.
- SSLSocketDataProvider ssl_proxy2(ASYNC, OK);
- ssl_proxy2.expected_send_client_cert = true;
- ssl_proxy2.expected_client_cert = identity_proxy->certificate();
- // The client attempts an HTTP CONNECT, but the proxy requests basic auth.
- std::vector<MockWrite> mock_writes2;
- std::vector<MockRead> mock_reads2;
- mock_writes2.emplace_back(
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n");
- mock_reads2.emplace_back(
- "HTTP/1.1 407 Proxy Authentication Required\r\n"
- "Content-Length: 0\r\n"
- "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n");
- // The client retries with credentials.
- mock_writes2.emplace_back(
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- // Authenticate as proxyuser:proxypass.
- "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
- mock_reads2.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
- // The origin requests client certificates.
- SSLSocketDataProvider ssl_origin2(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
- ssl_origin2.cert_request_info = cert_request_info_origin.get();
- StaticSocketDataProvider data2(mock_reads2, mock_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy2);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin2);
- // The client responds to the origin client certificate request on a new
- // connection.
- SSLSocketDataProvider ssl_proxy3(ASYNC, OK);
- ssl_proxy3.expected_send_client_cert = true;
- ssl_proxy3.expected_client_cert = identity_proxy->certificate();
- std::vector<MockWrite> mock_writes3;
- std::vector<MockRead> mock_reads3;
- mock_writes3.emplace_back(
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- // Authenticate as proxyuser:proxypass.
- "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
- mock_reads3.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
- SSLSocketDataProvider ssl_origin3(ASYNC, OK);
- ssl_origin3.expected_send_client_cert = true;
- ssl_origin3.expected_client_cert = identity_origin->certificate();
- // The client sends the origin HTTP request, which results in another HTTP
- // auth request.
- mock_writes3.emplace_back(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n");
- mock_reads3.emplace_back(
- "HTTP/1.1 401 Unauthorized\r\n"
- "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Content-Length: 0\r\n\r\n");
- // The client retries with credentials, and the request finally succeeds.
- mock_writes3.emplace_back(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- // Authenticate as user:pass.
- "Authorization: Basic dXNlcjpwYXNz\r\n\r\n");
- mock_reads3.emplace_back(
- "HTTP/1.1 200 OK\r\n"
- "Content-Length: 0\r\n\r\n");
- // The client makes another request. This should reuse the socket with all
- // credentials cached.
- mock_writes3.emplace_back(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- // Authenticate as user:pass.
- "Authorization: Basic dXNlcjpwYXNz\r\n\r\n");
- mock_reads3.emplace_back(
- "HTTP/1.1 200 OK\r\n"
- "Content-Length: 0\r\n\r\n");
- StaticSocketDataProvider data3(mock_reads3, mock_writes3);
- session_deps_.socket_factory->AddSocketDataProvider(&data3);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy3);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin3);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Start the request.
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = callback.GetResult(
- trans->Start(&request, callback.callback(), NetLogWithSource()));
- // Handle the proxy client certificate challenge.
- ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
- SSLCertRequestInfo* cert_request_info =
- trans->GetResponseInfo()->cert_request_info.get();
- ASSERT_TRUE(cert_request_info);
- EXPECT_TRUE(cert_request_info->is_proxy);
- EXPECT_EQ(cert_request_info->host_and_port,
- cert_request_info_proxy->host_and_port);
- rv = callback.GetResult(trans->RestartWithCertificate(
- identity_proxy->certificate(), identity_proxy->ssl_private_key(),
- callback.callback()));
- // Handle the proxy HTTP auth challenge.
- ASSERT_THAT(rv, IsOk());
- EXPECT_EQ(407, trans->GetResponseInfo()->headers->response_code());
- EXPECT_TRUE(
- CheckBasicSecureProxyAuth(trans->GetResponseInfo()->auth_challenge));
- rv = callback.GetResult(trans->RestartWithAuth(
- AuthCredentials(u"proxyuser", u"proxypass"), callback.callback()));
- // Handle the origin client certificate challenge.
- ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
- cert_request_info = trans->GetResponseInfo()->cert_request_info.get();
- ASSERT_TRUE(cert_request_info);
- EXPECT_FALSE(cert_request_info->is_proxy);
- EXPECT_EQ(cert_request_info->host_and_port,
- cert_request_info_origin->host_and_port);
- rv = callback.GetResult(trans->RestartWithCertificate(
- identity_origin->certificate(), identity_origin->ssl_private_key(),
- callback.callback()));
- // Handle the origin HTTP auth challenge.
- ASSERT_THAT(rv, IsOk());
- EXPECT_EQ(401, trans->GetResponseInfo()->headers->response_code());
- EXPECT_TRUE(
- CheckBasicSecureServerAuth(trans->GetResponseInfo()->auth_challenge));
- rv = callback.GetResult(trans->RestartWithAuth(
- AuthCredentials(u"user", u"pass"), callback.callback()));
- // The request completes.
- ASSERT_THAT(rv, IsOk());
- EXPECT_EQ(200, trans->GetResponseInfo()->headers->response_code());
- // Make a second request. This time all credentials are cached.
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- ASSERT_THAT(callback.GetResult(trans->Start(&request, callback.callback(),
- NetLogWithSource())),
- IsOk());
- EXPECT_EQ(200, trans->GetResponseInfo()->headers->response_code());
- }
- // Test the proxy and origin server each requesting both TLS client certificates
- // and HTTP auth and each HTTP auth closing the connection. This is a regression
- // test for https://crbug.com/946406.
- TEST_F(HttpNetworkTransactionTest, AuthEverythingWithConnectClose) {
- // Note these hosts must match the CheckBasic*Auth() functions.
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- auto cert_request_info_proxy = base::MakeRefCounted<SSLCertRequestInfo>();
- cert_request_info_proxy->host_and_port = HostPortPair("myproxy", 70);
- std::unique_ptr<FakeClientCertIdentity> identity_proxy =
- FakeClientCertIdentity::CreateFromCertAndKeyFiles(
- GetTestCertsDirectory(), "client_1.pem", "client_1.pk8");
- ASSERT_TRUE(identity_proxy);
- auto cert_request_info_origin = base::MakeRefCounted<SSLCertRequestInfo>();
- cert_request_info_origin->host_and_port =
- HostPortPair("www.example.org", 443);
- std::unique_ptr<FakeClientCertIdentity> identity_origin =
- FakeClientCertIdentity::CreateFromCertAndKeyFiles(
- GetTestCertsDirectory(), "client_2.pem", "client_2.pk8");
- ASSERT_TRUE(identity_origin);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // First, the client connects to the proxy, which requests a client
- // certificate.
- SSLSocketDataProvider ssl_proxy1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
- ssl_proxy1.cert_request_info = cert_request_info_proxy.get();
- ssl_proxy1.expected_send_client_cert = false;
- StaticSocketDataProvider data1;
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy1);
- // The client responds with a certificate on a new connection. The handshake
- // succeeds.
- SSLSocketDataProvider ssl_proxy2(ASYNC, OK);
- ssl_proxy2.expected_send_client_cert = true;
- ssl_proxy2.expected_client_cert = identity_proxy->certificate();
- // The client attempts an HTTP CONNECT, but the proxy requests basic auth.
- std::vector<MockWrite> mock_writes2;
- std::vector<MockRead> mock_reads2;
- mock_writes2.emplace_back(
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n");
- mock_reads2.emplace_back(
- "HTTP/1.1 407 Proxy Authentication Required\r\n"
- "Content-Length: 0\r\n"
- "Proxy-Connection: close\r\n"
- "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n");
- StaticSocketDataProvider data2(mock_reads2, mock_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy2);
- // The client retries with credentials on a new connection.
- SSLSocketDataProvider ssl_proxy3(ASYNC, OK);
- ssl_proxy3.expected_send_client_cert = true;
- ssl_proxy3.expected_client_cert = identity_proxy->certificate();
- std::vector<MockWrite> mock_writes3;
- std::vector<MockRead> mock_reads3;
- mock_writes3.emplace_back(
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- // Authenticate as proxyuser:proxypass.
- "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
- mock_reads3.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
- // The origin requests client certificates.
- SSLSocketDataProvider ssl_origin3(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
- ssl_origin3.cert_request_info = cert_request_info_origin.get();
- StaticSocketDataProvider data3(mock_reads3, mock_writes3);
- session_deps_.socket_factory->AddSocketDataProvider(&data3);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy3);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin3);
- // The client responds to the origin client certificate request on a new
- // connection.
- SSLSocketDataProvider ssl_proxy4(ASYNC, OK);
- ssl_proxy4.expected_send_client_cert = true;
- ssl_proxy4.expected_client_cert = identity_proxy->certificate();
- std::vector<MockWrite> mock_writes4;
- std::vector<MockRead> mock_reads4;
- mock_writes4.emplace_back(
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- // Authenticate as proxyuser:proxypass.
- "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
- mock_reads4.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
- SSLSocketDataProvider ssl_origin4(ASYNC, OK);
- ssl_origin4.expected_send_client_cert = true;
- ssl_origin4.expected_client_cert = identity_origin->certificate();
- // The client sends the origin HTTP request, which results in another HTTP
- // auth request and closed connection.
- mock_writes4.emplace_back(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n");
- mock_reads4.emplace_back(
- "HTTP/1.1 401 Unauthorized\r\n"
- "WWW-Authenticate: Basic realm=\"MyRealm1\"\r\n"
- "Connection: close\r\n"
- "Content-Length: 0\r\n\r\n");
- StaticSocketDataProvider data4(mock_reads4, mock_writes4);
- session_deps_.socket_factory->AddSocketDataProvider(&data4);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy4);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin4);
- // The client retries with credentials on a new connection, and the request
- // finally succeeds.
- SSLSocketDataProvider ssl_proxy5(ASYNC, OK);
- ssl_proxy5.expected_send_client_cert = true;
- ssl_proxy5.expected_client_cert = identity_proxy->certificate();
- std::vector<MockWrite> mock_writes5;
- std::vector<MockRead> mock_reads5;
- mock_writes5.emplace_back(
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- // Authenticate as proxyuser:proxypass.
- "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
- mock_reads5.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
- SSLSocketDataProvider ssl_origin5(ASYNC, OK);
- ssl_origin5.expected_send_client_cert = true;
- ssl_origin5.expected_client_cert = identity_origin->certificate();
- mock_writes5.emplace_back(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- // Authenticate as user:pass.
- "Authorization: Basic dXNlcjpwYXNz\r\n\r\n");
- mock_reads5.emplace_back(
- "HTTP/1.1 200 OK\r\n"
- "Connection: close\r\n"
- "Content-Length: 0\r\n\r\n");
- StaticSocketDataProvider data5(mock_reads5, mock_writes5);
- session_deps_.socket_factory->AddSocketDataProvider(&data5);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy5);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin5);
- // The client makes a second request. This needs yet another connection, but
- // all credentials are cached.
- SSLSocketDataProvider ssl_proxy6(ASYNC, OK);
- ssl_proxy6.expected_send_client_cert = true;
- ssl_proxy6.expected_client_cert = identity_proxy->certificate();
- std::vector<MockWrite> mock_writes6;
- std::vector<MockRead> mock_reads6;
- mock_writes6.emplace_back(
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- // Authenticate as proxyuser:proxypass.
- "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
- mock_reads6.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
- SSLSocketDataProvider ssl_origin6(ASYNC, OK);
- ssl_origin6.expected_send_client_cert = true;
- ssl_origin6.expected_client_cert = identity_origin->certificate();
- mock_writes6.emplace_back(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n"
- // Authenticate as user:pass.
- "Authorization: Basic dXNlcjpwYXNz\r\n\r\n");
- mock_reads6.emplace_back(
- "HTTP/1.1 200 OK\r\n"
- "Connection: close\r\n"
- "Content-Length: 0\r\n\r\n");
- StaticSocketDataProvider data6(mock_reads6, mock_writes6);
- session_deps_.socket_factory->AddSocketDataProvider(&data6);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy6);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin6);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Start the request.
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = callback.GetResult(
- trans->Start(&request, callback.callback(), NetLogWithSource()));
- // Handle the proxy client certificate challenge.
- ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
- SSLCertRequestInfo* cert_request_info =
- trans->GetResponseInfo()->cert_request_info.get();
- ASSERT_TRUE(cert_request_info);
- EXPECT_TRUE(cert_request_info->is_proxy);
- EXPECT_EQ(cert_request_info->host_and_port,
- cert_request_info_proxy->host_and_port);
- rv = callback.GetResult(trans->RestartWithCertificate(
- identity_proxy->certificate(), identity_proxy->ssl_private_key(),
- callback.callback()));
- // Handle the proxy HTTP auth challenge.
- ASSERT_THAT(rv, IsOk());
- EXPECT_EQ(407, trans->GetResponseInfo()->headers->response_code());
- EXPECT_TRUE(
- CheckBasicSecureProxyAuth(trans->GetResponseInfo()->auth_challenge));
- rv = callback.GetResult(trans->RestartWithAuth(
- AuthCredentials(u"proxyuser", u"proxypass"), callback.callback()));
- // Handle the origin client certificate challenge.
- ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
- cert_request_info = trans->GetResponseInfo()->cert_request_info.get();
- ASSERT_TRUE(cert_request_info);
- EXPECT_FALSE(cert_request_info->is_proxy);
- EXPECT_EQ(cert_request_info->host_and_port,
- cert_request_info_origin->host_and_port);
- rv = callback.GetResult(trans->RestartWithCertificate(
- identity_origin->certificate(), identity_origin->ssl_private_key(),
- callback.callback()));
- // Handle the origin HTTP auth challenge.
- ASSERT_THAT(rv, IsOk());
- EXPECT_EQ(401, trans->GetResponseInfo()->headers->response_code());
- EXPECT_TRUE(
- CheckBasicSecureServerAuth(trans->GetResponseInfo()->auth_challenge));
- rv = callback.GetResult(trans->RestartWithAuth(
- AuthCredentials(u"user", u"pass"), callback.callback()));
- // The request completes.
- ASSERT_THAT(rv, IsOk());
- EXPECT_EQ(200, trans->GetResponseInfo()->headers->response_code());
- // Make a second request. This time all credentials are cached.
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- ASSERT_THAT(callback.GetResult(trans->Start(&request, callback.callback(),
- NetLogWithSource())),
- IsOk());
- EXPECT_EQ(200, trans->GetResponseInfo()->headers->response_code());
- }
- // Test the proxy requesting HTTP auth and the server requesting TLS client
- // certificates. This is a regression test for https://crbug.com/946406.
- TEST_F(HttpNetworkTransactionTest, ProxyHTTPAndServerTLSAuth) {
- // Note these hosts must match the CheckBasic*Auth() functions.
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- auto cert_request_info_origin = base::MakeRefCounted<SSLCertRequestInfo>();
- cert_request_info_origin->host_and_port =
- HostPortPair("www.example.org", 443);
- std::unique_ptr<FakeClientCertIdentity> identity_origin =
- FakeClientCertIdentity::CreateFromCertAndKeyFiles(
- GetTestCertsDirectory(), "client_2.pem", "client_2.pk8");
- ASSERT_TRUE(identity_origin);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // The client connects to the proxy. The handshake succeeds.
- SSLSocketDataProvider ssl_proxy1(ASYNC, OK);
- // The client attempts an HTTP CONNECT, but the proxy requests basic auth.
- std::vector<MockWrite> mock_writes1;
- std::vector<MockRead> mock_reads1;
- mock_writes1.emplace_back(
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n");
- mock_reads1.emplace_back(
- "HTTP/1.1 407 Proxy Authentication Required\r\n"
- "Content-Length: 0\r\n"
- "Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n\r\n");
- // The client retries with credentials, and the request finally succeeds.
- mock_writes1.emplace_back(
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- // Authenticate as proxyuser:proxypass.
- "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
- mock_reads1.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
- // The origin requests client certificates.
- SSLSocketDataProvider ssl_origin1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
- ssl_origin1.cert_request_info = cert_request_info_origin.get();
- StaticSocketDataProvider data1(mock_reads1, mock_writes1);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy1);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin1);
- // The client responds to the origin client certificate request on a new
- // connection.
- SSLSocketDataProvider ssl_proxy2(ASYNC, OK);
- std::vector<MockWrite> mock_writes2;
- std::vector<MockRead> mock_reads2;
- mock_writes2.emplace_back(
- "CONNECT www.example.org:443 HTTP/1.1\r\n"
- "Host: www.example.org:443\r\n"
- "Proxy-Connection: keep-alive\r\n"
- // Authenticate as proxyuser:proxypass.
- "Proxy-Authorization: Basic cHJveHl1c2VyOnByb3h5cGFzcw==\r\n\r\n");
- mock_reads2.emplace_back("HTTP/1.1 200 Connection Established\r\n\r\n");
- SSLSocketDataProvider ssl_origin2(ASYNC, OK);
- ssl_origin2.expected_send_client_cert = true;
- ssl_origin2.expected_client_cert = identity_origin->certificate();
- // The client sends the origin HTTP request, which succeeds.
- mock_writes2.emplace_back(
- "GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n");
- mock_reads2.emplace_back(
- "HTTP/1.1 200 OK\r\n"
- "Content-Length: 0\r\n\r\n");
- StaticSocketDataProvider data2(mock_reads2, mock_writes2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy2);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin2);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Start the request.
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = callback.GetResult(
- trans->Start(&request, callback.callback(), NetLogWithSource()));
- // Handle the proxy HTTP auth challenge.
- ASSERT_THAT(rv, IsOk());
- EXPECT_EQ(407, trans->GetResponseInfo()->headers->response_code());
- EXPECT_TRUE(
- CheckBasicSecureProxyAuth(trans->GetResponseInfo()->auth_challenge));
- rv = callback.GetResult(trans->RestartWithAuth(
- AuthCredentials(u"proxyuser", u"proxypass"), callback.callback()));
- // Handle the origin client certificate challenge.
- ASSERT_THAT(rv, IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
- SSLCertRequestInfo* cert_request_info =
- trans->GetResponseInfo()->cert_request_info.get();
- ASSERT_TRUE(cert_request_info);
- EXPECT_FALSE(cert_request_info->is_proxy);
- EXPECT_EQ(cert_request_info->host_and_port,
- cert_request_info_origin->host_and_port);
- rv = callback.GetResult(trans->RestartWithCertificate(
- identity_origin->certificate(), identity_origin->ssl_private_key(),
- callback.callback()));
- // The request completes.
- ASSERT_THAT(rv, IsOk());
- EXPECT_EQ(200, trans->GetResponseInfo()->headers->response_code());
- }
- // Test that socket reuse works with client certificates.
- TEST_F(HttpNetworkTransactionTest, ClientCertSocketReuse) {
- auto cert_request_info = base::MakeRefCounted<SSLCertRequestInfo>();
- cert_request_info->host_and_port = HostPortPair("www.example.org", 443);
- std::unique_ptr<FakeClientCertIdentity> identity =
- FakeClientCertIdentity::CreateFromCertAndKeyFiles(
- GetTestCertsDirectory(), "client_1.pem", "client_1.pk8");
- ASSERT_TRUE(identity);
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://www.example.org/a");
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://www.example.org/b");
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // The first connection results in a client certificate request.
- StaticSocketDataProvider data1;
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- SSLSocketDataProvider ssl1(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
- ssl1.cert_request_info = cert_request_info.get();
- ssl1.expected_send_client_cert = false;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- // The second connection succeeds and is usable for both requests.
- MockWrite mock_writes[] = {
- MockWrite("GET /a HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- MockWrite("GET /b HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- MockRead mock_reads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Content-Length: 0\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"
- "Content-Length: 0\r\n\r\n"),
- };
- StaticSocketDataProvider data2(mock_reads, mock_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl2(ASYNC, OK);
- ssl2.expected_send_client_cert = true;
- ssl2.expected_client_cert = identity->certificate();
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Start the first request. It succeeds after providing client certificates.
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- ASSERT_THAT(callback.GetResult(trans->Start(&request1, callback.callback(),
- NetLogWithSource())),
- IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
- SSLCertRequestInfo* info = trans->GetResponseInfo()->cert_request_info.get();
- ASSERT_TRUE(info);
- EXPECT_FALSE(info->is_proxy);
- EXPECT_EQ(info->host_and_port, cert_request_info->host_and_port);
- ASSERT_THAT(callback.GetResult(trans->RestartWithCertificate(
- identity->certificate(), identity->ssl_private_key(),
- callback.callback())),
- IsOk());
- EXPECT_EQ(200, trans->GetResponseInfo()->headers->response_code());
- // Make the second request. It completes without requesting client
- // certificates.
- trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- ASSERT_THAT(callback.GetResult(trans->Start(&request2, callback.callback(),
- NetLogWithSource())),
- IsOk());
- EXPECT_EQ(200, trans->GetResponseInfo()->headers->response_code());
- }
- // Test for kPartitionConnectionsByNetworkIsolationKey. Runs 3 requests in
- // sequence with two different NetworkIsolationKeys, the first and last have the
- // same key, the second a different one. Checks that the requests are
- // partitioned across sockets as expected.
- TEST_F(HttpNetworkTransactionTest, NetworkIsolation) {
- const SchemefulSite kSite1(GURL("http://origin1/"));
- const SchemefulSite kSite2(GURL("http://origin2/"));
- NetworkIsolationKey network_isolation_key1(kSite1, kSite1);
- NetworkIsolationKey network_isolation_key2(kSite2, kSite2);
- for (bool partition_connections : {false, true}) {
- SCOPED_TRACE(partition_connections);
- base::test::ScopedFeatureList feature_list;
- if (partition_connections) {
- feature_list.InitAndEnableFeature(
- features::kPartitionConnectionsByNetworkIsolationKey);
- } else {
- feature_list.InitAndDisableFeature(
- features::kPartitionConnectionsByNetworkIsolationKey);
- }
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Reads and writes for the unpartitioned case, where only one socket is
- // used.
- const MockWrite kUnpartitionedWrites[] = {
- MockWrite("GET /1 HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- MockWrite("GET /2 HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- MockWrite("GET /3 HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- const MockRead kUnpartitionedReads[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 1\r\n\r\n"
- "1"),
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 1\r\n\r\n"
- "2"),
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 1\r\n\r\n"
- "3"),
- };
- StaticSocketDataProvider unpartitioned_data(kUnpartitionedReads,
- kUnpartitionedWrites);
- // Reads and writes for the partitioned case, where two sockets are used.
- const MockWrite kPartitionedWrites1[] = {
- MockWrite("GET /1 HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- MockWrite("GET /3 HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- const MockRead kPartitionedReads1[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 1\r\n\r\n"
- "1"),
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 1\r\n\r\n"
- "3"),
- };
- const MockWrite kPartitionedWrites2[] = {
- MockWrite("GET /2 HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- const MockRead kPartitionedReads2[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 1\r\n\r\n"
- "2"),
- };
- StaticSocketDataProvider partitioned_data1(kPartitionedReads1,
- kPartitionedWrites1);
- StaticSocketDataProvider partitioned_data2(kPartitionedReads2,
- kPartitionedWrites2);
- if (partition_connections) {
- session_deps_.socket_factory->AddSocketDataProvider(&partitioned_data1);
- session_deps_.socket_factory->AddSocketDataProvider(&partitioned_data2);
- } else {
- session_deps_.socket_factory->AddSocketDataProvider(&unpartitioned_data);
- }
- TestCompletionCallback callback;
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("http://foo.test/1");
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request1.network_isolation_key = network_isolation_key1;
- auto trans1 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
- session.get());
- int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data1;
- EXPECT_THAT(ReadTransaction(trans1.get(), &response_data1), IsOk());
- EXPECT_EQ("1", response_data1);
- trans1.reset();
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("http://foo.test/2");
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request2.network_isolation_key = network_isolation_key2;
- auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
- session.get());
- rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data2;
- EXPECT_THAT(ReadTransaction(trans2.get(), &response_data2), IsOk());
- EXPECT_EQ("2", response_data2);
- trans2.reset();
- HttpRequestInfo request3;
- request3.method = "GET";
- request3.url = GURL("http://foo.test/3");
- request3.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request3.network_isolation_key = network_isolation_key1;
- auto trans3 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
- session.get());
- rv = trans3->Start(&request3, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data3;
- EXPECT_THAT(ReadTransaction(trans3.get(), &response_data3), IsOk());
- EXPECT_EQ("3", response_data3);
- trans3.reset();
- }
- }
- TEST_F(HttpNetworkTransactionTest, NetworkIsolationH2) {
- const SchemefulSite kSite1(GURL("http://origin1/"));
- const SchemefulSite kSite2(GURL("http://origin2/"));
- NetworkIsolationKey network_isolation_key1(kSite1, kSite1);
- NetworkIsolationKey network_isolation_key2(kSite2, kSite2);
- // Whether to use an H2 proxy. When false, uses HTTPS H2 requests without a
- // proxy, when true, uses HTTP requests over an H2 proxy. It's unnecessary to
- // test tunneled HTTPS over an H2 proxy, since that path sets up H2 sessions
- // the same way as the HTTP over H2 proxy case.
- for (bool use_proxy : {false, true}) {
- SCOPED_TRACE(use_proxy);
- if (use_proxy) {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedFromPacResultForTest(
- "HTTPS proxy:443", TRAFFIC_ANNOTATION_FOR_TESTS);
- } else {
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateDirect();
- }
- const char* url1 = nullptr;
- const char* url2 = nullptr;
- const char* url3 = nullptr;
- if (use_proxy) {
- url1 = "http://foo.test/1";
- url2 = "http://foo.test/2";
- url3 = "http://foo.test/3";
- } else {
- url1 = "https://foo.test/1";
- url2 = "https://foo.test/2";
- url3 = "https://foo.test/3";
- }
- for (bool partition_connections : {false, true}) {
- SCOPED_TRACE(partition_connections);
- base::test::ScopedFeatureList feature_list;
- if (partition_connections) {
- feature_list.InitAndEnableFeature(
- features::kPartitionConnectionsByNetworkIsolationKey);
- } else {
- feature_list.InitAndDisableFeature(
- features::kPartitionConnectionsByNetworkIsolationKey);
- }
- std::unique_ptr<HttpNetworkSession> session(
- CreateSession(&session_deps_));
- // Reads and writes for the unpartitioned case, where only one socket is
- // used.
- SpdyTestUtil spdy_util;
- spdy::SpdySerializedFrame unpartitioned_req1(
- spdy_util.ConstructSpdyGet(url1, 1, LOWEST));
- spdy::SpdySerializedFrame unpartitioned_response1(
- spdy_util.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame unpartitioned_body1(
- spdy_util.ConstructSpdyDataFrame(1, "1", true));
- spdy_util.UpdateWithStreamDestruction(1);
- spdy::SpdySerializedFrame unpartitioned_req2(
- spdy_util.ConstructSpdyGet(url2, 3, LOWEST));
- spdy::SpdySerializedFrame unpartitioned_response2(
- spdy_util.ConstructSpdyGetReply(nullptr, 0, 3));
- spdy::SpdySerializedFrame unpartitioned_body2(
- spdy_util.ConstructSpdyDataFrame(3, "2", true));
- spdy_util.UpdateWithStreamDestruction(3);
- spdy::SpdySerializedFrame unpartitioned_req3(
- spdy_util.ConstructSpdyGet(url3, 5, LOWEST));
- spdy::SpdySerializedFrame unpartitioned_response3(
- spdy_util.ConstructSpdyGetReply(nullptr, 0, 5));
- spdy::SpdySerializedFrame unpartitioned_body3(
- spdy_util.ConstructSpdyDataFrame(5, "3", true));
- const MockWrite kUnpartitionedWrites[] = {
- CreateMockWrite(unpartitioned_req1, 0),
- CreateMockWrite(unpartitioned_req2, 3),
- CreateMockWrite(unpartitioned_req3, 6),
- };
- const MockRead kUnpartitionedReads[] = {
- CreateMockRead(unpartitioned_response1, 1),
- CreateMockRead(unpartitioned_body1, 2),
- CreateMockRead(unpartitioned_response2, 4),
- CreateMockRead(unpartitioned_body2, 5),
- CreateMockRead(unpartitioned_response3, 7),
- CreateMockRead(unpartitioned_body3, 8),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 9),
- };
- SequencedSocketData unpartitioned_data(kUnpartitionedReads,
- kUnpartitionedWrites);
- // Reads and writes for the partitioned case, where two sockets are used.
- SpdyTestUtil spdy_util2;
- spdy::SpdySerializedFrame partitioned_req1(
- spdy_util2.ConstructSpdyGet(url1, 1, LOWEST));
- spdy::SpdySerializedFrame partitioned_response1(
- spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame partitioned_body1(
- spdy_util2.ConstructSpdyDataFrame(1, "1", true));
- spdy_util2.UpdateWithStreamDestruction(1);
- spdy::SpdySerializedFrame partitioned_req3(
- spdy_util2.ConstructSpdyGet(url3, 3, LOWEST));
- spdy::SpdySerializedFrame partitioned_response3(
- spdy_util2.ConstructSpdyGetReply(nullptr, 0, 3));
- spdy::SpdySerializedFrame partitioned_body3(
- spdy_util2.ConstructSpdyDataFrame(3, "3", true));
- const MockWrite kPartitionedWrites1[] = {
- CreateMockWrite(partitioned_req1, 0),
- CreateMockWrite(partitioned_req3, 3),
- };
- const MockRead kPartitionedReads1[] = {
- CreateMockRead(partitioned_response1, 1),
- CreateMockRead(partitioned_body1, 2),
- CreateMockRead(partitioned_response3, 4),
- CreateMockRead(partitioned_body3, 5),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
- };
- SpdyTestUtil spdy_util3;
- spdy::SpdySerializedFrame partitioned_req2(
- spdy_util3.ConstructSpdyGet(url2, 1, LOWEST));
- spdy::SpdySerializedFrame partitioned_response2(
- spdy_util3.ConstructSpdyGetReply(nullptr, 0, 1));
- spdy::SpdySerializedFrame partitioned_body2(
- spdy_util3.ConstructSpdyDataFrame(1, "2", true));
- const MockWrite kPartitionedWrites2[] = {
- CreateMockWrite(partitioned_req2, 0),
- };
- const MockRead kPartitionedReads2[] = {
- CreateMockRead(partitioned_response2, 1),
- CreateMockRead(partitioned_body2, 2),
- MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3),
- };
- SequencedSocketData partitioned_data1(kPartitionedReads1,
- kPartitionedWrites1);
- SequencedSocketData partitioned_data2(kPartitionedReads2,
- kPartitionedWrites2);
- // No need to segment SSLDataProviders by whether or not partitioning is
- // enabled.
- SSLSocketDataProvider ssl_data1(ASYNC, OK);
- ssl_data1.next_proto = kProtoHTTP2;
- SSLSocketDataProvider ssl_data2(ASYNC, OK);
- ssl_data2.next_proto = kProtoHTTP2;
- if (partition_connections) {
- session_deps_.socket_factory->AddSocketDataProvider(&partitioned_data1);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data1);
- session_deps_.socket_factory->AddSocketDataProvider(&partitioned_data2);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data2);
- } else {
- session_deps_.socket_factory->AddSocketDataProvider(
- &unpartitioned_data);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data1);
- }
- TestCompletionCallback callback;
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL(url1);
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request1.network_isolation_key = network_isolation_key1;
- auto trans1 =
- std::make_unique<HttpNetworkTransaction>(LOWEST, session.get());
- int rv =
- trans1->Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data1;
- EXPECT_THAT(ReadTransaction(trans1.get(), &response_data1), IsOk());
- EXPECT_EQ("1", response_data1);
- trans1.reset();
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL(url2);
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request2.network_isolation_key = network_isolation_key2;
- auto trans2 =
- std::make_unique<HttpNetworkTransaction>(LOWEST, session.get());
- rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data2;
- EXPECT_THAT(ReadTransaction(trans2.get(), &response_data2), IsOk());
- EXPECT_EQ("2", response_data2);
- trans2.reset();
- HttpRequestInfo request3;
- request3.method = "GET";
- request3.url = GURL(url3);
- request3.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request3.network_isolation_key = network_isolation_key1;
- auto trans3 =
- std::make_unique<HttpNetworkTransaction>(LOWEST, session.get());
- rv = trans3->Start(&request3, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data3;
- EXPECT_THAT(ReadTransaction(trans3.get(), &response_data3), IsOk());
- EXPECT_EQ("3", response_data3);
- trans3.reset();
- }
- }
- }
- // Preconnect two sockets with different NetworkIsolationKeys when
- // features::kPartitionConnectionsByNetworkIsolationKey is enabled. Then issue a
- // request and make sure the correct socket is used. Loops three times,
- // expecting to use the first preconnect, second preconnect, and neither.
- TEST_F(HttpNetworkTransactionTest, NetworkIsolationPreconnect) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(
- features::kPartitionConnectionsByNetworkIsolationKey);
- enum class TestCase {
- kUseFirstPreconnect,
- kUseSecondPreconnect,
- kDontUsePreconnect,
- };
- const SchemefulSite kSite1(GURL("http://origin1/"));
- const SchemefulSite kSite2(GURL("http://origin2/"));
- const SchemefulSite kSite3(GURL("http://origin3/"));
- NetworkIsolationKey preconnect1_isolation_key(kSite1, kSite1);
- NetworkIsolationKey preconnect2_isolation_key(kSite2, kSite2);
- NetworkIsolationKey not_preconnected_isolation_key(kSite3, kSite3);
- // Test that only preconnects with
- for (TestCase test_case :
- {TestCase::kUseFirstPreconnect, TestCase::kUseSecondPreconnect,
- TestCase::kDontUsePreconnect}) {
- SpdySessionDependencies session_deps;
- // Make DNS lookups completely synchronously, so preconnects complete
- // immediately.
- session_deps.host_resolver->set_synchronous_mode(true);
- const MockWrite kMockWrites[] = {
- MockWrite(ASYNC, 0,
- "GET / HTTP/1.1\r\n"
- "Host: www.foo.com\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- const MockRead kMockReads[] = {
- MockRead(ASYNC, 1,
- "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n"
- "hello"),
- };
- // Used for the socket that will actually be used, which may or may not be
- // one of the preconnects
- SequencedSocketData used_socket_data(MockConnect(SYNCHRONOUS, OK),
- kMockReads, kMockWrites);
- // Used for the preconnects that won't actually be used.
- SequencedSocketData preconnect1_data(MockConnect(SYNCHRONOUS, OK),
- base::span<const MockRead>(),
- base::span<const MockWrite>());
- SequencedSocketData preconnect2_data(MockConnect(SYNCHRONOUS, OK),
- base::span<const MockRead>(),
- base::span<const MockWrite>());
- NetworkIsolationKey network_isolation_key_for_request;
- switch (test_case) {
- case TestCase::kUseFirstPreconnect:
- session_deps.socket_factory->AddSocketDataProvider(&used_socket_data);
- session_deps.socket_factory->AddSocketDataProvider(&preconnect2_data);
- network_isolation_key_for_request = preconnect1_isolation_key;
- break;
- case TestCase::kUseSecondPreconnect:
- session_deps.socket_factory->AddSocketDataProvider(&preconnect1_data);
- session_deps.socket_factory->AddSocketDataProvider(&used_socket_data);
- network_isolation_key_for_request = preconnect2_isolation_key;
- break;
- case TestCase::kDontUsePreconnect:
- session_deps.socket_factory->AddSocketDataProvider(&preconnect1_data);
- session_deps.socket_factory->AddSocketDataProvider(&preconnect2_data);
- session_deps.socket_factory->AddSocketDataProvider(&used_socket_data);
- network_isolation_key_for_request = not_preconnected_isolation_key;
- break;
- }
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps));
- // Preconnect sockets.
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.foo.com/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request.network_isolation_key = preconnect1_isolation_key;
- session->http_stream_factory()->PreconnectStreams(1, request);
- request.network_isolation_key = preconnect2_isolation_key;
- session->http_stream_factory()->PreconnectStreams(1, request);
- request.network_isolation_key = network_isolation_key_for_request;
- EXPECT_EQ(2, GetIdleSocketCountInTransportSocketPool(session.get()));
- // Make the request.
- TestCompletionCallback callback;
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- const HttpResponseInfo* response = trans.GetResponseInfo();
- ASSERT_TRUE(response);
- ASSERT_TRUE(response->headers);
- EXPECT_EQ(200, response->headers->response_code());
- std::string response_data;
- rv = ReadTransaction(&trans, &response_data);
- EXPECT_THAT(rv, IsOk());
- EXPECT_EQ("hello", response_data);
- if (test_case != TestCase::kDontUsePreconnect) {
- EXPECT_EQ(2, GetIdleSocketCountInTransportSocketPool(session.get()));
- } else {
- EXPECT_EQ(3, GetIdleSocketCountInTransportSocketPool(session.get()));
- }
- }
- }
- // Test that the NetworkIsolationKey is passed down to SSLConfig so the session
- // cache is isolated.
- TEST_F(HttpNetworkTransactionTest, NetworkIsolationSSL) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- {features::kPartitionConnectionsByNetworkIsolationKey,
- features::kPartitionSSLSessionsByNetworkIsolationKey},
- {});
- const SchemefulSite kSite1(GURL("http://origin1/"));
- const SchemefulSite kSite2(GURL("http://origin2/"));
- const NetworkIsolationKey kNetworkIsolationKey1(kSite1, kSite1);
- const NetworkIsolationKey kNetworkIsolationKey2(kSite2, kSite2);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // The server always sends Connection: close, so each request goes over a
- // distinct socket.
- const MockWrite kWrites1[] = {
- MockWrite("GET /1 HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n")};
- const MockRead kReads1[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: close\r\n"
- "Content-Length: 1\r\n\r\n"
- "1")};
- const MockWrite kWrites2[] = {
- MockWrite("GET /2 HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n")};
- const MockRead kReads2[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: close\r\n"
- "Content-Length: 1\r\n\r\n"
- "2")};
- const MockWrite kWrites3[] = {
- MockWrite("GET /3 HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n")};
- const MockRead kReads3[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: close\r\n"
- "Content-Length: 1\r\n\r\n"
- "3")};
- StaticSocketDataProvider data1(kReads1, kWrites1);
- StaticSocketDataProvider data2(kReads2, kWrites2);
- StaticSocketDataProvider data3(kReads3, kWrites3);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- session_deps_.socket_factory->AddSocketDataProvider(&data3);
- SSLSocketDataProvider ssl_data1(ASYNC, OK);
- ssl_data1.expected_host_and_port = HostPortPair("foo.test", 443);
- ssl_data1.expected_network_isolation_key = kNetworkIsolationKey1;
- SSLSocketDataProvider ssl_data2(ASYNC, OK);
- ssl_data2.expected_host_and_port = HostPortPair("foo.test", 443);
- ssl_data2.expected_network_isolation_key = kNetworkIsolationKey2;
- SSLSocketDataProvider ssl_data3(ASYNC, OK);
- ssl_data3.expected_host_and_port = HostPortPair("foo.test", 443);
- ssl_data3.expected_network_isolation_key = kNetworkIsolationKey1;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data1);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data2);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data3);
- TestCompletionCallback callback;
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://foo.test/1");
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request1.network_isolation_key = kNetworkIsolationKey1;
- auto trans1 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data1;
- EXPECT_THAT(ReadTransaction(trans1.get(), &response_data1), IsOk());
- EXPECT_EQ("1", response_data1);
- trans1.reset();
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://foo.test/2");
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request2.network_isolation_key = kNetworkIsolationKey2;
- auto trans2 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data2;
- EXPECT_THAT(ReadTransaction(trans2.get(), &response_data2), IsOk());
- EXPECT_EQ("2", response_data2);
- trans2.reset();
- HttpRequestInfo request3;
- request3.method = "GET";
- request3.url = GURL("https://foo.test/3");
- request3.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request3.network_isolation_key = kNetworkIsolationKey1;
- auto trans3 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans3->Start(&request3, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data3;
- EXPECT_THAT(ReadTransaction(trans3.get(), &response_data3), IsOk());
- EXPECT_EQ("3", response_data3);
- trans3.reset();
- }
- // Test that the NetworkIsolationKey is passed down to SSLConfig so the session
- // cache is isolated, for both origins and proxies.
- TEST_F(HttpNetworkTransactionTest, NetworkIsolationSSLProxy) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitWithFeatures(
- {features::kPartitionConnectionsByNetworkIsolationKey,
- features::kPartitionSSLSessionsByNetworkIsolationKey},
- {});
- session_deps_.proxy_resolution_service =
- ConfiguredProxyResolutionService::CreateFixedForTest(
- "https://myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS);
- const SchemefulSite kSite1(GURL("http://origin1/"));
- const SchemefulSite kSite2(GURL("http://origin2/"));
- const NetworkIsolationKey kNetworkIsolationKey1(kSite1, kSite1);
- const NetworkIsolationKey kNetworkIsolationKey2(kSite2, kSite2);
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Make both a tunneled and non-tunneled request.
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://foo.test/1");
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request1.network_isolation_key = kNetworkIsolationKey1;
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("http://foo.test/2");
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- request2.network_isolation_key = kNetworkIsolationKey2;
- const MockWrite kWrites1[] = {
- MockWrite("CONNECT foo.test:443 HTTP/1.1\r\n"
- "Host: foo.test:443\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- MockWrite("GET /1 HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n")};
- const MockRead kReads1[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n\r\n"),
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: close\r\n"
- "Content-Length: 1\r\n\r\n"
- "1")};
- const MockWrite kWrites2[] = {
- MockWrite("GET http://foo.test/2 HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n")};
- const MockRead kReads2[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: close\r\n"
- "Content-Length: 1\r\n\r\n"
- "2")};
- StaticSocketDataProvider data1(kReads1, kWrites1);
- StaticSocketDataProvider data2(kReads2, kWrites2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl_proxy1(ASYNC, OK);
- ssl_proxy1.expected_host_and_port = HostPortPair("myproxy", 70);
- ssl_proxy1.expected_network_isolation_key = kNetworkIsolationKey1;
- SSLSocketDataProvider ssl_origin1(ASYNC, OK);
- ssl_origin1.expected_host_and_port = HostPortPair("foo.test", 443);
- ssl_origin1.expected_network_isolation_key = kNetworkIsolationKey1;
- SSLSocketDataProvider ssl_proxy2(ASYNC, OK);
- ssl_proxy2.expected_host_and_port = HostPortPair("myproxy", 70);
- ssl_proxy2.expected_network_isolation_key = kNetworkIsolationKey2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy1);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_origin1);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_proxy2);
- TestCompletionCallback callback;
- auto trans1 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data1;
- EXPECT_THAT(ReadTransaction(trans1.get(), &response_data1), IsOk());
- EXPECT_EQ("1", response_data1);
- trans1.reset();
- auto trans2 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data2;
- EXPECT_THAT(ReadTransaction(trans2.get(), &response_data2), IsOk());
- EXPECT_EQ("2", response_data2);
- trans2.reset();
- }
- // Test that SSLConfig changes from SSLConfigService are picked up even when
- // there are live sockets.
- TEST_F(HttpNetworkTransactionTest, SSLConfigChanged) {
- SSLContextConfig ssl_context_config;
- ssl_context_config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
- auto ssl_config_service =
- std::make_unique<TestSSLConfigService>(ssl_context_config);
- TestSSLConfigService* ssl_config_service_raw = ssl_config_service.get();
- session_deps_.ssl_config_service = std::move(ssl_config_service);
- // Make three requests. Between the second and third, the SSL config will
- // change.
- HttpRequestInfo request1;
- request1.method = "GET";
- request1.url = GURL("https://foo.test/1");
- request1.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpRequestInfo request2;
- request2.method = "GET";
- request2.url = GURL("https://foo.test/2");
- request2.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- HttpRequestInfo request3;
- request3.method = "GET";
- request3.url = GURL("https://foo.test/3");
- request3.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- const MockWrite kWrites1[] = {
- MockWrite("GET /1 HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- MockWrite("GET /2 HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- const MockRead kReads1[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 1\r\n\r\n"
- "1"),
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 1\r\n\r\n"
- "2"),
- };
- // The third request goes on a different socket because the SSL config has
- // changed.
- const MockWrite kWrites2[] = {
- MockWrite("GET /3 HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n")};
- const MockRead kReads2[] = {
- MockRead("HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 1\r\n\r\n"
- "3")};
- StaticSocketDataProvider data1(kReads1, kWrites1);
- StaticSocketDataProvider data2(kReads2, kWrites2);
- session_deps_.socket_factory->AddSocketDataProvider(&data1);
- session_deps_.socket_factory->AddSocketDataProvider(&data2);
- SSLSocketDataProvider ssl1(ASYNC, OK);
- ssl1.expected_ssl_version_max = SSL_PROTOCOL_VERSION_TLS1_3;
- SSLSocketDataProvider ssl2(ASYNC, OK);
- ssl2.expected_ssl_version_max = SSL_PROTOCOL_VERSION_TLS1_2;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl1);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl2);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- TestCompletionCallback callback;
- auto trans1 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans1->Start(&request1, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data1;
- EXPECT_THAT(ReadTransaction(trans1.get(), &response_data1), IsOk());
- EXPECT_EQ("1", response_data1);
- trans1.reset();
- auto trans2 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans2->Start(&request2, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data2;
- EXPECT_THAT(ReadTransaction(trans2.get(), &response_data2), IsOk());
- EXPECT_EQ("2", response_data2);
- trans2.reset();
- ssl_context_config.version_max = SSL_PROTOCOL_VERSION_TLS1_2;
- ssl_config_service_raw->UpdateSSLConfigAndNotify(ssl_context_config);
- auto trans3 =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans3->Start(&request3, callback.callback(), NetLogWithSource());
- EXPECT_THAT(callback.GetResult(rv), IsOk());
- std::string response_data3;
- EXPECT_THAT(ReadTransaction(trans3.get(), &response_data3), IsOk());
- EXPECT_EQ("3", response_data3);
- trans3.reset();
- }
- TEST_F(HttpNetworkTransactionTest, SSLConfigChangedPendingConnect) {
- SSLContextConfig ssl_context_config;
- ssl_context_config.version_max = SSL_PROTOCOL_VERSION_TLS1_3;
- auto ssl_config_service =
- std::make_unique<TestSSLConfigService>(ssl_context_config);
- TestSSLConfigService* ssl_config_service_raw = ssl_config_service.get();
- session_deps_.ssl_config_service = std::move(ssl_config_service);
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("https://foo.test/1");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Make a socket which never connects.
- StaticSocketDataProvider data({}, {});
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl_data(SYNCHRONOUS, ERR_IO_PENDING);
- ssl_data.expected_ssl_version_max = SSL_PROTOCOL_VERSION_TLS1_3;
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_data);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- TestCompletionCallback callback;
- auto trans =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans->Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- ssl_context_config.version_max = SSL_PROTOCOL_VERSION_TLS1_2;
- ssl_config_service_raw->UpdateSSLConfigAndNotify(ssl_context_config);
- EXPECT_THAT(callback.GetResult(rv), IsError(ERR_NETWORK_CHANGED));
- }
- // Test that HttpNetworkTransaction correctly handles existing sockets when the
- // server requests a client certificate post-handshake (via a TLS
- // renegotiation). This is a regression test for https://crbug.com/829184.
- TEST_F(HttpNetworkTransactionTest, PostHandshakeClientCertWithSockets) {
- const MutableNetworkTrafficAnnotationTag kTrafficAnnotation(
- TRAFFIC_ANNOTATION_FOR_TESTS);
- auto cert_request_info = base::MakeRefCounted<SSLCertRequestInfo>();
- cert_request_info->host_and_port = HostPortPair("foo.test", 443);
- std::unique_ptr<FakeClientCertIdentity> identity =
- FakeClientCertIdentity::CreateFromCertAndKeyFiles(
- GetTestCertsDirectory(), "client_1.pem", "client_1.pk8");
- ASSERT_TRUE(identity);
- // This test will make several requests so that, when the client certificate
- // request comes in, we have a socket in use, an idle socket, and a socket for
- // an unrelated host.
- //
- // First, two long-lived requests which do not complete until after the client
- // certificate request. This arranges for sockets to be in use during the
- // request. They should not be interrupted.
- HttpRequestInfo request_long_lived;
- request_long_lived.method = "GET";
- request_long_lived.url = GURL("https://foo.test/long-lived");
- request_long_lived.traffic_annotation = kTrafficAnnotation;
- HttpRequestInfo request_long_lived_bar;
- request_long_lived_bar.method = "GET";
- request_long_lived_bar.url = GURL("https://bar.test/long-lived");
- request_long_lived_bar.traffic_annotation = kTrafficAnnotation;
- // Next, make a request that needs client certificates.
- HttpRequestInfo request_auth;
- request_auth.method = "GET";
- request_auth.url = GURL("https://foo.test/auth");
- request_auth.traffic_annotation = kTrafficAnnotation;
- // Before responding to the challenge, make a request to an unauthenticated
- // endpoint. This will result in an idle socket when the client certificate
- // challenge is resolved.
- HttpRequestInfo request_unauth;
- request_unauth.method = "GET";
- request_unauth.url = GURL("https://foo.test/unauth");
- request_unauth.traffic_annotation = kTrafficAnnotation;
- // After all the preceding requests complete, end with two additional requests
- // to ensure pre-authentication foo.test sockets are not used and bar.test
- // sockets are unaffected.
- HttpRequestInfo request_post_auth;
- request_post_auth.method = "GET";
- request_post_auth.url = GURL("https://foo.test/post-auth");
- request_post_auth.traffic_annotation = kTrafficAnnotation;
- HttpRequestInfo request_post_auth_bar;
- request_post_auth_bar.method = "GET";
- request_post_auth_bar.url = GURL("https://bar.test/post-auth");
- request_post_auth_bar.traffic_annotation = kTrafficAnnotation;
- // The sockets for /long-lived and /unauth complete their request but are
- // not allocated for /post-auth or /retry because SSL state has since changed.
- const MockWrite kLongLivedWrites[] = {
- MockWrite(ASYNC, 0,
- "GET /long-lived HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- const MockRead kLongLivedReads[] = {
- // Pause so /long-lived completes after the client presents client
- // certificates.
- MockRead(ASYNC, ERR_IO_PENDING, 1),
- MockRead(ASYNC, 2,
- "HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 10\r\n\r\n"
- "long-lived"),
- };
- SequencedSocketData data_long_lived(kLongLivedReads, kLongLivedWrites);
- SSLSocketDataProvider ssl_long_lived(ASYNC, OK);
- session_deps_.socket_factory->AddSocketDataProvider(&data_long_lived);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_long_lived);
- // Requests for bar.test should be unaffected by foo.test and get allocated
- // a single socket.
- const MockWrite kBarWrites[] = {
- MockWrite(ASYNC, 0,
- "GET /long-lived HTTP/1.1\r\n"
- "Host: bar.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- MockWrite(ASYNC, 3,
- "GET /post-auth HTTP/1.1\r\n"
- "Host: bar.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- const MockRead kBarReads[] = {
- // Pause on /long-lived so it completes after foo.test's authentication.
- MockRead(ASYNC, ERR_IO_PENDING, 1),
- MockRead(ASYNC, 2,
- "HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 10\r\n\r\n"
- "long-lived"),
- MockRead(ASYNC, 4,
- "HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 9\r\n\r\n"
- "post-auth"),
- };
- SequencedSocketData data_bar(kBarReads, kBarWrites);
- SSLSocketDataProvider ssl_bar(ASYNC, OK);
- session_deps_.socket_factory->AddSocketDataProvider(&data_bar);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_bar);
- // Requesting /auth results in a post-handshake client certificate challenge.
- const MockWrite kAuthWrites[] = {
- MockWrite(ASYNC, 0,
- "GET /auth HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- const MockRead kAuthReads[] = {
- MockRead(ASYNC, ERR_SSL_CLIENT_AUTH_CERT_NEEDED, 1),
- };
- SequencedSocketData data_auth(kAuthReads, kAuthWrites);
- SSLSocketDataProvider ssl_auth(ASYNC, OK);
- ssl_auth.cert_request_info = cert_request_info.get();
- session_deps_.socket_factory->AddSocketDataProvider(&data_auth);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_auth);
- // Requesting /unauth completes.
- const MockWrite kUnauthWrites[] = {
- MockWrite(ASYNC, 0,
- "GET /unauth HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- const MockRead kUnauthReads[] = {
- MockRead(ASYNC, 1,
- "HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 6\r\n\r\n"
- "unauth"),
- };
- SequencedSocketData data_unauth(kUnauthReads, kUnauthWrites);
- SSLSocketDataProvider ssl_unauth(ASYNC, OK);
- session_deps_.socket_factory->AddSocketDataProvider(&data_unauth);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_unauth);
- // When the client certificate is selected, /auth is retried on a new
- // connection. In particular, it should not be retried on |data_unauth|,
- // which would not honor the new client certificate configuration.
- const MockWrite kRetryWrites[] = {
- MockWrite(ASYNC, 0,
- "GET /auth HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- const MockRead kRetryReads[] = {
- MockRead(ASYNC, 1,
- "HTTP/1.1 200 OK\r\n"
- // Close the connection so we test that /post-auth is not
- // allocated to |data_unauth| or |data_long_lived|.
- "Connection: close\r\n"
- "Content-Length: 4\r\n\r\n"
- "auth"),
- };
- SequencedSocketData data_retry(kRetryReads, kRetryWrites);
- SSLSocketDataProvider ssl_retry(ASYNC, OK);
- ssl_retry.expected_send_client_cert = true;
- ssl_retry.expected_client_cert = identity->certificate();
- session_deps_.socket_factory->AddSocketDataProvider(&data_retry);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_retry);
- // /post-auth gets its own socket.
- const MockWrite kPostAuthWrites[] = {
- MockWrite(ASYNC, 0,
- "GET /post-auth HTTP/1.1\r\n"
- "Host: foo.test\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- const MockRead kPostAuthReads[] = {
- MockRead(ASYNC, 1,
- "HTTP/1.1 200 OK\r\n"
- "Connection: keep-alive\r\n"
- "Content-Length: 9\r\n\r\n"
- "post-auth"),
- };
- SequencedSocketData data_post_auth(kPostAuthReads, kPostAuthWrites);
- SSLSocketDataProvider ssl_post_auth(ASYNC, OK);
- ssl_post_auth.expected_send_client_cert = true;
- ssl_post_auth.expected_client_cert = identity->certificate();
- session_deps_.socket_factory->AddSocketDataProvider(&data_post_auth);
- session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl_post_auth);
- std::unique_ptr<HttpNetworkSession> session = CreateSession(&session_deps_);
- // Start the two long-lived requests.
- TestCompletionCallback callback_long_lived;
- auto trans_long_lived =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- int rv = trans_long_lived->Start(
- &request_long_lived, callback_long_lived.callback(), NetLogWithSource());
- ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
- data_long_lived.RunUntilPaused();
- TestCompletionCallback callback_long_lived_bar;
- auto trans_long_lived_bar =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans_long_lived_bar->Start(&request_long_lived_bar,
- callback_long_lived_bar.callback(),
- NetLogWithSource());
- ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
- data_bar.RunUntilPaused();
- // Request /auth. This gives a client certificate challenge.
- TestCompletionCallback callback_auth;
- auto trans_auth =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans_auth->Start(&request_auth, callback_auth.callback(),
- NetLogWithSource());
- EXPECT_THAT(callback_auth.GetResult(rv),
- IsError(ERR_SSL_CLIENT_AUTH_CERT_NEEDED));
- // Make an unauthenticated request. This completes.
- TestCompletionCallback callback_unauth;
- auto trans_unauth =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans_unauth->Start(&request_unauth, callback_unauth.callback(),
- NetLogWithSource());
- EXPECT_THAT(callback_unauth.GetResult(rv), IsOk());
- std::string response_unauth;
- EXPECT_THAT(ReadTransaction(trans_unauth.get(), &response_unauth), IsOk());
- EXPECT_EQ("unauth", response_unauth);
- trans_unauth.reset();
- // Complete the authenticated request.
- rv = trans_auth->RestartWithCertificate(identity->certificate(),
- identity->ssl_private_key(),
- callback_auth.callback());
- EXPECT_THAT(callback_auth.GetResult(rv), IsOk());
- std::string response_auth;
- EXPECT_THAT(ReadTransaction(trans_auth.get(), &response_auth), IsOk());
- EXPECT_EQ("auth", response_auth);
- trans_auth.reset();
- // Complete the long-lived requests.
- data_long_lived.Resume();
- EXPECT_THAT(callback_long_lived.GetResult(ERR_IO_PENDING), IsOk());
- std::string response_long_lived;
- EXPECT_THAT(ReadTransaction(trans_long_lived.get(), &response_long_lived),
- IsOk());
- EXPECT_EQ("long-lived", response_long_lived);
- trans_long_lived.reset();
- data_bar.Resume();
- EXPECT_THAT(callback_long_lived_bar.GetResult(ERR_IO_PENDING), IsOk());
- std::string response_long_lived_bar;
- EXPECT_THAT(
- ReadTransaction(trans_long_lived_bar.get(), &response_long_lived_bar),
- IsOk());
- EXPECT_EQ("long-lived", response_long_lived_bar);
- trans_long_lived_bar.reset();
- // Run the post-authentication requests.
- TestCompletionCallback callback_post_auth;
- auto trans_post_auth =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans_post_auth->Start(&request_post_auth, callback_post_auth.callback(),
- NetLogWithSource());
- EXPECT_THAT(callback_post_auth.GetResult(rv), IsOk());
- std::string response_post_auth;
- EXPECT_THAT(ReadTransaction(trans_post_auth.get(), &response_post_auth),
- IsOk());
- EXPECT_EQ("post-auth", response_post_auth);
- trans_post_auth.reset();
- TestCompletionCallback callback_post_auth_bar;
- auto trans_post_auth_bar =
- std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
- rv = trans_post_auth_bar->Start(&request_post_auth_bar,
- callback_post_auth_bar.callback(),
- NetLogWithSource());
- EXPECT_THAT(callback_post_auth_bar.GetResult(rv), IsOk());
- std::string response_post_auth_bar;
- EXPECT_THAT(
- ReadTransaction(trans_post_auth_bar.get(), &response_post_auth_bar),
- IsOk());
- EXPECT_EQ("post-auth", response_post_auth_bar);
- trans_post_auth_bar.reset();
- }
- TEST_F(HttpNetworkTransactionTest, RequestWithDnsAliases) {
- // Create a request.
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Add a rule with DNS aliases to the host resolver.
- std::vector<std::string> aliases({"alias1", "alias2", "www.example.org"});
- session_deps_.host_resolver->rules()->AddIPLiteralRuleWithDnsAliases(
- "www.example.org", "127.0.0.1", std::move(aliases));
- // Create a HttpNetworkSession.
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Create a transaction.
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Prepare the expected data to be written and read. The client should send
- // the request below.
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- // The server should respond with the following.
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- // Start the transaction.
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Wait for completion.
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- // Get the response info.
- const HttpResponseInfo* response = trans.GetResponseInfo();
- // Verify that the alias list was stored in the response info as expected.
- ASSERT_TRUE(response);
- EXPECT_THAT(response->dns_aliases,
- testing::ElementsAre("alias1", "alias2", "www.example.org"));
- }
- TEST_F(HttpNetworkTransactionTest, RequestWithNoAdditionalDnsAliases) {
- // Create a request.
- HttpRequestInfo request;
- request.method = "GET";
- request.url = GURL("http://www.example.org/");
- request.traffic_annotation =
- net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
- // Add a rule without DNS aliases to the host resolver.
- session_deps_.host_resolver->rules()->AddRule("www.example.org", "127.0.0.1");
- // Create a HttpNetworkSession.
- std::unique_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
- // Create a transaction.
- HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
- // Prepare the expected data to be written and read. The client should send
- // the request below.
- MockWrite data_writes[] = {
- MockWrite("GET / HTTP/1.1\r\n"
- "Host: www.example.org\r\n"
- "Connection: keep-alive\r\n\r\n"),
- };
- // The server should respond with the following.
- MockRead data_reads[] = {
- MockRead("HTTP/1.0 200 OK\r\n"),
- MockRead("Content-Type: text/html; charset=iso-8859-1\r\n"),
- MockRead("Content-Length: 100\r\n\r\n"),
- MockRead(SYNCHRONOUS, OK),
- };
- StaticSocketDataProvider data(data_reads, data_writes);
- session_deps_.socket_factory->AddSocketDataProvider(&data);
- TestCompletionCallback callback;
- // Start the transaction.
- int rv = trans.Start(&request, callback.callback(), NetLogWithSource());
- EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
- // Wait for completion.
- rv = callback.WaitForResult();
- EXPECT_THAT(rv, IsOk());
- // Get the response info.
- const HttpResponseInfo* response = trans.GetResponseInfo();
- // Verify that the alias list was stored in the response info as expected.
- ASSERT_TRUE(response);
- EXPECT_THAT(response->dns_aliases, testing::ElementsAre("www.example.org"));
- }
- } // namespace net
|