WebKit Bugzilla
Attachment 349967 Details for
Bug 189606
: Web Inspector: group media network entries by the node that triggered the request
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
189606.diff (text/plain), 102.08 KB, created by
Devin Rousso
on 2018-09-17 16:18:43 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Devin Rousso
Created:
2018-09-17 16:18:43 PDT
Size:
102.08 KB
patch
obsolete
>diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 7dd3b8aafea..1c775ad7820 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,22 @@ >+2018-09-17 Devin Rousso <drousso@apple.com> >+ >+ Web Inspector: group media network entries by the node that triggered the request >+ https://bugs.webkit.org/show_bug.cgi?id=189606 >+ <rdar://problem/44438527> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * http/tests/inspector/network/resource-initiatorNode-expected.txt: Added. >+ * http/tests/inspector/network/resource-initiatorNode.html: Added. >+ >+ * http/tests/inspector/network/har/har-basic.html: >+ * inspector/unit-tests/resource-collection.html: >+ Update for changes to `WI.Resource`. >+ >+ * inspector/canvas/requestNode-expected.txt: >+ * inspector/canvas/requestNode.html: >+ Test case no longer needed since the document is always requested once it's available. >+ > 2018-09-17 Basuke Suzuki <Basuke.Suzuki@sony.com> > > [Curl] Respond with requested authentication scheme for authentication challenge. >diff --git a/LayoutTests/http/tests/inspector/network/har/har-basic.html b/LayoutTests/http/tests/inspector/network/har/har-basic.html >index 3c8fef964f3..6205dc44b3d 100644 >--- a/LayoutTests/http/tests/inspector/network/har/har-basic.html >+++ b/LayoutTests/http/tests/inspector/network/har/har-basic.html >@@ -34,19 +34,13 @@ function test() > const url = "https://example.com/fake.js"; > const mimeType = "text/javascript"; > const type = WI.Resource.Type.Script; >- const loaderIdentifier = undefined; >- const targetId = undefined; >- const requestIdentifier = undefined; > const requestMethod = "GET"; > const requestHeaders = {"Test-Request-Header": "Test Request Header Value"}; > const responseHeaders = {"Test-Response-Header": "Test Response Header Value"}; > const statusCode = 200; > const statusText = "OK"; > const source = "network"; >- const requestData = null; > const requestSentWalltime = 1508723752694 / 1000; // Sun Oct 22 2017 18:55:52 GMT-0700, when this test was written. >- const initiatorSourceCodeLocation = null; >- const timestamp = undefined; > const size = 1234; > const timingData = { > startTime: 1, >@@ -72,14 +66,18 @@ function test() > requestHeaders, > }; > >- let bareResource = new WI.Resource(url, mimeType, type, loaderIdentifier, targetId, requestIdentifier, requestMethod, requestHeaders, requestData, timestamp, requestSentWalltime, initiatorSourceCodeLocation, timestamp); >- bareResource.markAsFinished(undefined); >+ let bareResource = new WI.Resource(url, {mimeType, type, requestMethod, requestHeaders, requestSentWalltime}); >+ bareResource.markAsFinished(); > >- let fullResource = new WI.Resource(url, mimeType, type, loaderIdentifier, targetId, requestIdentifier, requestMethod, requestHeaders, requestData, timestamp, requestSentWalltime, initiatorSourceCodeLocation, timestamp); >+ let fullResource = new WI.Resource(url, {mimeType, type, requestMethod, requestHeaders, requestSentWalltime}); >+ >+ const timestamp = null; > fullResource.updateForResponse(url, mimeType, type, responseHeaders, statusCode, statusText, timestamp, timingData, source); > fullResource.increaseSize(size); > fullResource.updateWithMetrics(metrics); >- fullResource.markAsFinished(1.7); >+ >+ const elapsedTime = 1.7; >+ fullResource.markAsFinished(elapsedTime); > > let har = await WI.HARBuilder.buildArchive([bareResource, fullResource]); > InspectorTest.json(har, HARJSONFilter); >diff --git a/LayoutTests/http/tests/inspector/network/resource-initiatorNode-expected.txt b/LayoutTests/http/tests/inspector/network/resource-initiatorNode-expected.txt >new file mode 100644 >index 00000000000..239cb049aca >--- /dev/null >+++ b/LayoutTests/http/tests/inspector/network/resource-initiatorNode-expected.txt >@@ -0,0 +1,17 @@ >+Tests that Request initiatorNode is set correctly. >+ >+ >+ >+== Running test suite: WI.Resource.initiatorNode >+-- Running test case: WI.Resource.initiatorNode.posterPNG >+PASS: Resource should have an initiatorNode >+PASS: Resource initiatorNode should match video node id >+ >+-- Running test case: WI.Resource.initiatorNode.sourceMP4 >+PASS: Resource should have an initiatorNode >+PASS: Resource initiatorNode should match video node id >+ >+-- Running test case: WI.Resource.initiatorNode.trackVTT >+PASS: Resource should have an initiatorNode >+PASS: Resource initiatorNode should match video node id >+ >diff --git a/LayoutTests/http/tests/inspector/network/resource-initiatorNode.html b/LayoutTests/http/tests/inspector/network/resource-initiatorNode.html >new file mode 100644 >index 00000000000..2f119a0cf1f >--- /dev/null >+++ b/LayoutTests/http/tests/inspector/network/resource-initiatorNode.html >@@ -0,0 +1,137 @@ >+<!doctype html> >+<html> >+<head> >+<script src="../resources/inspector-test.js"></script> >+<script> >+ >+function replay() { >+ let videoElement = document.getElementById("video"); >+ videoElement.pause(); >+ videoElement.currentTime = 0; >+ videoElement.load(); >+} >+ >+function loadPoster(url) { >+ document.getElementById("video").poster = url; >+ >+ replay(); >+} >+ >+function loadSource(url, type) { >+ let sourceElement = document.createElement("source"); >+ sourceElement.type = type; >+ sourceElement.src = url; >+ >+ document.getElementById("video").appendChild(sourceElement); >+ >+ replay(); >+} >+ >+function loadTrack(url, kind) { >+ let trackElement = document.createElement("track"); >+ trackElement.kind = kind; >+ trackElement.default = true; >+ trackElement.src = url; >+ >+ trackElement.track.mode = "hidden"; >+ >+ document.getElementById("video").appendChild(trackElement); >+ >+ replay(); >+} >+ >+function handleVideoEnded(event) { >+ TestPage.dispatchEventToFrontend("TestPage-video-ended"); >+} >+ >+function test() >+{ >+ let suite = InspectorTest.createAsyncSuite("WI.Resource.initiatorNode"); >+ >+ let videoNode = null; >+ >+ suite.addTestCase({ >+ name: "WI.Resource.initiatorNode.posterPNG", >+ test(resolve, reject) { >+ let file = "white.png"; >+ >+ WI.Frame.awaitEvent(WI.Frame.Event.ResourceWasAdded) >+ .then((event) => { >+ let resource = event.data.resource; >+ >+ InspectorTest.assert(resource.url.endsWith(file), `Resource should be "${file}"`); >+ >+ InspectorTest.expectNotNull(resource.initiatorNode, "Resource should have an initiatorNode"); >+ if (resource.initiatorNode) >+ InspectorTest.expectEqual(resource.initiatorNode.id, videoNode.id, "Resource initiatorNode should match video node id"); >+ }) >+ .then(resolve, reject); >+ >+ InspectorTest.evaluateInPage(`loadPoster("resources/${file}")`); >+ } >+ }); >+ >+ suite.addTestCase({ >+ name: "WI.Resource.initiatorNode.sourceMP4", >+ test(resolve, reject) { >+ let file = "white.mp4"; >+ >+ WI.Frame.awaitEvent(WI.Frame.Event.ResourceWasAdded) >+ .then((event) => { >+ let resource = event.data.resource; >+ >+ InspectorTest.assert(resource.url.endsWith(file), `Resource should be "${file}"`); >+ >+ InspectorTest.expectNotNull(resource.initiatorNode, "Resource should have an initiatorNode"); >+ if (resource.initiatorNode) >+ InspectorTest.expectEqual(resource.initiatorNode.id, videoNode.id, "Resource initiatorNode should match video node id"); >+ }) >+ .then(resolve, reject); >+ >+ InspectorTest.evaluateInPage(`loadSource("resources/${file}", "video/mp4")`); >+ } >+ }); >+ >+ suite.addTestCase({ >+ name: "WI.Resource.initiatorNode.trackVTT", >+ test(resolve, reject) { >+ let file = "white.vtt"; >+ >+ // Loading a track causes a bunch of media controls to be loaded. >+ let listener = WI.Frame.addEventListener(WI.Frame.Event.ResourceWasAdded, (event) => { >+ let resource = event.data.resource; >+ if (!resource.url.endsWith(file)) >+ return; >+ >+ InspectorTest.expectNotNull(resource.initiatorNode, "Resource should have an initiatorNode"); >+ if (resource.initiatorNode) >+ InspectorTest.expectEqual(resource.initiatorNode.id, videoNode.id, "Resource initiatorNode should match video node id"); >+ >+ WI.Frame.removeEventListener(WI.Frame.Event.ResourceWasAdded, listener); >+ >+ resolve(); >+ }); >+ >+ InspectorTest.evaluateInPage(`loadTrack("resources/${file}", "captions")`); >+ } >+ }); >+ >+ WI.domTreeManager.requestDocument((documentNode) => { >+ WI.domTreeManager.querySelector(documentNode.id, "video#video", (videoNodeId) => { >+ videoNode = WI.domTreeManager.nodeForId(videoNodeId); >+ if (videoNode) >+ suite.runTestCasesAndFinish(); >+ else { >+ InspectorTest.fail(`DOM node for "video#video" not found.`); >+ InspectorTest.completeTest(); >+ } >+ }); >+ }); >+} >+</script> >+</head> >+<body onload="runTest()"> >+ <p>Tests that Request initiatorNode is set correctly.</p> >+ <video id="video" muted autoplay></video> >+</body> >+</html> >diff --git a/LayoutTests/http/tests/inspector/network/resources/white.mp4 b/LayoutTests/http/tests/inspector/network/resources/white.mp4 >new file mode 100644 >index 0000000000000000000000000000000000000000..a7bcd70e3f52d5de4236758c1e89bfb8816d1ec6 >GIT binary patch >literal 3843 >zcmeHKUuYaf7~e~pnvzy4wx&uf1IFS*{_JkfG#)I?C4^S7P!x-Tu+HwzW!LQ9Zgw}9 >zyS}s*DL(ih3WcU{2clSNA4)+}tWqEPP((qo*rxiRK8U4OBdE0$dj972?y`5?g5pb& >z4$RCq-=E+2eKX(A%?X0gmkUdt<E3Rm5K@>WPFsQN)Yb+KF{7;+z|gT~J;qJbhOpt- >zQZ{=%g=MGE8$3TQ{5EmuMaa6$%RirhYR84uUDfKjZ>KJO{NvJ&#e)ME$kM~V{92Sp >z(`1n7uFr@hi^P|u$0R~Wa_O|V6@nc@P#E61Yij#onq+rRLepS61e2~;vRN)9vM7!W >z%AzEJX@;Sf86KXWpC2k%26JtiA9DTaVeVzf3>_Oft`}NvKFAQAYE)Mw;<KDGLJX$a >zu0Eqk88IUgnx}RtV2W5A$%sWs8X*o-OjabpoCazu@q!XeF{-|yNJAowFc8NoGDGEv >z5-e1o=BJq=jS}7TU5BbLl}P9_+qMEwW5qE;4?*a&jv^uiYV2|IOp&Dlq?4mTsCvPS >z<#CM&VAfOJTrOatGANVK^kD%YnFO|_!*PQnlDuC7)GddG+^LlhnQv1lfv?$fJ}s%b >z>v%N8TE~8bKDF|IfTB;iPR^$e3$Qbq>XkrSh9ZNe2K9KznyOhe;7%-`)smQJ*0dRF >zkhvbqtJAIrX~gtkI>So9Rz}4-r8-t#86|<v@=Tu#m9)r%^eNvxp9Ln2eO<L(cZQls >zlgoWw(KVkq8n%!prCHENda{@vBb*9dn;!<5<*6y+5S-0=+)r($MP>AHFoKYIN}3e3 >zg6h!X3Ib<nbGg9U18`X$BPasZ#QElND8%w`oG2YQKqzz;mBP<m*oPwD#$J6zc(8io >z>bb?wPF#7${h;T_)wjx9)XBL=Qil(oxsur@eE7%S#c$ltzwCPZi*bA-9Ub>PxAf=v >zt?3_RCG#>MI@X97*JT&_?d;wgU%z%-=sa3u@50!VEl(8pSGnDrE6h}xhS|NG`9_?n >zzZ5YeO^$kBcENn&NY*^`RQGT-!hWx5u`XLaFm>-h@6G7%)X`g9zFS9+T-MQ#0o{(F >zuS5>?Pp38}p<hah{c;leavOR)_R8If=#{~Q*ek;c=!es7=<(PqPbZ_#Cd6I|lF*B7 >z=q<4yY@){xu=0LV?2C2u_^BTLs13a(_KQvQ_yJa~CB=R{3H`e^^my#$%}w-p>}4eZ >zy}T^}eWAY%Jsx{`qKO`l{a@C5ydqm-Kah-mr`~V(dOvl`n(4__E>85c-C=7}m21{| >zwZ@IAbUm)UfAU)4H~M~I_38g`qj#NhT(<y!wo@<-%)<FkjxX_!8~Z0gxa%t+g$EWF >zG+N67%(nG-Loa#mz+-DWeh_CMej%Kx`An_&Y@oq!du#L4&}^uUgGljV8C?+inGpt< >z`<NZn--6tthI=-$U3J<qED9as811?DoD_uKbI+dPP=aI{wqK(#@F!b?=JO<f6z*g| >zBD?u(4y;u<{F>)LY$!NUf?ToQ`i)4|XW$7@=ke6m&iOXM40_d;Ak=KoM}sh^9ZJL( >z7HC12K=a0JS{jmH7IuKeJ8w5>MC{nOsfwx-M4(Ql@Hno1f9tYKHQ&g>2E1$<TMF|B >zc+qYO!rFFoaPC(@N93u$^c6nmaoO2uPW|4x#wwEYjG=c&Uf+-Ue(~+8?ceRPKd;{+ >zJ{~XXA>f}MZ}{Y!HSs9;dX2ln-&~h>)@Oe9-O$@p*W(jvr}Ih7z33Zb{h>DA|6$GZ >ayB|G|-WP;AzfySP`-A_etC3^(#lHa_5C#VT > >literal 0 >HcmV?d00001 > >diff --git a/LayoutTests/http/tests/inspector/network/resources/white.png b/LayoutTests/http/tests/inspector/network/resources/white.png >new file mode 100644 >index 0000000000000000000000000000000000000000..ac49a6139f5b587763e2a5bd3d80e23825f665fb >GIT binary patch >literal 10044 >zcmeHLhgVZsx4)rRgHnPZ5EGgTBvPaY1cZQqp-5E}Fw{VRgb7U&nu0JC8R>!oLs1c; >zpnwV(snTp91BmplfHZ0H1?8KWx88d1FUVah>z;jfId`9v`@8$M<1pq%yj&t&008hB >zqYW$pfQbSCpkWR+`i#ok!EpfKG4<5f#~ADDLooq(H%}ZE0MK!_Y}u`?+C*|4EsZ@Q >zFon@W2FI8{h0$+d9B4sYv}7{I#gqf~TN+mI!n0UPZT@}OjfbqsRW68l7m_?U(8Asx >z!hOnmsIZ~-Yw*JD^*kj~-S%?#dV0rgO=gOd*d^(9qg9Y>ve0Y(0-7EFdnLQV>lB{p >z2EJiRCq(v2PIR;#fGyd5_Phqfcb?pHv1zq?Y4<prUWy(7+ywm7Fh^x6K{`NCrmi%C >zh0=O0<XL8nqF^o$HRT8!2h}u&pj>Sl^H{ms!6!ARH6};~xFV8==mzON6`Zv{6M3Yy >zAe7q$T#A9Q>L&5{SLk*?^p5Z@wMItH9OwB$A@oAD)X8HVB9r6Gglkl3NLBJHDK2{y >zxp&t-aaW#o<MmOA#EQ3#-=+=DcUAa4{Z`acg5(`_^0c|2)p(7sK9!?qjjzC(s;F_s >zHOYZP;DVh}Lv){hD>x~lk7*R`8Ghk`P2Mf}xbf3Gwj2&}$Ht|+rxXqygWasm3H&w_ >zx1_J;*frrXb!utCtN!>_>g(qMiD|oOc8#K=<clzK^Y@Jj7V(m${(N(K9oFMgO&&Pp >z)}fQCzO9B2O|6^oV1Ei)M6hV2rO2%v&R@0mjj0J!*9W6ULyDVJVn)Y3<h#v5m&EFi >zHI~7S$zWrR3NwT?|A@y3h~I4!dnR|Y$YZ&w_DYO%Tz?G$yTR!YnsfYhlI4ug(I*%I >zDbK0Vmoa{)y}mE0**oh!k~Y^mk*=d~njh@M;{t+2GYes8X{<$27oaoKJ~J`(%J38l >zcpS<eOL=CaqzpIHhQ)MCVwiqV&@2M4mT4afU>KIwylYii#hR@)NkXOW;}I=<5Q=az >zn0%t=ap9{W%a?czeB(L^l%OJUs;5sU@JLBqkJlgi&*femJ?p}9GDp}fL9%vuG6*Ri >z+d^}f#W|^ou1nllLxj>?^<+klj%eJC_Y2J`wEl4(C5IFzo(8A%=RB_KI82IufC>^8 >zXW2Na+SS+@p^0J(867_Q<|+6?Kvl~9N4r^Dc=a%gz%sF>s7Omw*}DQ$<?ge!vzt7R >zOT0F*G0Ido-jBC5wZ2u6zd~*a(NL4#XK@FgfHkAUTDqLCR|qxG5?#vr&dgVEfy?th >zf4J|_>X@&QtJO+RMyIZ~_})#fB*P@}q@*mWo(0v5%rZFh$UeY0u{yaaLbE=$DV59c >z_bb7{L9~mGt730)R^=J93(PdF-SmemD!^&l%a<?p$ulk^nlE-8fs&-%cj{sh0}-5n >z`w3Q);1t8__r+OsSwj|oS7f$nIH2|_>^TL&!EzVMl)$_MJzN-7TJhSYI(Oo-bOy6f >zWB`UUElTAM8;&LW<!=?-^Q`j2d};^Gqqv6^s}Fo_=y}hZ8-ZG6<AHMM=}mJmpVWVF >zkiC(2Nv{u$JQUFgi$iPNj2nkq8pL&+t~-4^<rbRv5vQkaxZVL+O9}xk6CfH)S%D%_ >zz_QogVc;JQ1sWI?;QokezSA}>pv-<dBJB=#+Okrl%!riVIqko~6e9LTFYoS-a03x3 >z?G{zzic5%Zay@K!O1fpzS<p_<CP~HFXOUcYBhdLpUuaIOlAqAm1Gaw3xslw9hreru >zaXLleTe6o@zn|X*4P7Tozu^>OQPl$?j55%zM>{0{;J?S=$jQ!8JUsBhEJ$DSP^N)Q >zzC@Vl`?#9MzZ#_)R~tVyx;C1R!d-OY3>4utDUs+UNmOaFwYh^)zp;i%t=_Ek3;0}e >zS)0>1I)KgIL_x|ng_N9>T%Mel%r3hrz-|Ia<-!U(^5qI}cPlLvENYK2TQlF|SBcFs >z?fg@r(8emeq_~7sT23Sqae>=`($i?7(6sg3{9E<=%eqtAoyn6XWACKj|55p8rB9`6 >z<v^t^QR7pJxJmaN$h-7+qSG?d>oW_)!?gv(;99*;8?{xnowc^ayg7@NBP(hlR;wl} >z_g2<sF20-VDW2AxC9H02F0Xj6f@eQ}SWvwz93;{xDj+O(vd`JCYq<1i+ncvY8pgxU >zt@^LU=n*(ubA_wlVWwu)1o;H31YdZ5O6tLG*^edfJkl+$TjWviE(woWkGYIFjJ;~U >zXqqt7I(~9Fvppj;Q#C`vRL)FI8kX85Z6<ANI+T@&<W&*Ow8{8->V@y-%LJ^DbDH}T >z+JmO~Ty@{CUZ|I0MH_6(R+BH_35G0*d<iAOR8nKPP)W@FGx<%p_)Z~+{HA=FT!9=m >zZBFi--I~M6GQF~ZG8;!R>MYgGj@|L>16xOlsvozp9itWB?0X)hK0t|bXM2eL*(sfU >zARFW;GaxWvIq>Pp`h3Z6xM#R$J->bV?dn?Z+Sr$=KGpu+SzZ6jnz3TN8ae(!bJOD) >zlizQ<#*bOaSjpsC#aR`+zvx~|h+XEH3Yqd&Fn~Nco7*0e-u|%Ue$xHEs@~O`qO+58 >z(*BMMz3MlS@5qJ3D?6>(UzJITp(&vSTTvDr7SsY0qpE}uRDU?Jd0McbJK@Lt$XLn( >zwP`G|`0kWiw`KRK?sTVzPE6$v<=#WY1@ywkP}vZox%&5mzyF1tOas4if8I?(eL>}g >z?SxI#nbm2BuZ3rZ2ZpQuWjN2Wc4*C>97)dD4cpcKvA`V0%*DLMwtaY7JOfe<U!1Wk >zrsh)}n^9bkct_cNxMsQBSl!un`341D_-Wu$aIml!<T%eKk<I8aTHD0@xE6SsBlWr% >zM`%0maMy%5cMGk6c7mn}<AGbkykK9A`VA)yP8qJ9*)Zr#)DSX@O^kCocs13%jek)j >z=<3*ZbEg<d@tRPofEE8TvRB1MeBhM0n2zuEy(QAvk<mhb`6XyBr2hC1r${SWLUf)C >zpNynw$?Zk8w@UuzqnVP1?<xz$jPW;L-AtGIZ0v7tQB+wx`=`0N5Bh4hQ0^1OGVjsp >zID(85TJ>Cd;ZwI{MN6e8ZY$?*WK_CYu3yP(n@Gi*`e#{cO$=Humu^^r&%MuX&U=DL >zP0mcKfiJ^#axZl+bdO?tu&bQakyVlIG|Y&XbCN8&(sD&oQ#KU4_CDuM&Utn1Q9l1$ >z)wZ--AJ9(YhEu*BSF<5`Pv!AQ9eFYdR0DlHeCGouOGaD$lUK;nig{-CgA2VX@XO6v >zhp&DU-mqcK&&c<XSB_*~i#Ktfc>0?C%*!)XXBOOwx(01=7&-Ymwf4Z?QTuZyu(RPg >zzjq6D_~yAPxsT+q6VwT+o%)m5PVYRtYCSG|J+g##0AdN5l;8gILje&xGlzdy=Xv6> >zoFis!dY}X^+8)?GF`-(|z3n>&3ro3T(c-euG$%xU$Y+yNzEbkw-gdP?#rXDm?q^%F >zPPKBVXN%%ztY{j4`q}i)b_XB1Y?(yek~$$#CQ^SdSj9WAY4)RcQJK1}N|D!?!>q$Z >z|HIk7+1|jlxwP^vJNUyICsCVc&${w`{XY$?(pGIxMf-a6d(=<^#;!|9>J0V^RF&2Y >zQR}>v{0VO-TO2K)=4_<wxW2MkF1zKZ<CE$;*PmOxb0zAM{;LD=V(lVt4Y97>U2U3( >z1+LFM{o_NGo~i`Wgm{Hf&D46HBDt2T>W1G!t<@Fn9N3yWfIMKW4DWoLwdK$#f3a+) >z>^6Ig7!J>k(_CCG$$KjHNZmTL@B88-_y;)Fh%G7Y$QK=H&E8P0sqY1Ao?l4jrds}A >z#-mfkie1caYl{VMHXiQEEO3wN64!wEeH{*7+eqWCgJdB#FK8{scO%#}!ZfoG8yCG^ >z%#&-%2)L<~6Gv?mFY(rgY>F)O$ISVE)WjDKRtFNkbv|^YIiAB$eGXspep}8=5*m~m >zEUPXim(SKU?QD{3w!KN|_>Uv(BVYxTX-Lpi%JAFAp9Si#&MSnPk}s?_ZW_O`Dlfhs >z0t;2xMa`^#b${f}{9=MEylt^QxUum=M}PNupDML{D`vZCxLvBe!^tO9donPTthc+P >z%8F+jvU#o)`gBKoYbO)zDUr+5v5nre+i9Dy8koxHCb4s~v17y3FI^RAxUB#9F({~p >z7YNY+651EHk;a5>EAIT7?0W~lpR*%Ctm6@YS%sC@$C?(Pk2!mcsa1@NGFy^+gbRaT >z7%37w^W<szwRkqXRx~Lps$32PtpY6?qtw(Y!u=NC3klEr0EwM%1`+4==z0mg^V7AZ >zexUCrKX`HL<Z$=z&xYvqg3}LePXGWRsl6Y_*iv$l&OB~=TH6ur%uF?0@jeR9SMV-a >zg&-e4x-|f31!>TSK3JkNG{^_%OV9|?hW)hAppW;a5isaa6QZ{^%+3r0)yD^5p(+Z> >z3P>1=3krp51zd5{urx5-cc)9*Fb^WpPXmD<kw^+8B?WwdJL06ex;g@>h)`6Nr(4Jq >zf_;h3LGr!?_^%-Ujbnf%xCVIo5k2v~(7m|MF8DyAHVn46(BIdu=fnni{<D%VVLvT; >zf`~m0;-mr+@po*xtJdDE2F5c8i?cKE^uhWP=xd-(DI>Lh+W#-jKP&#r)BYb%Wwrm| >z`7h1Brxs!_fqy0RYqx&R(zgr6rG@x=>rq@M%&@ie(>UU3aL$^3XWBa&`b9rHKz9F5 >zAM@Od)6bEo-<^yNPFn|o=6g>c1fV?3r)MuIV=Md}+5cKesaZ&b>rwy^6AK4lD@Ot- >zW5xlqH-_p`8X!nOo9U+pstc9A3^a2=(tlY(F9VzV3W~021CSu7ps+7D04vPD{DFuJ >z3P||Gg$w)fD4=QfpMmKyPJ)<`Hr3Vph9KrQ;Jp?1g1a!WU4G!_&$%zN-I3T=a5S>; >zG}w)d9@>|Abanpw;IW*-6e_JrYF`$ngzskr<>N;Jt}*dv_hlrov!4JXp}lQnoDkzL >zxBqG|-XS{TFi?&G3XJa%<HO3q$EXzOaLB0T_9{w7aY`@C|L<yBj!rmsck_--x6zq~ >z;~vxa!r&PUp20wmUksLk9{(?TFt|FsCBo>Y(2H(HduWe|Gx}ZhZXp8{7@+X0HOv47 >f1}N-z_2mW|LtcXg{ch0t24H-~+~A?!<;ed4a&zRe > >literal 0 >HcmV?d00001 > >diff --git a/LayoutTests/http/tests/inspector/network/resources/white.vtt b/LayoutTests/http/tests/inspector/network/resources/white.vtt >new file mode 100644 >index 00000000000..f3e906d3f88 >--- /dev/null >+++ b/LayoutTests/http/tests/inspector/network/resources/white.vtt >@@ -0,0 +1,7 @@ >+WEBVTT >+ >+00:00:00.000 --> 00:00:00.999 >+0.000 to 0.999 >+ >+00:00:01.000 --> 00:00:01.999 >+1.000 to 1.999 >diff --git a/LayoutTests/inspector/canvas/requestNode-expected.txt b/LayoutTests/inspector/canvas/requestNode-expected.txt >index 715c431b0e9..9b04fa6b555 100644 >--- a/LayoutTests/inspector/canvas/requestNode-expected.txt >+++ b/LayoutTests/inspector/canvas/requestNode-expected.txt >@@ -2,18 +2,13 @@ Test that CanvasAgent.requestNode can properly resolve the owner canvas node. > > > == Running test suite: Canvas.requestNode >--- Running test case: Canvas.requestNode.missingDocument >-PASS: The page should have three canvases. >-PASS: Should produce an error. >-Error: Document has not been requested >- > -- Running test case: Canvas.requestNode.validCanvasId > PASS: Canvas "CSS canvas âcssâ" has node with valid id. > PASS: Canvas "CSS canvas âcssâ" has node with type "CANVAS". >+PASS: Canvas "Canvas #onscreen" has node with valid id. >+PASS: Canvas "Canvas #onscreen" has node with type "CANVAS". > PASS: Canvas "Canvas 1" has node with valid id. > PASS: Canvas "Canvas 1" has node with type "CANVAS". >-PASS: Canvas "Canvas 2" has node with valid id. >-PASS: Canvas "Canvas 2" has node with type "CANVAS". > > -- Running test case: Canvas.requestNode.invalidCanvasId > PASS: Should produce an error. >diff --git a/LayoutTests/inspector/canvas/requestNode.html b/LayoutTests/inspector/canvas/requestNode.html >index 0dcc8dcdf53..5e244b04b92 100644 >--- a/LayoutTests/inspector/canvas/requestNode.html >+++ b/LayoutTests/inspector/canvas/requestNode.html >@@ -14,25 +14,6 @@ function load() { > function test() { > let suite = InspectorTest.createAsyncSuite("Canvas.requestNode"); > >- suite.addTestCase({ >- name: "Canvas.requestNode.missingDocument", >- description: "Getting the canvas node requires that WebInspector knows about the document.", >- test(resolve, reject) { >- let canvases = WI.canvasManager.canvases; >- InspectorTest.expectEqual(canvases.length, 3, "The page should have three canvases."); >- if (!canvases.length) { >- reject("Missing canvas."); >- return; >- } >- >- CanvasAgent.requestNode(canvases[0].identifier, (error) => { >- InspectorTest.expectThat(error, "Should produce an error."); >- InspectorTest.log("Error: " + error); >- resolve(); >- }); >- } >- }); >- > suite.addTestCase({ > name: "Canvas.requestNode.validCanvasId", > description: "Get the node id for each canvas on the page.", >diff --git a/LayoutTests/inspector/unit-tests/resource-collection.html b/LayoutTests/inspector/unit-tests/resource-collection.html >index f989cefdbdc..f6133043131 100644 >--- a/LayoutTests/inspector/unit-tests/resource-collection.html >+++ b/LayoutTests/inspector/unit-tests/resource-collection.html >@@ -8,7 +8,7 @@ function test() > let suite = InspectorTest.createAsyncSuite("ResourceCollection"); > > function createResource(url, type) { >- return new WI.Resource(url, null, type); >+ return new WI.Resource(url, {type}); > } > > function logResourceNames(collection) { >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index 5d7b9aee758..c8f152c9a94 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -1,3 +1,16 @@ >+2018-09-17 Devin Rousso <drousso@apple.com> >+ >+ Web Inspector: group media network entries by the node that triggered the request >+ https://bugs.webkit.org/show_bug.cgi?id=189606 >+ <rdar://problem/44438527> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * inspector/protocol/Network.json: >+ Add an optional `nodeId` field to the `Initiator` object that is set it is possible to >+ determine which ancestor node triggered the load. It may not correspond directly to the node >+ with the href/src, as that url may only be used by an ancestor for loading. >+ > 2018-09-17 Darin Adler <darin@apple.com> > > Use OpaqueJSString rather than JSRetainPtr inside WebKit >diff --git a/Source/JavaScriptCore/inspector/protocol/Network.json b/Source/JavaScriptCore/inspector/protocol/Network.json >index 891dac5f883..091d4cb55e2 100644 >--- a/Source/JavaScriptCore/inspector/protocol/Network.json >+++ b/Source/JavaScriptCore/inspector/protocol/Network.json >@@ -142,7 +142,8 @@ > { "name": "type", "type": "string", "enum": ["parser", "script", "other"], "description": "Type of this initiator." }, > { "name": "stackTrace", "type": "array", "items": { "$ref": "Console.CallFrame" }, "optional": true, "description": "Initiator JavaScript stack trace, set for Script only." }, > { "name": "url", "type": "string", "optional": true, "description": "Initiator URL, set for Parser type only." }, >- { "name": "lineNumber", "type": "number", "optional": true, "description": "Initiator line number, set for Parser type only." } >+ { "name": "lineNumber", "type": "number", "optional": true, "description": "Initiator line number, set for Parser type only." }, >+ { "name": "nodeId", "$ref": "DOM.NodeId", "optional": true, "description": "Set if the load was triggered by a DOM node, in addition to the other initiator information." } > ] > } > ], >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 6f49e4c3031..bf2b23776fe 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,66 @@ >+2018-09-17 Devin Rousso <drousso@apple.com> >+ >+ Web Inspector: group media network entries by the node that triggered the request >+ https://bugs.webkit.org/show_bug.cgi?id=189606 >+ <rdar://problem/44438527> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Test: http/tests/inspector/network/resource-initiatorNode.html >+ >+ Add extra arguments to functions that create `ResourceRequest` objets for media resources so >+ that `initiatorNodeIdentifier` can be set for WebInspector frontend to use for grouping. >+ >+ * html/HTMLMediaElement.cpp: >+ (WebCore::HTMLMediaElement::loadResource): >+ * html/HTMLVideoElement.cpp: >+ (WebCore::HTMLVideoElement::setDisplayMode): >+ * loader/FrameLoader.h: >+ * loader/FrameLoader.cpp: >+ (WebCore::FrameLoader::willLoadMediaElementURL): >+ Handles initial (e.g. DNT) resource requests. >+ >+ * loader/ImageLoader.cpp: >+ (ImageLoader::updateFromElement): >+ Handles "poster" requests. >+ >+ * loader/MediaResourceLoader.cpp: >+ (MediaResourceLoader::requestResource): >+ Handles byte-range requests. >+ >+ * html/track/LoadableTextTrack.cpp: >+ (WebCore::LoadableTextTrack::loadTimerFired): >+ * loader/TextTrackLoader.h: >+ * loader/TextTrackLoader.cpp: >+ (WebCore::TextTrackLoader::load): >+ * html/HTMLTrackElement.h: >+ Handles <track> (e.g. subtitle) requests. >+ >+ * inspector/agents/InspectorDOMAgent.cpp: >+ (WebCore::InspectorDOMAgent::identifierForNode): >+ * inspector/InspectorInstrumentation.h: >+ (WebCore::InspectorInstrumentation::identifierForNode): >+ * inspector/InspectorInstrumentation.cpp: >+ (WebCore::InspectorInstrumentation::identifierForNodeImpl): >+ Allows callers to get a `DOM.nodeId` for the given `Node`, which is (in this patch) attached >+ to the `ResourceRequest` and later used by `InspectorNetworkAgent`. >+ >+ * inspector/agents/InspectorNetworkAgent.h: >+ * inspector/agents/InspectorNetworkAgent.cpp: >+ (WebCore::InspectorNetworkAgent::willSendRequest): >+ (WebCore::InspectorNetworkAgent::didLoadResourceFromMemoryCache): >+ (WebCore::InspectorNetworkAgent::buildInitiatorObject): >+ >+ * platform/network/ResourceRequestBase.h: >+ (WebCore::ResourceRequestBase::initiatorNodeIdentifier const): >+ (WebCore::ResourceRequestBase::setInitiatorNodeIdentifier): >+ * platform/network/ResourceRequestBase.cpp: >+ (WebCore::ResourceRequestBase::setAsIsolatedCopy): >+ * platform/network/cf/ResourceRequestCFNet.cpp: >+ (WebCore::ResourceRequest::updateFromDelegatePreservingOldProperties): >+ * loader/cache/CachedResourceLoader.cpp: >+ (WebCore::CachedResourceLoader::shouldContinueAfterNotifyingLoadedFromMemoryCache): >+ > 2018-09-17 Jer Noble <jer.noble@apple.com> > > Enable USE_MEDIAREMOTE on iOS >diff --git a/Source/WebCore/html/HTMLMediaElement.cpp b/Source/WebCore/html/HTMLMediaElement.cpp >index 8392dabf7a5..0be8e8dca7e 100644 >--- a/Source/WebCore/html/HTMLMediaElement.cpp >+++ b/Source/WebCore/html/HTMLMediaElement.cpp >@@ -1591,7 +1591,7 @@ void HTMLMediaElement::loadResource(const URL& initialURL, ContentType& contentT > } > > URL url = initialURL; >- if (!url.isEmpty() && !frame->loader().willLoadMediaElementURL(url)) { >+ if (!url.isEmpty() && !frame->loader().willLoadMediaElementURL(url, *this)) { > mediaLoadingFailed(MediaPlayer::FormatError); > return; > } >diff --git a/Source/WebCore/html/HTMLTrackElement.h b/Source/WebCore/html/HTMLTrackElement.h >index b9ca9485a5a..9cbdadb4c48 100644 >--- a/Source/WebCore/html/HTMLTrackElement.h >+++ b/Source/WebCore/html/HTMLTrackElement.h >@@ -58,6 +58,7 @@ public: > enum LoadStatus { Failure, Success }; > void didCompleteLoad(LoadStatus); > >+ RefPtr<HTMLMediaElement> mediaElement() const; > const AtomicString& mediaElementCrossOriginAttribute() const; > > private: >@@ -73,8 +74,6 @@ private: > > void loadTimerFired(); > >- RefPtr<HTMLMediaElement> mediaElement() const; >- > // TextTrackClient > void textTrackModeChanged(TextTrack&) final; > void textTrackKindChanged(TextTrack&) final; >diff --git a/Source/WebCore/html/HTMLVideoElement.cpp b/Source/WebCore/html/HTMLVideoElement.cpp >index f4149b2ff31..8f83a46f140 100644 >--- a/Source/WebCore/html/HTMLVideoElement.cpp >+++ b/Source/WebCore/html/HTMLVideoElement.cpp >@@ -263,7 +263,7 @@ void HTMLVideoElement::setDisplayMode(DisplayMode mode) > bool canLoad = true; > if (!poster.isEmpty()) { > if (RefPtr<Frame> frame = document().frame()) >- canLoad = frame->loader().willLoadMediaElementURL(poster); >+ canLoad = frame->loader().willLoadMediaElementURL(poster, *this); > } > if (canLoad) > player()->setPoster(poster); >diff --git a/Source/WebCore/html/track/LoadableTextTrack.cpp b/Source/WebCore/html/track/LoadableTextTrack.cpp >index 238ebe7be62..a8019f24870 100644 >--- a/Source/WebCore/html/track/LoadableTextTrack.cpp >+++ b/Source/WebCore/html/track/LoadableTextTrack.cpp >@@ -82,7 +82,7 @@ void LoadableTextTrack::loadTimerFired() > // mode being the state of the media element's crossorigin content attribute, the origin being the > // origin of the media element's Document, and the default origin behaviour set to fail. > m_loader = std::make_unique<TextTrackLoader>(static_cast<TextTrackLoaderClient&>(*this), static_cast<ScriptExecutionContext*>(&m_trackElement->document())); >- if (!m_loader->load(m_url, m_trackElement->mediaElementCrossOriginAttribute(), m_trackElement->isInUserAgentShadowTree())) >+ if (!m_loader->load(m_url, *m_trackElement)) > m_trackElement->didCompleteLoad(HTMLTrackElement::Failure); > } > >diff --git a/Source/WebCore/inspector/InspectorInstrumentation.cpp b/Source/WebCore/inspector/InspectorInstrumentation.cpp >index 7f7f126e047..61a7c739559 100644 >--- a/Source/WebCore/inspector/InspectorInstrumentation.cpp >+++ b/Source/WebCore/inspector/InspectorInstrumentation.cpp >@@ -128,6 +128,13 @@ bool InspectorInstrumentation::isDebuggerPausedImpl(InstrumentingAgents& instrum > return false; > } > >+int InspectorInstrumentation::identifierForNodeImpl(InstrumentingAgents& instrumentingAgents, Node& node) >+{ >+ if (InspectorDOMAgent* domAgent = instrumentingAgents.inspectorDOMAgent()) >+ return domAgent->identifierForNode(node); >+ return 0; >+} >+ > void InspectorInstrumentation::willInsertDOMNodeImpl(InstrumentingAgents& instrumentingAgents, Node& parent) > { > if (InspectorDOMDebuggerAgent* domDebuggerAgent = instrumentingAgents.inspectorDOMDebuggerAgent()) >diff --git a/Source/WebCore/inspector/InspectorInstrumentation.h b/Source/WebCore/inspector/InspectorInstrumentation.h >index dde2122cced..926c97d63c3 100644 >--- a/Source/WebCore/inspector/InspectorInstrumentation.h >+++ b/Source/WebCore/inspector/InspectorInstrumentation.h >@@ -106,6 +106,7 @@ public: > static void didClearWindowObjectInWorld(Frame&, DOMWrapperWorld&); > static bool isDebuggerPaused(Frame*); > >+ static int identifierForNode(Node&); > static void willInsertDOMNode(Document&, Node& parent); > static void didInsertDOMNode(Document&, Node&); > static void willRemoveDOMNode(Document&, Node&); >@@ -290,6 +291,7 @@ private: > static void didClearWindowObjectInWorldImpl(InstrumentingAgents&, Frame&, DOMWrapperWorld&); > static bool isDebuggerPausedImpl(InstrumentingAgents&); > >+ static int identifierForNodeImpl(InstrumentingAgents&, Node&); > static void willInsertDOMNodeImpl(InstrumentingAgents&, Node& parent); > static void didInsertDOMNodeImpl(InstrumentingAgents&, Node&); > static void willRemoveDOMNodeImpl(InstrumentingAgents&, Node&); >@@ -470,6 +472,14 @@ inline bool InspectorInstrumentation::isDebuggerPaused(Frame* frame) > return false; > } > >+inline int InspectorInstrumentation::identifierForNode(Node& node) >+{ >+ FAST_RETURN_IF_NO_FRONTENDS(0); >+ if (InstrumentingAgents* instrumentingAgents = instrumentingAgentsForDocument(node.document())) >+ return identifierForNodeImpl(*instrumentingAgents, node); >+ return 0; >+} >+ > inline void InspectorInstrumentation::willInsertDOMNode(Document& document, Node& parent) > { > FAST_RETURN_IF_NO_FRONTENDS(void()); >diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp >index af816ad13bc..0c7f72ba529 100644 >--- a/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp >+++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp >@@ -2085,6 +2085,11 @@ void InspectorDOMAgent::didCommitLoad(Document* document) > m_frontendDispatcher->childNodeInserted(parentId, prevId, WTFMove(value)); > } > >+int InspectorDOMAgent::identifierForNode(Node& node) >+{ >+ return pushNodePathToFrontend(&node); >+} >+ > void InspectorDOMAgent::didInsertDOMNode(Node& node) > { > if (containsOnlyHTMLWhitespace(&node)) >diff --git a/Source/WebCore/inspector/agents/InspectorDOMAgent.h b/Source/WebCore/inspector/agents/InspectorDOMAgent.h >index 93751a22ece..cd1f5a1ebb3 100644 >--- a/Source/WebCore/inspector/agents/InspectorDOMAgent.h >+++ b/Source/WebCore/inspector/agents/InspectorDOMAgent.h >@@ -157,6 +157,7 @@ public: > > > // InspectorInstrumentation >+ int identifierForNode(Node&); > void didInsertDOMNode(Node&); > void didRemoveDOMNode(Node&); > void willModifyDOMAttr(Element&, const AtomicString& oldValue, const AtomicString& newValue); >diff --git a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp >index 33310781caa..f305e2ae6d5 100644 >--- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp >+++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.cpp >@@ -45,6 +45,7 @@ > #include "FrameLoader.h" > #include "HTTPHeaderMap.h" > #include "HTTPHeaderNames.h" >+#include "InspectorDOMAgent.h" > #include "InspectorTimelineAgent.h" > #include "InstrumentingAgents.h" > #include "JSExecState.h" >@@ -386,7 +387,7 @@ void InspectorNetworkAgent::willSendRequest(unsigned long identifier, DocumentLo > auto protocolResourceType = InspectorPageAgent::resourceTypeJSON(type); > > Document* document = loader && loader->frame() ? loader->frame()->document() : nullptr; >- auto initiatorObject = buildInitiatorObject(document); >+ auto initiatorObject = buildInitiatorObject(document, request); > > String url = loader ? loader->url().string() : request.url(); > m_frontendDispatcher->requestWillBeSent(requestId, frameId, loaderId, url, buildObjectForResourceRequest(request), sendTimestamp, walltime.secondsSinceEpoch().seconds(), initiatorObject, buildObjectForResourceResponse(redirectResponse, nullptr), type != InspectorPageAgent::OtherResource ? &protocolResourceType : nullptr, targetId.isEmpty() ? nullptr : &targetId); >@@ -566,7 +567,7 @@ void InspectorNetworkAgent::didLoadResourceFromMemoryCache(DocumentLoader* loade > > m_resourcesData->resourceCreated(requestId, loaderId, resource); > >- RefPtr<Inspector::Protocol::Network::Initiator> initiatorObject = buildInitiatorObject(loader->frame() ? loader->frame()->document() : nullptr); >+ auto initiatorObject = buildInitiatorObject(loader->frame() ? loader->frame()->document() : nullptr, resource.resourceRequest()); > > // FIXME: It would be ideal to generate the Network.Response with the MemoryCache source > // instead of whatever ResourceResponse::Source the CachedResources's response has. >@@ -636,7 +637,7 @@ void InspectorNetworkAgent::didScheduleStyleRecalculation(Document& document) > m_styleRecalculationInitiator = buildInitiatorObject(&document); > } > >-RefPtr<Inspector::Protocol::Network::Initiator> InspectorNetworkAgent::buildInitiatorObject(Document* document) >+RefPtr<Inspector::Protocol::Network::Initiator> InspectorNetworkAgent::buildInitiatorObject(Document* document, std::optional<const ResourceRequest&> resourceRequest) > { > // FIXME: Worker support. > if (!isMainThread()) { >@@ -645,24 +646,38 @@ RefPtr<Inspector::Protocol::Network::Initiator> InspectorNetworkAgent::buildInit > .release(); > } > >+ RefPtr<Inspector::Protocol::Network::Initiator> initiatorObject; >+ > Ref<ScriptCallStack> stackTrace = createScriptCallStack(JSExecState::currentState()); > if (stackTrace->size() > 0) { >- auto initiatorObject = Inspector::Protocol::Network::Initiator::create() >+ initiatorObject = Inspector::Protocol::Network::Initiator::create() > .setType(Inspector::Protocol::Network::Initiator::Type::Script) > .release(); > initiatorObject->setStackTrace(stackTrace->buildInspectorArray()); >- return WTFMove(initiatorObject); >- } >- >- if (document && document->scriptableDocumentParser()) { >- auto initiatorObject = Inspector::Protocol::Network::Initiator::create() >+ } else if (document && document->scriptableDocumentParser()) { >+ initiatorObject = Inspector::Protocol::Network::Initiator::create() > .setType(Inspector::Protocol::Network::Initiator::Type::Parser) > .release(); > initiatorObject->setUrl(document->url().string()); > initiatorObject->setLineNumber(document->scriptableDocumentParser()->textPosition().m_line.oneBasedInt()); >- return WTFMove(initiatorObject); > } > >+ auto domAgent = m_instrumentingAgents.inspectorDOMAgent(); >+ if (domAgent && resourceRequest) { >+ if (int initiatorNodeIdentifier = resourceRequest->initiatorNodeIdentifier()) { >+ if (!initiatorObject) { >+ initiatorObject = Inspector::Protocol::Network::Initiator::create() >+ .setType(Inspector::Protocol::Network::Initiator::Type::Other) >+ .release(); >+ } >+ >+ initiatorObject->setNodeId(initiatorNodeIdentifier); >+ } >+ } >+ >+ if (initiatorObject) >+ return initiatorObject; >+ > if (m_isRecalculatingStyle && m_styleRecalculationInitiator) > return m_styleRecalculationInitiator; > >diff --git a/Source/WebCore/inspector/agents/InspectorNetworkAgent.h b/Source/WebCore/inspector/agents/InspectorNetworkAgent.h >index 64d0e045802..781c0049130 100644 >--- a/Source/WebCore/inspector/agents/InspectorNetworkAgent.h >+++ b/Source/WebCore/inspector/agents/InspectorNetworkAgent.h >@@ -132,7 +132,7 @@ private: > > WebSocket* webSocketForRequestId(const String& requestId); > >- RefPtr<Inspector::Protocol::Network::Initiator> buildInitiatorObject(Document*); >+ RefPtr<Inspector::Protocol::Network::Initiator> buildInitiatorObject(Document*, std::optional<const ResourceRequest&> = std::nullopt); > Ref<Inspector::Protocol::Network::ResourceTiming> buildObjectForTiming(const NetworkLoadMetrics&, ResourceLoader&); > Ref<Inspector::Protocol::Network::Metrics> buildObjectForMetrics(const NetworkLoadMetrics&); > RefPtr<Inspector::Protocol::Network::Response> buildObjectForResourceResponse(const ResourceResponse&, ResourceLoader*); >diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp >index e76d0db7c32..1fc6a67f70b 100644 >--- a/Source/WebCore/loader/FrameLoader.cpp >+++ b/Source/WebCore/loader/FrameLoader.cpp >@@ -88,6 +88,7 @@ > #include "MemoryRelease.h" > #include "NavigationDisabler.h" > #include "NavigationScheduler.h" >+#include "Node.h" > #include "Page.h" > #include "PageCache.h" > #include "PageTransitionEvent.h" >@@ -1652,7 +1653,7 @@ const ResourceRequest& FrameLoader::initialRequest() const > return activeDocumentLoader()->originalRequest(); > } > >-bool FrameLoader::willLoadMediaElementURL(URL& url) >+bool FrameLoader::willLoadMediaElementURL(URL& url, Node& initiatorNode) > { > #if PLATFORM(IOS) > // MobileStore depends on the iOS 4.0 era client delegate method because webView:resource:willSendRequest:redirectResponse:fromDataSource >@@ -1662,6 +1663,7 @@ bool FrameLoader::willLoadMediaElementURL(URL& url) > #endif > > ResourceRequest request(url); >+ request.setInitiatorNodeIdentifier(InspectorInstrumentation::identifierForNode(initiatorNode)); > > unsigned long identifier; > ResourceError error; >diff --git a/Source/WebCore/loader/FrameLoader.h b/Source/WebCore/loader/FrameLoader.h >index 9ed7a5dd6de..2bf0e0a1dc3 100644 >--- a/Source/WebCore/loader/FrameLoader.h >+++ b/Source/WebCore/loader/FrameLoader.h >@@ -72,6 +72,7 @@ class HistoryController; > class HistoryItem; > class NavigationAction; > class NetworkingContext; >+class Node; > class Page; > class PolicyChecker; > class ResourceError; >@@ -177,7 +178,7 @@ public: > const ResourceRequest& initialRequest() const; > void receivedMainResourceError(const ResourceError&); > >- bool willLoadMediaElementURL(URL&); >+ bool willLoadMediaElementURL(URL&, Node&); > > void handleFallbackContent(); > >diff --git a/Source/WebCore/loader/ImageLoader.cpp b/Source/WebCore/loader/ImageLoader.cpp >index 5c28f826133..ab7ee883dee 100644 >--- a/Source/WebCore/loader/ImageLoader.cpp >+++ b/Source/WebCore/loader/ImageLoader.cpp >@@ -37,6 +37,7 @@ > #include "HTMLNames.h" > #include "HTMLObjectElement.h" > #include "HTMLParserIdioms.h" >+#include "InspectorInstrumentation.h" > #include "Page.h" > #include "RenderImage.h" > #include "RenderSVGImage.h" >@@ -179,7 +180,11 @@ void ImageLoader::updateFromElement() > options.sameOriginDataURLFlag = SameOriginDataURLFlag::Set; > > auto crossOriginAttribute = element().attributeWithoutSynchronization(HTMLNames::crossoriginAttr); >- auto request = createPotentialAccessControlRequest(document.completeURL(sourceURI(attr)), document, crossOriginAttribute, WTFMove(options)); >+ >+ ResourceRequest resourceRequest(document.completeURL(sourceURI(attr))); >+ resourceRequest.setInitiatorNodeIdentifier(InspectorInstrumentation::identifierForNode(m_element)); >+ >+ auto request = createPotentialAccessControlRequest(WTFMove(resourceRequest), document, crossOriginAttribute, WTFMove(options)); > request.setInitiator(element()); > > if (m_loadManually) { >diff --git a/Source/WebCore/loader/MediaResourceLoader.cpp b/Source/WebCore/loader/MediaResourceLoader.cpp >index b119133c8c8..50022317910 100644 >--- a/Source/WebCore/loader/MediaResourceLoader.cpp >+++ b/Source/WebCore/loader/MediaResourceLoader.cpp >@@ -35,6 +35,7 @@ > #include "CrossOriginAccessControl.h" > #include "Document.h" > #include "HTMLMediaElement.h" >+#include "InspectorInstrumentation.h" > #include "SecurityOrigin.h" > #include <wtf/NeverDestroyed.h> > >@@ -69,6 +70,10 @@ RefPtr<PlatformMediaResource> MediaResourceLoader::requestResource(ResourceReque > auto cachingPolicy = options & LoadOption::DisallowCaching ? CachingPolicy::DisallowCaching : CachingPolicy::AllowCaching; > > request.setRequester(ResourceRequest::Requester::Media); >+ >+ if (m_mediaElement) >+ request.setInitiatorNodeIdentifier(InspectorInstrumentation::identifierForNode(*m_mediaElement)); >+ > #if HAVE(AVFOUNDATION_LOADER_DELEGATE) && PLATFORM(MAC) > // FIXME: Workaround for <rdar://problem/26071607>. We are not able to do CORS checking on 304 responses because they are usually missing the headers we need. > if (!m_crossOriginMode.isNull()) >diff --git a/Source/WebCore/loader/TextTrackLoader.cpp b/Source/WebCore/loader/TextTrackLoader.cpp >index a72d0b4336b..61c4a5ed388 100644 >--- a/Source/WebCore/loader/TextTrackLoader.cpp >+++ b/Source/WebCore/loader/TextTrackLoader.cpp >@@ -35,6 +35,8 @@ > #include "CachedTextTrack.h" > #include "CrossOriginAccessControl.h" > #include "Document.h" >+#include "HTMLTrackElement.h" >+#include "InspectorInstrumentation.h" > #include "Logging.h" > #include "SharedBuffer.h" > #include "VTTCue.h" >@@ -142,7 +144,7 @@ void TextTrackLoader::notifyFinished(CachedResource& resource) > cancelLoad(); > } > >-bool TextTrackLoader::load(const URL& url, const String& crossOriginMode, bool isInitiatingElementInUserAgentShadowTree) >+bool TextTrackLoader::load(const URL& url, HTMLTrackElement& element) > { > cancelLoad(); > >@@ -150,9 +152,14 @@ bool TextTrackLoader::load(const URL& url, const String& crossOriginMode, bool i > Document& document = downcast<Document>(*m_scriptExecutionContext); > > ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); >- options.contentSecurityPolicyImposition = isInitiatingElementInUserAgentShadowTree ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck; >+ options.contentSecurityPolicyImposition = element.isInUserAgentShadowTree() ? ContentSecurityPolicyImposition::SkipPolicyCheck : ContentSecurityPolicyImposition::DoPolicyCheck; > >- auto cueRequest = createPotentialAccessControlRequest(document.completeURL(url), document, crossOriginMode, WTFMove(options)); >+ ResourceRequest resourceRequest(document.completeURL(url)); >+ >+ if (auto mediaElement = element.mediaElement()) >+ resourceRequest.setInitiatorNodeIdentifier(InspectorInstrumentation::identifierForNode(*mediaElement)); >+ >+ auto cueRequest = createPotentialAccessControlRequest(WTFMove(resourceRequest), document, element.mediaElementCrossOriginAttribute(), WTFMove(options)); > m_resource = document.cachedResourceLoader().requestTextTrack(WTFMove(cueRequest)).value_or(nullptr); > if (!m_resource) > return false; >diff --git a/Source/WebCore/loader/TextTrackLoader.h b/Source/WebCore/loader/TextTrackLoader.h >index 6001d5c449b..ae0793606bf 100644 >--- a/Source/WebCore/loader/TextTrackLoader.h >+++ b/Source/WebCore/loader/TextTrackLoader.h >@@ -37,6 +37,7 @@ namespace WebCore { > > class CachedTextTrack; > class Document; >+class HTMLTrackElement; > class TextTrackLoader; > class ScriptExecutionContext; > >@@ -56,7 +57,7 @@ public: > TextTrackLoader(TextTrackLoaderClient&, ScriptExecutionContext*); > virtual ~TextTrackLoader(); > >- bool load(const URL&, const String& crossOriginMode, bool isInitiatingElementInUserAgentShadowTree); >+ bool load(const URL&, HTMLTrackElement&); > void cancelLoad(); > void getNewCues(Vector<RefPtr<TextTrackCue>>& outputCues); > void getNewRegions(Vector<RefPtr<VTTRegion>>& outputRegions); >diff --git a/Source/WebCore/loader/cache/CachedResourceLoader.cpp b/Source/WebCore/loader/cache/CachedResourceLoader.cpp >index 9d3d108113c..fdd7c9a9e76 100644 >--- a/Source/WebCore/loader/cache/CachedResourceLoader.cpp >+++ b/Source/WebCore/loader/cache/CachedResourceLoader.cpp >@@ -600,6 +600,7 @@ bool CachedResourceLoader::shouldContinueAfterNotifyingLoadedFromMemoryCache(con > > ResourceRequest newRequest = ResourceRequest(resource.url()); > newRequest.setInitiatorIdentifier(request.resourceRequest().initiatorIdentifier()); >+ newRequest.setInitiatorNodeIdentifier(request.resourceRequest().initiatorNodeIdentifier()); > if (request.resourceRequest().hiddenFromInspector()) > newRequest.setHiddenFromInspector(true); > frame()->loader().loadedResourceFromMemoryCache(resource, newRequest, error); >diff --git a/Source/WebCore/platform/network/ResourceRequestBase.cpp b/Source/WebCore/platform/network/ResourceRequestBase.cpp >index ff5836174ea..74231c0a62b 100644 >--- a/Source/WebCore/platform/network/ResourceRequestBase.cpp >+++ b/Source/WebCore/platform/network/ResourceRequestBase.cpp >@@ -65,6 +65,7 @@ void ResourceRequestBase::setAsIsolatedCopy(const ResourceRequest& other) > setPriority(other.priority()); > setRequester(other.requester()); > setInitiatorIdentifier(other.initiatorIdentifier().isolatedCopy()); >+ setInitiatorNodeIdentifier(other.initiatorNodeIdentifier()); > setCachePartition(other.cachePartition().isolatedCopy()); > > if (!other.isSameSiteUnspecified()) { >diff --git a/Source/WebCore/platform/network/ResourceRequestBase.h b/Source/WebCore/platform/network/ResourceRequestBase.h >index 15d09a5457f..64125d2678c 100644 >--- a/Source/WebCore/platform/network/ResourceRequestBase.h >+++ b/Source/WebCore/platform/network/ResourceRequestBase.h >@@ -172,6 +172,10 @@ public: > String initiatorIdentifier() const { return m_initiatorIdentifier; } > void setInitiatorIdentifier(const String& identifier) { m_initiatorIdentifier = identifier; } > >+ // Additional information for the Inspector to be able to identify the node that initiated this request. >+ int initiatorNodeIdentifier() const { return m_initiatorNodeIdentifier; } >+ void setInitiatorNodeIdentifier(int initiatorNodeIdentifier) { m_initiatorNodeIdentifier = initiatorNodeIdentifier; } >+ > #if USE(SYSTEM_PREVIEW) > WEBCORE_EXPORT bool isSystemPreview() const; > WEBCORE_EXPORT void setSystemPreview(bool); >@@ -232,6 +236,7 @@ protected: > SameSiteDisposition m_sameSiteDisposition { SameSiteDisposition::Unspecified }; > ResourceLoadPriority m_priority { ResourceLoadPriority::Low }; > Requester m_requester { Requester::Unspecified }; >+ int m_initiatorNodeIdentifier; > bool m_allowCookies { false }; > mutable bool m_resourceRequestUpdated { false }; > mutable bool m_platformRequestUpdated { false }; >diff --git a/Source/WebCore/platform/network/cf/ResourceRequestCFNet.cpp b/Source/WebCore/platform/network/cf/ResourceRequestCFNet.cpp >index 986721b626c..cc8f6c6994f 100644 >--- a/Source/WebCore/platform/network/cf/ResourceRequestCFNet.cpp >+++ b/Source/WebCore/platform/network/cf/ResourceRequestCFNet.cpp >@@ -371,6 +371,7 @@ void ResourceRequest::updateFromDelegatePreservingOldProperties(const ResourceRe > bool isHiddenFromInspector = hiddenFromInspector(); > auto oldRequester = requester(); > auto oldInitiatorIdentifier = initiatorIdentifier(); >+ auto oldInitiatorNodeIdentifier = initiatorNodeIdentifier(); > > *this = delegateProvidedRequest; > >@@ -379,6 +380,7 @@ void ResourceRequest::updateFromDelegatePreservingOldProperties(const ResourceRe > setHiddenFromInspector(isHiddenFromInspector); > setRequester(oldRequester); > setInitiatorIdentifier(oldInitiatorIdentifier); >+ setInitiatorNodeIdentifier(oldInitiatorNodeIdentifier); > } > > bool ResourceRequest::httpPipeliningEnabled() >diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog >index 37c3181bd1e..62f0759b037 100644 >--- a/Source/WebInspectorUI/ChangeLog >+++ b/Source/WebInspectorUI/ChangeLog >@@ -1,3 +1,91 @@ >+2018-09-17 Devin Rousso <drousso@apple.com> >+ >+ Web Inspector: group media network entries by the node that triggered the request >+ https://bugs.webkit.org/show_bug.cgi?id=189606 >+ <rdar://problem/44438527> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Introduces a `WI.NavigationItem` for changing whether network entries are grouped by the >+ node that initiated the load (if appliable). When grouped by node, a tree-like layout of the >+ table cells (including expand/collapse) is used for resources that share the same initiator >+ node. The values for the node's cell are based on it's initated resources. >+ >+ * Localizations/en.lproj/localizedStrings.js: >+ * UserInterface/Base/Setting.js: >+ >+ * UserInterface/Controllers/DOMTreeManager.js: >+ (WI.DOMTreeManager): >+ (WI.DOMTreeManager.prototype._mainResourceDidChange): >+ Whenever the frame navigates, re-reqeust the document so that `NetworkAgent` is able to send >+ valid `nodeId` for each request's `initiatorNode`. This means that the document should >+ always be available. >+ >+ * UserInterface/Views/NetworkTableContentView.js: >+ (WI.NetworkTableContentView): >+ (WI.NetworkTableContentView.prototype.get filterNavigationItems): >+ (WI.NetworkTableContentView.prototype.closed): >+ (WI.NetworkTableContentView.prototype.reset): >+ (WI.NetworkTableContentView.prototype.tableSortChanged): >+ (WI.NetworkTableContentView.prototype.tableSelectedRowChanged): >+ (WI.NetworkTableContentView.prototype.tablePopulateCell): >+ (WI.NetworkTableContentView.prototype._populateNameCell.createIconElement): Added. >+ (WI.NetworkTableContentView.prototype._populateNameCell): >+ (WI.NetworkTableContentView.prototype._populateDomainCell.createIconAndText): Added. >+ (WI.NetworkTableContentView.prototype._populateDomainCell): >+ (WI.NetworkTableContentView.prototype._populateInitiatorCell): >+ (WI.NetworkTableContentView.prototype._populateTransferSizeCell): >+ (WI.NetworkTableContentView.prototype._generateSortComparator): >+ (WI.NetworkTableContentView.prototype._processPendingEntries): >+ (WI.NetworkTableContentView.prototype._updateEntryForResource.updateEntry): Added. >+ (WI.NetworkTableContentView.prototype._updateEntryForResource): >+ (WI.NetworkTableContentView.prototype._insertResourceAndReloadTable): >+ (WI.NetworkTableContentView.prototype._entryForNode): Added. >+ (WI.NetworkTableContentView.prototype._tryLinkResourceToNode): Added. >+ (WI.NetworkTableContentView.prototype._uniqueValuesForNodeEntry): Added. >+ (WI.NetworkTableContentView.prototype._updateFilteredEntries): >+ (WI.NetworkTableContentView.prototype._handleGroupByNodeCheckedDidChange): Added. >+ * UserInterface/Views/NetworkTableContentView.css: >+ (.network-table .cell.node.name .icon): Added. >+ (.network-table .cell.node.name .disclosure): Added. >+ (body[dir=rtl] .network-table .cell.node.name .disclosure): Added. >+ (.network-table:focus li.selected .cell.node.name .disclosure): Added. >+ (.network-table .cell.node.name .disclosure.expanded): Added. >+ (.network-table:focus li.selected .cell.node.name .disclosure.expanded): Added. >+ (.network-table .cell.grouped-by-node.name): Added. >+ (body[dir=ltr] .network-table .cell.grouped-by-node.name): Added. >+ (body[dir=rtl] .network-table .cell.grouped-by-node.name): Added. >+ (.network-table li:not(.selected) .cell:matches(.cache-type, .multiple)): Added. >+ (.network-table li.selected .cell.domain > .lock): Added. >+ (.network-table .cache-type): Deleted. >+ When two resources are added that share the same `initiatorNode`, insert a node entry into >+ the `WI.Table` before the first resource entry for that node (based on the current sort). >+ This node entry is added after the resource entries are filtered, so they won't appear in >+ the default entries list. >+ >+ * UserInterface/Models/Resource.js: >+ (WI.Resource): >+ * UserInterface/Models/SourceMapResource.js: >+ (WI.SourceMapResource): >+ * UserInterface/Models/WebSocketResource.js: >+ (WI.WebSocketResource): >+ * UserInterface/Controllers/FrameResourceManager.js: >+ (WI.FrameResourceManager.prototype.frameDidNavigate): >+ (WI.FrameResourceManager.prototype.resourceRequestWillBeSent): >+ (WI.FrameResourceManager.prototype.webSocketWillSendHandshakeRequest): >+ (WI.FrameResourceManager.prototype.resourceRequestWasServedFromMemoryCache): >+ (WI.FrameResourceManager.prototype.resourceRequestDidReceiveResponse): >+ (WI.FrameResourceManager.prototype._addNewResourceToFrameOrTarget.createResourceFromArguments): Added. >+ (WI.FrameResourceManager.prototype._addNewResourceToFrameOrTarget): >+ (WI.FrameResourceManager.prototype._initiatorNodeFromPayload): >+ (WI.FrameResourceManager.prototype._createFrame): >+ (WI.FrameResourceManager.prototype._createResource): >+ Use an object to pass all optional parameters when creating `WI.Resource`. >+ >+ * UserInterface/Images/Range.svg: Added. >+ * UserInterface/Views/ResourceIcons.css: >+ (.resource-icon.resource-type-range .icon): Added. >+ > 2018-09-15 Devin Rousso <drousso@apple.com> > > Web Inspector: REGRESSION: breakpoint context menu appears twice in DOM tree >diff --git a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >index 22c0d1a5820..6431de7a965 100644 >--- a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >+++ b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js >@@ -156,6 +156,7 @@ localizedStrings["Breakpoints"] = "Breakpoints"; > localizedStrings["Breakpoints disabled"] = "Breakpoints disabled"; > localizedStrings["Bubbling"] = "Bubbling"; > localizedStrings["Busy"] = "Busy"; >+localizedStrings["Byte Range %s"] = "Byte Range %s"; > localizedStrings["Bytes Received"] = "Bytes Received"; > localizedStrings["Bytes Sent"] = "Bytes Sent"; > localizedStrings["CSP Hash"] = "CSP Hash"; >diff --git a/Source/WebInspectorUI/UserInterface/Base/Setting.js b/Source/WebInspectorUI/UserInterface/Base/Setting.js >index a0a579e421b..dff72d223cf 100644 >--- a/Source/WebInspectorUI/UserInterface/Base/Setting.js >+++ b/Source/WebInspectorUI/UserInterface/Base/Setting.js >@@ -117,6 +117,7 @@ WI.settings = { > showCanvasPath: new WI.Setting("show-canvas-path", false), > selectedNetworkDetailContentViewIdentifier: new WI.Setting("network-detail-content-view-identifier", "preview"), > showRulers: new WI.Setting("show-rulers", false), >+ groupByNode: new WI.Setting("group-by-node", false), > > // Experimental > experimentalEnableLayersTab: new WI.Setting("experimental-enable-layers-tab", false), >diff --git a/Source/WebInspectorUI/UserInterface/Controllers/DOMTreeManager.js b/Source/WebInspectorUI/UserInterface/Controllers/DOMTreeManager.js >index fbfda93bc79..72b484cf5ca 100644 >--- a/Source/WebInspectorUI/UserInterface/Controllers/DOMTreeManager.js >+++ b/Source/WebInspectorUI/UserInterface/Controllers/DOMTreeManager.js >@@ -46,6 +46,8 @@ WI.DOMTreeManager = class DOMTreeManager extends WI.Object > this._breakpointsForEventListeners = new Map; > > WI.Frame.addEventListener(WI.Frame.Event.MainResourceDidChange, this._mainResourceDidChange, this); >+ >+ this.ensureDocument(); > } > > // Public >@@ -628,8 +630,12 @@ WI.DOMTreeManager = class DOMTreeManager extends WI.Object > > _mainResourceDidChange(event) > { >- if (event.target.isMainFrame()) >- this._restoreSelectedNodeIsAllowed = true; >+ if (!event.target.isMainFrame()) >+ return; >+ >+ this._restoreSelectedNodeIsAllowed = true; >+ >+ this.ensureDocument(); > } > }; > >diff --git a/Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js b/Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js >index 75224c8c986..51671413dbc 100644 >--- a/Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js >+++ b/Source/WebInspectorUI/UserInterface/Controllers/FrameResourceManager.js >@@ -88,7 +88,14 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object > // If the frame wasn't known before now, then the main resource was loaded instantly (about:blank, etc.) > // Make a new resource (which will make the frame). Mark will mark it as loaded at the end too since we > // don't expect any more events about the load finishing for these frames. >- var frameResource = this._addNewResourceToFrameOrTarget(null, framePayload.id, framePayload.loaderId, framePayload.url, null, null, null, null, null, null, framePayload.name, framePayload.securityOrigin); >+ const requestIdentifier = null; >+ const type = null; >+ const requestMethod = null; >+ const requestHeaders = null; >+ const requestData = null; >+ const elapsedTime = null; >+ const walltime = null; >+ var frameResource = this._addNewResourceToFrameOrTarget(requestIdentifier, framePayload.id, framePayload.loaderId, framePayload.url, type, requestMethod, requestHeaders, requestData, elapsedTime, walltime, framePayload.name, framePayload.securityOrigin); > frame = frameResource.parentFrame; > frameWasLoadedInstantly = true; > >@@ -101,12 +108,16 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object > // There was a provisional load in progress, commit it. > frame.commitProvisionalLoad(framePayload.securityOrigin); > } else { >+ let mainResource = null; > if (frame.mainResource.url !== framePayload.url || frame.loaderIdentifier !== framePayload.loaderId) { > // Navigations like back/forward do not have provisional loads, so create a new main resource here. >- var mainResource = new WI.Resource(framePayload.url, framePayload.mimeType, null, framePayload.loaderId); >+ mainResource = new WI.Resource(framePayload.url, { >+ mimeType: framePayload.mimeType, >+ loaderIdentifier: framePayload.loaderId, >+ }); > } else { > // The main resource is already correct, so reuse it. >- var mainResource = frame.mainResource; >+ mainResource = frame.mainResource; > } > > frame.initialize(framePayload.name, framePayload.securityOrigin, framePayload.loaderId, mainResource); >@@ -192,9 +203,12 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object > } > > var initiatorSourceCodeLocation = this._initiatorSourceCodeLocationFromPayload(initiator); >+ let initiatorNode = this._initiatorNodeFromPayload(initiator); > > // This is a new request, make a new resource and add it to the right frame. >- resource = this._addNewResourceToFrameOrTarget(requestIdentifier, frameIdentifier, loaderIdentifier, request.url, type, request.method, request.headers, request.postData, elapsedTime, walltime, null, null, initiatorSourceCodeLocation, originalRequestWillBeSentTimestamp, targetId); >+ const frameName = null; >+ const frameSecurityOrigin = null; >+ resource = this._addNewResourceToFrameOrTarget(requestIdentifier, frameIdentifier, loaderIdentifier, request.url, type, request.method, request.headers, request.postData, elapsedTime, walltime, frameName, frameSecurityOrigin, initiatorSourceCodeLocation, initiatorNode, originalRequestWillBeSentTimestamp, targetId); > > // Associate the resource with the requestIdentifier so it can be found in future loading events. > this._resourceRequestIdentifierMap.set(requestIdentifier, resource); >@@ -205,9 +219,9 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object > this._webSocketIdentifierToURL.set(requestId, url); > } > >- webSocketWillSendHandshakeRequest(requestId, timestamp, walltime, request) >+ webSocketWillSendHandshakeRequest(requestIdentifier, timestamp, walltime, request) > { >- let url = this._webSocketIdentifierToURL.get(requestId); >+ let url = this._webSocketIdentifierToURL.get(requestIdentifier); > console.assert(url); > if (!url) > return; >@@ -221,18 +235,21 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object > // FIXME: <webkit.org/b/168475> Web Inspector: Correctly display iframe's and worker's WebSockets > let frameIdentifier = WI.frameResourceManager.mainFrame.id; > let loaderIdentifier = WI.frameResourceManager.mainFrame.id; >- let targetId; > > let frame = this.frameForIdentifier(frameIdentifier); >- let requestData = null; >- let elapsedTime = WI.timelineManager.computeElapsedTime(timestamp); >- let initiatorSourceCodeLocation = null; > >- let resource = new WI.WebSocketResource(url, loaderIdentifier, targetId, requestId, request.headers, requestData, timestamp, walltime, elapsedTime, initiatorSourceCodeLocation); >+ let resource = new WI.WebSocketResource(url, { >+ loaderIdentifier, >+ requestIdentifier, >+ requestHeaders: request.headers, >+ timestamp, >+ walltime, >+ elapsedTime: WI.timelineManager.computeElapsedTime(timestamp), >+ }); > > frame.addResource(resource); > >- this._resourceRequestIdentifierMap.set(requestId, resource); >+ this._resourceRequestIdentifierMap.set(requestIdentifier, resource); > } > > webSocketHandshakeResponseReceived(requestId, timestamp, response) >@@ -325,12 +342,19 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object > > console.assert(!this._resourceRequestIdentifierMap.has(requestIdentifier)); > >+ const requestMethod = "GET"; >+ const requestHeaders = null; >+ const requestData = null; > let elapsedTime = WI.timelineManager.computeElapsedTime(timestamp); >+ const walltime = null; >+ const frameName = null; >+ const frameSecurityOrigin = null; > let initiatorSourceCodeLocation = this._initiatorSourceCodeLocationFromPayload(initiator); >+ let initiatorNode = this._initiatorNodeFromPayload(initiator); >+ let resource = this._addNewResourceToFrameOrTarget(requestIdentifier, frameIdentifier, loaderIdentifier, cachedResourcePayload.url, cachedResourcePayload.type, requestMethod, requestHeaders, requestData, elapsedTime, walltime, frameName, frameSecurityOrigin, initiatorSourceCodeLocation, initiatorNode); >+ > let response = cachedResourcePayload.response; > const responseSource = NetworkAgent.ResponseSource.MemoryCache; >- >- let resource = this._addNewResourceToFrameOrTarget(requestIdentifier, frameIdentifier, loaderIdentifier, cachedResourcePayload.url, cachedResourcePayload.type, "GET", null, null, elapsedTime, null, null, null, initiatorSourceCodeLocation); > resource.updateForResponse(cachedResourcePayload.url, response.mimeType, cachedResourcePayload.type, response.headers, response.status, response.statusText, elapsedTime, response.timing, responseSource); > resource.increaseSize(cachedResourcePayload.bodySize, elapsedTime); > resource.increaseTransferSize(cachedResourcePayload.bodySize); >@@ -377,7 +401,9 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object > // If we haven't found an existing Resource by now, then it is a resource that was loading when the inspector > // opened and we just missed the resourceRequestWillBeSent for it. So make a new resource and add it. > if (!resource) { >- resource = this._addNewResourceToFrameOrTarget(requestIdentifier, frameIdentifier, loaderIdentifier, response.url, type, null, response.requestHeaders, null, elapsedTime, null, null, null, null); >+ const requestMethod = null; >+ const requestData = null; >+ resource = this._addNewResourceToFrameOrTarget(requestIdentifier, frameIdentifier, loaderIdentifier, response.url, type, requestMethod, response.requestHeaders, requestData, elapsedTime); > > // Associate the resource with the requestIdentifier so it can be found in future loading events. > this._resourceRequestIdentifierMap.set(requestIdentifier, resource); >@@ -501,17 +527,34 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object > > // Private > >- _addNewResourceToFrameOrTarget(requestIdentifier, frameIdentifier, loaderIdentifier, url, type, requestMethod, requestHeaders, requestData, elapsedTime, walltime, frameName, frameSecurityOrigin, initiatorSourceCodeLocation, originalRequestWillBeSentTimestamp, targetId) >+ _addNewResourceToFrameOrTarget(requestIdentifier, frameIdentifier, loaderIdentifier, url, type, requestMethod, requestHeaders, requestData, elapsedTime, walltime, frameName, frameSecurityOrigin, initiatorSourceCodeLocation, initiatorNode, originalRequestWillBeSentTimestamp, targetIdentifier) > { > console.assert(!this._waitingForMainFrameResourceTreePayload); > >+ function createResourceFromArguments() { >+ return new WI.Resource(url, { >+ type, >+ loaderIdentifier, >+ targetIdentifier, >+ requestIdentifier, >+ requestMethod, >+ requestHeaders, >+ requestData, >+ requestSentTimestamp: elapsedTime, >+ requestSentWalltime: walltime, >+ initiatorSourceCodeLocation, >+ initiatorNode, >+ originalRequestWillBeSentTimestamp, >+ }); >+ } >+ > let resource = null; > >- if (!frameIdentifier && targetId) { >+ if (!frameIdentifier && targetIdentifier) { > // This is a new resource for a ServiceWorker target. > console.assert(WI.sharedApp.debuggableType === WI.DebuggableType.ServiceWorker); >- console.assert(targetId === WI.mainTarget.identifier); >- resource = new WI.Resource(url, null, type, loaderIdentifier, targetId, requestIdentifier, requestMethod, requestHeaders, requestData, elapsedTime, walltime, initiatorSourceCodeLocation, originalRequestWillBeSentTimestamp); >+ console.assert(targetIdentifier === WI.mainTarget.identifier); >+ resource = createResourceFromArguments(); > resource.target.addResource(resource); > return resource; > } >@@ -524,19 +567,19 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object > else if (type === "Document" && frame.provisionalMainResource && frame.provisionalMainResource.url === url && frame.provisionalLoaderIdentifier === loaderIdentifier) > resource = frame.provisionalMainResource; > else { >- resource = new WI.Resource(url, null, type, loaderIdentifier, targetId, requestIdentifier, requestMethod, requestHeaders, requestData, elapsedTime, walltime, initiatorSourceCodeLocation, originalRequestWillBeSentTimestamp); >+ resource = createResourceFromArguments(); > if (resource.target === WI.pageTarget) > this._addResourceToFrame(frame, resource); > else if (resource.target) > resource.target.addResource(resource); > else >- this._addOrphanedResource(resource, targetId); >+ this._addOrphanedResource(resource, targetIdentifier); > } > } else { > // This is a new request for a new frame, which is always the main resource. > console.assert(WI.sharedApp.debuggableType !== WI.DebuggableType.ServiceWorker); >- console.assert(!targetId); >- resource = new WI.Resource(url, null, type, loaderIdentifier, targetId, requestIdentifier, requestMethod, requestHeaders, requestData, elapsedTime, walltime, initiatorSourceCodeLocation, originalRequestWillBeSentTimestamp); >+ console.assert(!targetIdentifier); >+ resource = createResourceFromArguments(); > frame = new WI.Frame(frameIdentifier, frameName, frameSecurityOrigin, loaderIdentifier, resource); > this._frameIdentifierMap.set(frame.id, frame); > >@@ -629,6 +672,11 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object > return sourceCode.createSourceCodeLocation(lineNumber, columnNumber); > } > >+ _initiatorNodeFromPayload(initiatorPayload) >+ { >+ return WI.domTreeManager.nodeForId(initiatorPayload.nodeId); >+ } >+ > _processServiceWorkerConfiguration(error, initializationPayload) > { > console.assert(this._waitingForMainFrameResourceTreePayload); >@@ -686,7 +734,10 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object > { > // If payload.url is missing or empty then this page is likely the special empty page. In that case > // we will just say it is "about:blank" so we have a URL, which is required for resources. >- var mainResource = new WI.Resource(payload.url || "about:blank", payload.mimeType, null, payload.loaderId); >+ let mainResource = new WI.Resource(payload.url || "about:blank", { >+ mimeType: payload.mimeType, >+ loaderIdentifier: payload.loaderId, >+ }); > var frame = new WI.Frame(payload.id, payload.name, payload.securityOrigin, payload.loaderId, mainResource); > > this._frameIdentifierMap.set(frame.id, frame); >@@ -698,7 +749,12 @@ WI.FrameResourceManager = class FrameResourceManager extends WI.Object > > _createResource(payload, framePayload) > { >- var resource = new WI.Resource(payload.url, payload.mimeType, payload.type, framePayload.loaderId, payload.targetId); >+ let resource = new WI.Resource(payload.url, { >+ mimeType: payload.mimeType, >+ type: payload.type, >+ loaderIdentifier: framePayload.loaderId, >+ targetIdentifier: payload.targetId, >+ }); > > if (payload.sourceMapURL) > WI.sourceMapManager.downloadSourceMap(payload.sourceMapURL, resource.url, resource); >diff --git a/Source/WebInspectorUI/UserInterface/Images/Range.svg b/Source/WebInspectorUI/UserInterface/Images/Range.svg >new file mode 100644 >index 00000000000..605dca3c7bf >--- /dev/null >+++ b/Source/WebInspectorUI/UserInterface/Images/Range.svg >@@ -0,0 +1,8 @@ >+<?xml version="1.0" encoding="utf-8"?> >+<!-- Copyright © 2013 Apple Inc. All rights reserved. --> >+<svg xmlns="http://www.w3.org/2000/svg" id="root" version="1.1" viewBox="0 0 16 16"> >+ <path fill="rgb(148, 183, 219)" d="M 13 1 L 3 1 C 1.898438 1 1 1.898438 1 3 L 1 13 C 1 14.101562 1.898438 15 3 15 L 13 15 C 14.101562 15 15 14.101562 15 13 L 15 3 C 15 1.898438 14.101562 1 13 1 Z"/> >+ <path fill="rgb(106, 136, 170)" d="M 13 1 L 3 1 C 1.898438 1 1 1.898438 1 3 L 1 13 C 1 14.101562 1.898438 15 3 15 L 13 15 C 14.101562 15 15 14.101562 15 13 L 15 3 C 15 1.898438 14.101562 1 13 1 M 13 2 C 13.550781 2 14 2.449219 14 3 L 14 13 C 14 13.550781 13.550781 14 13 14 L 3 14 C 2.449219 14 2 13.550781 2 13 L 2 3 C 2 2.449219 2.449219 2 3 2 L 13 2"/> >+ <path fill="white" d="M 7 7.632812 L 7.027344 7.632812 C 8.28125 7.632812 9.0625 7.144531 9.0625 6.167969 C 9.0625 5.453125 8.347656 5.097656 7.230469 5.097656 L 7 5.097656 Z M 5 12 L 5 4 L 8.109375 4 C 9.800781 4 11 4.675781 11 6 C 11 6.496094 10.855469 6.941406 10.570312 7.347656 C 10.285156 7.753906 9.53125 8.050781 9.03125 8.265625 L 11.75 12 L 9.402344 12 L 7.34375 8.730469 L 7 8.730469 L 7 12 Z"/> >+ <path fill="rgb(113, 146, 184)" d="M 8.109375 3 L 4 3 L 4 13 L 8 13 L 8 11.644531 L 8.558594 12.53125 L 8.851562 13 L 13.714844 13 L 12.558594 11.410156 L 10.550781 8.652344 C 10.875 8.460938 11.175781 8.226562 11.386719 7.925781 C 11.792969 7.351562 12 6.703125 12 6 C 12 4.179688 10.472656 3 8.109375 3 M 7 7.632812 L 7.027344 7.632812 C 8.28125 7.632812 9.0625 7.144531 9.0625 6.167969 C 9.0625 5.453125 8.347656 5.097656 7.230469 5.097656 L 7 5.097656 L 7 7.632812 M 8.109375 4 C 9.796875 4 11 4.679688 11 6 C 11 6.492188 10.855469 6.941406 10.570312 7.347656 C 10.285156 7.753906 9.535156 8.050781 9.03125 8.265625 L 11.75 12 L 9.40625 12 L 7.34375 8.730469 L 7 8.730469 L 7 12 L 5 12 L 5 4 L 8.109375 4"/> >+</svg> >diff --git a/Source/WebInspectorUI/UserInterface/Models/Resource.js b/Source/WebInspectorUI/UserInterface/Models/Resource.js >index 393053b44c0..6b22f340b73 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/Resource.js >+++ b/Source/WebInspectorUI/UserInterface/Models/Resource.js >@@ -26,7 +26,7 @@ > > WI.Resource = class Resource extends WI.SourceCode > { >- constructor(url, mimeType, type, loaderIdentifier, targetId, requestIdentifier, requestMethod, requestHeaders, requestData, requestSentTimestamp, requestSentWalltime, initiatorSourceCodeLocation, originalRequestWillBeSentTimestamp) >+ constructor(url, {mimeType, type, loaderIdentifier, targetIdentifier, requestIdentifier, requestMethod, requestHeaders, requestData, requestSentTimestamp, requestSentWalltime, initiatorSourceCodeLocation, initiatorNode, originalRequestWillBeSentTimestamp} = {}) > { > super(); > >@@ -53,6 +53,7 @@ WI.Resource = class Resource extends WI.SourceCode > this._parentFrame = null; > this._initiatorSourceCodeLocation = initiatorSourceCodeLocation || null; > this._initiatedResources = []; >+ this._initiatorNode = initiatorNode || null; > this._originalRequestWillBeSentTimestamp = originalRequestWillBeSentTimestamp || null; > this._requestSentTimestamp = requestSentTimestamp || NaN; > this._requestSentWalltime = requestSentWalltime || NaN; >@@ -74,7 +75,7 @@ WI.Resource = class Resource extends WI.SourceCode > this._priority = WI.Resource.NetworkPriority.Unknown; > this._remoteAddress = null; > this._connectionIdentifier = null; >- this._target = targetId ? WI.targetManager.targetForIdentifier(targetId) : WI.mainTarget; >+ this._target = targetIdentifier ? WI.targetManager.targetForIdentifier(targetIdentifier) : WI.mainTarget; > > // Exact sizes if loaded over the network or cache. > this._requestHeadersTransferSize = NaN; >@@ -286,6 +287,10 @@ WI.Resource = class Resource extends WI.SourceCode > get requestIdentifier() { return this._requestIdentifier; } > get requestMethod() { return this._requestMethod; } > get requestData() { return this._requestData; } >+ get initiatorSourceCodeLocation() { return this._initiatorSourceCodeLocation; } >+ get initiatedResources() { return this._initiatedResources; } >+ get initiatorNode() { return this._initiatorNode; } >+ get originalRequestWillBeSentTimestamp() { return this._originalRequestWillBeSentTimestamp; } > get statusCode() { return this._statusCode; } > get statusText() { return this._statusText; } > get responseSource() { return this._responseSource; } >@@ -319,21 +324,6 @@ WI.Resource = class Resource extends WI.SourceCode > return WI.truncateURL(this._url, isMultiLine, dataURIMaxSize); > } > >- get initiatorSourceCodeLocation() >- { >- return this._initiatorSourceCodeLocation; >- } >- >- get initiatedResources() >- { >- return this._initiatedResources; >- } >- >- get originalRequestWillBeSentTimestamp() >- { >- return this._originalRequestWillBeSentTimestamp; >- } >- > get mimeType() > { > return this._mimeType; >diff --git a/Source/WebInspectorUI/UserInterface/Models/SourceMapResource.js b/Source/WebInspectorUI/UserInterface/Models/SourceMapResource.js >index 110597b1138..35e30698ef7 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/SourceMapResource.js >+++ b/Source/WebInspectorUI/UserInterface/Models/SourceMapResource.js >@@ -27,7 +27,7 @@ WI.SourceMapResource = class SourceMapResource extends WI.Resource > { > constructor(url, sourceMap) > { >- super(url, null); >+ super(url); > > console.assert(url); > console.assert(sourceMap); >diff --git a/Source/WebInspectorUI/UserInterface/Models/WebSocketResource.js b/Source/WebInspectorUI/UserInterface/Models/WebSocketResource.js >index c498dcde0df..f009298e9b5 100644 >--- a/Source/WebInspectorUI/UserInterface/Models/WebSocketResource.js >+++ b/Source/WebInspectorUI/UserInterface/Models/WebSocketResource.js >@@ -25,12 +25,19 @@ > > WI.WebSocketResource = class WebSocketResource extends WI.Resource > { >- constructor(url, loaderIdentifier, targetId, requestIdentifier, requestHeaders, requestData, timestamp, walltime, requestSentTimestamp, initiatorSourceCodeLocation) >+ constructor(url, {loaderIdentifier, targetIdentifier, requestIdentifier, requestHeaders, requestData, timestamp, walltime, requestSentTimestamp, initiatorSourceCodeLocation} = {}) > { >- const type = WI.Resource.Type.WebSocket; >- const mimeType = null; >- const requestMethod = "GET"; >- super(url, mimeType, type, loaderIdentifier, targetId, requestIdentifier, requestMethod, requestHeaders, requestData, requestSentTimestamp, initiatorSourceCodeLocation); >+ super(url, { >+ type: WI.Resource.Type.WebSocket, >+ loaderIdentifier, >+ targetIdentifier, >+ requestIdentifier, >+ requestMethod: "GET", >+ requestHeaders, >+ requestData, >+ requestSentTimestamp, >+ initiatorSourceCodeLocation, >+ }); > > this._timestamp = timestamp; > this._walltime = walltime; >diff --git a/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css b/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css >index d1314984766..9fe337f256e 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css >+++ b/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css >@@ -40,7 +40,48 @@ > cursor: pointer; > } > >-.network-table .cache-type { >+.network-table .cell.node.name .icon { >+ content: url(../Images/DOMElement.svg); >+} >+ >+.network-table .cell.node.name .disclosure { >+ width: 13px; >+ height: 13px; >+ vertical-align: -2px; >+ content: url(../Images/DisclosureTriangles.svg#closed-normal); >+ background-size: 13px 13px; >+ background-repeat: no-repeat; >+} >+ >+body[dir=rtl] .network-table .cell.node.name .disclosure { >+ transform: scaleX(-1); >+} >+ >+.network-table:focus li.selected .cell.node.name .disclosure { >+ content: url(../Images/DisclosureTriangles.svg#closed-selected); >+} >+ >+.network-table .cell.node.name .disclosure.expanded { >+ content: url(../Images/DisclosureTriangles.svg#open-normal); >+} >+ >+.network-table:focus li.selected .cell.node.name .disclosure.expanded { >+ content: url(../Images/DisclosureTriangles.svg#open-selected); >+} >+ >+.network-table .cell.grouped-by-node.name { >+ --item-padding-start: 19px; >+} >+ >+body[dir=ltr] .network-table .cell.grouped-by-node.name { >+ padding-left: var(--item-padding-start); >+} >+ >+body[dir=rtl] .network-table .cell.grouped-by-node.name { >+ padding-right: var(--item-padding-start); >+} >+ >+.network-table li:not(.selected) .cell:matches(.cache-type, .multiple) { > color: var(--text-color-gray-medium); > } > >@@ -55,6 +96,10 @@ > -webkit-margin-end: 5px; > } > >+.network-table li.selected .cell.domain > .lock { >+ filter: invert(); >+} >+ > body[dir=ltr] .network-table .cell.name > .status { > float: right; > margin-left: 4px; >diff --git a/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js b/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js >index 070a5be94e0..675181d14a7 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js >+++ b/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js >@@ -44,6 +44,8 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > this._resourceDetailView = null; > this._resourceDetailViewMap = new Map; > >+ this._nodeEntries = new Map; >+ > this._waterfallStartTime = NaN; > this._waterfallEndTime = NaN; > this._waterfallTimelineRuler = null; >@@ -83,6 +85,9 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > this._typeFilterScopeBar = new WI.ScopeBar("network-type-filter-scope-bar", typeFilterScopeBarItems, typeFilterScopeBarItems[0]); > this._typeFilterScopeBar.addEventListener(WI.ScopeBar.Event.SelectionChanged, this._typeFilterScopeBarSelectionChanged, this); > >+ this._groupByNodeNavigationItem = new WI.CheckboxNavigationItem("group-by-node", WI.UIString("Group by Node"), WI.settings.groupByNode.value); >+ this._groupByNodeNavigationItem.addEventListener(WI.CheckboxNavigationItem.Event.CheckedDidChange, this._handleGroupByNodeCheckedDidChange, this); >+ > this._urlFilterSearchText = null; > this._urlFilterSearchRegex = null; > this._urlFilterIsActive = false; >@@ -201,7 +206,7 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > > get filterNavigationItems() > { >- return [this._urlFilterNavigationItem, this._typeFilterScopeBar]; >+ return [this._urlFilterNavigationItem, this._typeFilterScopeBar, this._groupByNodeNavigationItem]; > } > > get supportsSave() >@@ -241,6 +246,8 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > detailView.dispose(); > this._resourceDetailViewMap.clear(); > >+ this._nodeEntries.clear(); >+ > this._hidePopover(); > this._hideResourceDetailView(); > >@@ -264,6 +271,8 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > detailView.dispose(); > this._resourceDetailViewMap.clear(); > >+ this._nodeEntries.clear(); >+ > this._waterfallStartTime = NaN; > this._waterfallEndTime = NaN; > this._updateWaterfallTimelineRuler(); >@@ -320,7 +329,11 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > > this._hideResourceDetailView(); > >- this._entries = this._entries.sort(this._entriesSortComparator); >+ this._entries.sort(this._entriesSortComparator); >+ >+ for (let nodeEntry of this._nodeEntries.values()) >+ nodeEntry.initiatedResourceEntries.sort(this._entriesSortComparator); >+ > this._updateFilteredEntries(); > this._table.reloadData(); > } >@@ -360,14 +373,34 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > return; > > this._selectedResource = entry.resource; >- this._showResourceDetailView(this._selectedResource); >+ if (this._selectedResource) >+ this._showResourceDetailView(this._selectedResource); >+ else >+ this._hideResourceDetailView(); > } > > tablePopulateCell(table, cell, column, rowIndex) > { > let entry = this._filteredEntries[rowIndex]; > >- cell.classList.toggle("error", entry.resource.hadLoadingError()); >+ if (entry.resource) >+ cell.classList.toggle("error", entry.resource.hadLoadingError()); >+ >+ let setTextContent = (accessor) => { >+ let uniqueValues = this._uniqueValuesForNodeEntry(entry, accessor); >+ if (uniqueValues) { >+ if (uniqueValues.size > 1) { >+ cell.classList.add("multiple"); >+ cell.textContent = WI.UIString("(multiple)"); >+ return; >+ } >+ >+ cell.textContent = uniqueValues.values().next().value || emDash; >+ return; >+ } >+ >+ cell.textContent = accessor(entry) || emDash; >+ }; > > switch (column.identifier) { > case "name": >@@ -377,44 +410,52 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > this._populateDomainCell(cell, entry); > break; > case "type": >- cell.textContent = entry.displayType || emDash; >+ setTextContent((resourceEntry) => resourceEntry.displayType); > break; > case "mimeType": >- cell.textContent = entry.mimeType || emDash; >+ setTextContent((resourceEntry) => resourceEntry.mimeType); > break; > case "method": >- cell.textContent = entry.method || emDash; >+ setTextContent((resourceEntry) => resourceEntry.method); > break; > case "scheme": >- cell.textContent = entry.scheme || emDash; >+ setTextContent((resourceEntry) => resourceEntry.scheme); > break; > case "status": >- cell.textContent = entry.status || emDash; >+ setTextContent((resourceEntry) => resourceEntry.status); > break; > case "protocol": >- cell.textContent = entry.protocol || emDash; >+ setTextContent((resourceEntry) => resourceEntry.protocol); > break; > case "initiator": > this._populateInitiatorCell(cell, entry); > break; > case "priority": >- cell.textContent = WI.Resource.displayNameForPriority(entry.priority) || emDash; >+ setTextContent((resourceEntry) => WI.Resource.displayNameForPriority(resourceEntry.priority)); > break; > case "remoteAddress": >- cell.textContent = entry.remoteAddress || emDash; >+ setTextContent((resourceEntry) => resourceEntry.remoteAddress); > break; > case "connectionIdentifier": >- cell.textContent = entry.connectionIdentifier || emDash; >+ setTextContent((resourceEntry) => resourceEntry.connectionIdentifier); > break; > case "resourceSize": >- cell.textContent = isNaN(entry.resourceSize) ? emDash : Number.bytesToString(entry.resourceSize); >+ var resourceSize = entry.resourceSize; >+ var resourceEntries = entry.initiatedResourceEntries; >+ if (resourceEntries) >+ resourceSize = resourceEntries.reduce((accumulator, current) => accumulator + (current.transferSize || 0), 0); >+ cell.textContent = isNaN(resourceSize) ? emDash : Number.bytesToString(resourceSize); > break; > case "transferSize": > this._populateTransferSizeCell(cell, entry); > break; > case "time": > // FIXME: <https://webkit.org/b/176748> Web Inspector: Frontend sometimes receives resources with negative duration (responseEnd - requestStart) >- cell.textContent = isNaN(entry.time) ? emDash : Number.secondsToString(Math.max(entry.time, 0)); >+ var time = entry.time; >+ var resourceEntries = entry.initiatedResourceEntries; >+ if (resourceEntries) >+ time = resourceEntries.reduce((accumulator, current) => accumulator + (current.time || 0), 0); >+ cell.textContent = isNaN(time) ? emDash : Number.secondsToString(Math.max(time, 0)); > break; > case "waterfall": > this._populateWaterfallGraph(cell, entry); >@@ -430,6 +471,30 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > { > console.assert(!cell.firstChild, "We expect the cell to be empty.", cell, cell.firstChild); > >+ function createIconElement() { >+ let iconElement = cell.appendChild(document.createElement("img")); >+ iconElement.className = "icon"; >+ } >+ >+ let node = entry.node; >+ if (node) { >+ let disclosureElement = cell.appendChild(document.createElement("img")); >+ disclosureElement.classList.add("disclosure"); >+ disclosureElement.classList.toggle("expanded", !!entry.expanded); >+ disclosureElement.addEventListener("click", (event) => { >+ entry.expanded = !entry.expanded; >+ >+ this._updateFilteredEntries(); >+ this._table.reloadData(); >+ }); >+ >+ createIconElement(); >+ >+ cell.classList.add("node"); >+ cell.appendChild(WI.linkifyNodeReference(node)); >+ return; >+ } >+ > let resource = entry.resource; > if (resource.isLoading()) { > let statusElement = cell.appendChild(document.createElement("div")); >@@ -438,36 +503,75 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > statusElement.appendChild(spinner.element); > } > >- let iconElement = cell.appendChild(document.createElement("img")); >- iconElement.className = "icon"; >- cell.classList.add(WI.ResourceTreeElement.ResourceIconStyleClassName, entry.resource.type); >+ createIconElement(); >+ >+ cell.classList.add(WI.ResourceTreeElement.ResourceIconStyleClassName); > > let nameElement = cell.appendChild(document.createElement("span")); >- nameElement.textContent = entry.name; > >- cell.title = entry.resource.url; >+ if (WI.settings.groupByNode.value && resource.initiatorNode) { >+ let nodeEntry = this._nodeEntries.get(resource.initiatorNode); >+ if (nodeEntry.initiatedResourceEntries.length > 1) { >+ cell.classList.add("grouped-by-node"); >+ >+ if ("Range" in resource.requestHeaders) { >+ cell.classList.add("resource-type-range"); >+ nameElement.textContent = WI.UIString("Byte Range %s").format(resource.requestHeaders["Range"].replace("bytes=", "")); >+ } >+ } >+ } >+ >+ if (!nameElement.textContent) { >+ cell.classList.add(resource.type); >+ nameElement.textContent = entry.name; >+ } >+ >+ cell.title = resource.url; > } > > _populateDomainCell(cell, entry) > { > console.assert(!cell.firstChild, "We expect the cell to be empty.", cell, cell.firstChild); > >+ function createIconAndText(scheme, domain) { >+ let secure = scheme === "https" || scheme === "wss"; >+ if (secure) { >+ let lockIconElement = cell.appendChild(document.createElement("img")); >+ lockIconElement.className = "lock"; >+ } >+ >+ cell.append(domain); >+ } >+ >+ let uniqueSchemeValues = this._uniqueValuesForNodeEntry(entry, (resourceEntry) => resourceEntry.scheme); >+ let uniqueDomainValues = this._uniqueValuesForNodeEntry(entry, (resourceEntry) => resourceEntry.domain); >+ if (uniqueSchemeValues && uniqueDomainValues) { >+ if (uniqueSchemeValues.size > 1 || uniqueDomainValues.size > 1) { >+ cell.classList.add("multiple"); >+ cell.textContent = WI.UIString("(multiple)"); >+ return; >+ } >+ >+ createIconAndText(uniqueSchemeValues.values().next().value, uniqueDomainValues.values().next().value); >+ return; >+ } >+ > if (!entry.domain) { > cell.textContent = emDash; > return; > } > >- let secure = entry.scheme === "https" || entry.scheme === "wss"; >- if (secure) { >- let lockIconElement = cell.appendChild(document.createElement("img")); >- lockIconElement.className = "lock"; >- } >- >- cell.append(entry.domain); >+ createIconAndText(entry.scheme, entry.domain); > } > > _populateInitiatorCell(cell, entry) > { >+ let node = entry.node; >+ if (node) { >+ cell.textContent = emDash; >+ return; >+ } >+ > let initiatorLocation = entry.resource.initiatorSourceCodeLocation; > if (!initiatorLocation) { > cell.textContent = emDash; >@@ -483,6 +587,31 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > > _populateTransferSizeCell(cell, entry) > { >+ let resourceEntries = entry.initiatedResourceEntries; >+ if (resourceEntries) { >+ if (resourceEntries.every((resourceEntry) => resourceEntry.resource.responseSource === WI.Resource.ResponseSource.MemoryCache)) { >+ cell.classList.add("cache-type"); >+ cell.textContent = WI.UIString("(memory)"); >+ return; >+ } >+ if (resourceEntries.every((resourceEntry) => resourceEntry.resource.responseSource === WI.Resource.ResponseSource.DiskCache)) { >+ cell.classList.add("cache-type"); >+ cell.textContent = WI.UIString("(disk)"); >+ return; >+ } >+ if (resourceEntries.every((resourceEntry) => resourceEntry.resource.responseSource === WI.Resource.ResponseSource.ServiceWorker)) { >+ cell.classList.add("cache-type"); >+ cell.textContent = WI.UIString("(service worker)"); >+ return; >+ } >+ let transferSize = resourceEntries.reduce((accumulator, current) => accumulator + (current.transferSize || 0), 0); >+ if (isNaN(transferSize)) >+ cell.textContent = emDash; >+ else >+ cell.textContent = Number.bytesToString(transferSize); >+ return; >+ } >+ > let responseSource = entry.resource.responseSource; > if (responseSource === WI.Resource.ResponseSource.MemoryCache) { > cell.classList.add("cache-type"); >@@ -509,6 +638,12 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > { > cell.removeChildren(); > >+ let node = entry.node; >+ if (node) { >+ // FIXME: create special timelines for node entries >+ return; >+ } >+ > let resource = entry.resource; > if (!resource.hasResponse()) { > cell.textContent = zeroWidthSpace; >@@ -666,7 +801,7 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > > case "waterfall": > // Sort by startTime number. >- comparator = comparator = (a, b) => a.startTime - b.startTime; >+ comparator = (a, b) => a.startTime - b.startTime; > break; > > default: >@@ -675,7 +810,17 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > } > > let reverseFactor = this._table.sortOrder === WI.Table.SortOrder.Ascending ? 1 : -1; >- this._entriesSortComparator = (a, b) => reverseFactor * comparator(a, b); >+ >+ let substitute = (entry, other) => { >+ if (WI.settings.groupByNode.value && entry.resource.initiatorNode) { >+ let nodeEntry = this._nodeEntries.get(entry.resource.initiatorNode); >+ if (!nodeEntry.initiatedResourceEntries.includes(other)) >+ return nodeEntry.initiatedResourceEntries[0]; >+ } >+ return entry; >+ }; >+ >+ this._entriesSortComparator = (a, b) => reverseFactor * comparator(substitute(a, b), substitute(b, a)); > } > > // Protected >@@ -883,8 +1028,13 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > return; > } > >- for (let resource of this._pendingInsertions) >- this._entries.push(this._entryForResource(resource)); >+ for (let resource of this._pendingInsertions) { >+ let resourceEntry = this._entryForResource(resource); >+ >+ this._tryLinkResourceToNode(resourceEntry); >+ >+ this._entries.push(resourceEntry); >+ } > this._pendingInsertions = []; > > for (let resource of this._pendingUpdates) >@@ -952,13 +1102,20 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > return; > > let entry = this._entryForResource(resource); >- this._entries[index] = entry; >+ >+ // Don't wipe out the previous entry, as it may be used by a node entry. >+ function updateEntry(existing) { >+ for (let key in entry) >+ existing[key] = entry[key]; >+ } >+ >+ updateEntry(this._entries[index]); > > let rowIndex = this._rowIndexForResource(resource); > if (rowIndex === -1) > return; > >- this._filteredEntries[rowIndex] = entry; >+ updateEntry(this._filteredEntries[rowIndex]); > } > > _hidePopover() >@@ -1185,26 +1342,34 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > return; > } > >- let entry = this._entryForResource(resource); >+ let resourceEntry = this._entryForResource(resource); > >- // Default sort has fast path. >- if (this._isDefaultSort() || !this._entriesSortComparator) { >- this._entries.push(entry); >- if (this._passFilter(entry)) { >- this._filteredEntries.push(entry); >+ this._tryLinkResourceToNode(resourceEntry); >+ >+ if (WI.settings.groupByNode.value && resource.initiatorNode) { >+ if (!this._entriesSortComparator) >+ this._generateSortComparator(); >+ } else if (this._isDefaultSort() || !this._entriesSortComparator) { >+ // Default sort has fast path. >+ this._entries.push(resourceEntry); >+ if (this._passFilter(resourceEntry)) { >+ this._filteredEntries.push(resourceEntry); > this._table.reloadDataAddedToEndOnly(); > } > return; > } > >- insertObjectIntoSortedArray(entry, this._entries, this._entriesSortComparator); >+ insertObjectIntoSortedArray(resourceEntry, this._entries, this._entriesSortComparator); > >- if (this._passFilter(entry)) { >- insertObjectIntoSortedArray(entry, this._filteredEntries, this._entriesSortComparator); >+ if (this._passFilter(resourceEntry)) { >+ if (WI.settings.groupByNode.value) >+ this._updateFilteredEntries(); >+ else >+ insertObjectIntoSortedArray(resourceEntry, this._filteredEntries, this._entriesSortComparator); > > // Probably a useless optimization here, but if we only added this row to the end > // we may avoid recreating all visible rows by saying as such. >- if (this._filteredEntries.lastValue === entry) >+ if (this._filteredEntries.lastValue === resourceEntry) > this._table.reloadDataAddedToEndOnly(); > else > this._table.reloadData(); >@@ -1239,6 +1404,47 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > }; > } > >+ _entryForNode(node, requiredFields) >+ { >+ return { >+ node, >+ initiatedResourceEntries: [], >+ expanded: true, >+ }; >+ } >+ >+ _tryLinkResourceToNode(resourceEntry) >+ { >+ let resource = resourceEntry.resource; >+ if (!resource || !resource.initiatorNode) >+ return; >+ >+ let nodeEntry = this._nodeEntries.get(resource.initiatorNode); >+ if (!nodeEntry) { >+ nodeEntry = this._entryForNode(resource.initiatorNode, Object.keys(resourceEntry)); >+ this._nodeEntries.set(resource.initiatorNode, nodeEntry); >+ } >+ >+ if (!this._entriesSortComparator) >+ this._generateSortComparator(); >+ >+ insertObjectIntoSortedArray(resourceEntry, nodeEntry.initiatedResourceEntries, this._entriesSortComparator); >+ } >+ >+ _uniqueValuesForNodeEntry(nodeEntry, accessor) >+ { >+ let resourceEntries = nodeEntry.initiatedResourceEntries; >+ if (!resourceEntries) >+ return null; >+ >+ return resourceEntries.reduce((accumulator, current) => { >+ let value = accessor(current); >+ if (value || typeof value === "number") >+ accumulator.add(value); >+ return accumulator; >+ }, new Set); >+ } >+ > _hasTypeFilter() > { > return !!this._activeTypeFilters; >@@ -1290,6 +1496,38 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > else > this._filteredEntries = this._entries.slice(); > >+ if (WI.settings.groupByNode.value) { >+ this._filteredEntries = this._filteredEntries.filter((entry) => { >+ if (entry.resource && entry.resource.initiatorNode) { >+ let nodeEntry = this._nodeEntries.get(entry.resource.initiatorNode); >+ if (!nodeEntry.expanded) >+ return false; >+ } >+ return true; >+ }); >+ >+ for (let nodeEntry of this._nodeEntries.values()) { >+ if (nodeEntry.initiatedResourceEntries.length < 2) >+ continue; >+ >+ let firstIndex = Infinity; >+ for (let resourceEntry of nodeEntry.initiatedResourceEntries) { >+ if (this._hasActiveFilter() && !this._passFilter(resourceEntry)) >+ continue; >+ >+ let index = this._filteredEntries.indexOf(resourceEntry); >+ if (index >= 0 && index < firstIndex) >+ firstIndex = index; >+ } >+ >+ if (!isFinite(firstIndex)) >+ continue; >+ >+ >+ this._filteredEntries.insertAtIndex(nodeEntry, firstIndex); >+ } >+ } >+ > this._restoreSelectedRow(); > > this._updateURLFilterActiveIndicator(); >@@ -1361,6 +1599,14 @@ WI.NetworkTableContentView = class NetworkTableContentView extends WI.ContentVie > this._table.reloadData(); > } > >+ _handleGroupByNodeCheckedDidChange(event) >+ { >+ WI.settings.groupByNode.value = this._groupByNodeNavigationItem.checked; >+ >+ this._updateSortAndFilteredEntries(); >+ this._table.reloadData(); >+ } >+ > _urlFilterDidChange(event) > { > let searchQuery = this._urlFilterNavigationItem.filterBar.filters.text; >diff --git a/Source/WebInspectorUI/UserInterface/Views/ResourceIcons.css b/Source/WebInspectorUI/UserInterface/Views/ResourceIcons.css >index d1544dc5185..fc0cce70a7c 100644 >--- a/Source/WebInspectorUI/UserInterface/Views/ResourceIcons.css >+++ b/Source/WebInspectorUI/UserInterface/Views/ResourceIcons.css >@@ -76,6 +76,10 @@ > content: url(../Images/Beacon.svg); > } > >+.resource-icon.resource-type-range .icon { >+ content: url(../Images/Range.svg); >+} >+ > .large .resource-icon .icon { > content: image-set(url(../Images/DocumentGenericLarge.png) 1x, url(../Images/DocumentGenericLarge@2x.png) 2x); > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Flags:
ews-watchlist
:
commit-queue-
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 189606
:
349738
|
349745
|
349747
|
349749
|
349771
|
349858
|
349861
|
349862
|
349863
|
349913
|
349918
|
349920
|
349930
|
349967
|
349980
|
349987
|
349988
|
350230
|
350239
|
350463
|
351480
|
351728
|
351785