@@ -20,11 +20,39 @@ import (
2020 "testing"
2121)
2222
23+ func TestGetPagesRouterScriptsCapturesAllChunksPerRoute (t * testing.T ) {
24+ // a route array can list several chunks; every one is a real script to scan,
25+ // not just the first element after the opening bracket.
26+ manifest := `self.__BUILD_MANIFEST={"/":["static/chunks/pages/index-a.js","static/chunks/shared-b.js"]}`
27+
28+ srv := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , _ * http.Request ) {
29+ w .Write ([]byte (manifest ))
30+ }))
31+ defer srv .Close ()
32+
33+ scripts , err := GetPagesRouterScripts (srv .URL + "/_buildManifest.js" )
34+ if err != nil {
35+ t .Fatalf ("GetPagesRouterScripts: %v" , err )
36+ }
37+
38+ found := func (needle string ) bool {
39+ for _ , s := range scripts {
40+ if strings .Contains (s , needle ) {
41+ return true
42+ }
43+ }
44+ return false
45+ }
46+ if ! found ("index-a.js" ) || ! found ("shared-b.js" ) {
47+ t .Errorf ("want both chunks index-a.js and shared-b.js, got %v" , scripts )
48+ }
49+ }
50+
2351func TestGetPagesRouterScriptsReadsPastLongLine (t * testing.T ) {
2452 // a manifest token past bufio's 64k cap must not truncate the read and
2553 // drop the script references that follow it.
2654 huge := strings .Repeat ("x" , bufio .MaxScanTokenSize + 1 )
27- manifest := `["early.js"]` + "\n " + huge + "\n " + `["late.js"]`
55+ manifest := `["static/ early.js"]` + "\n " + huge + "\n " + `["static/ late.js"]`
2856
2957 srv := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , _ * http.Request ) {
3058 w .Write ([]byte (manifest ))
@@ -48,3 +76,61 @@ func TestGetPagesRouterScriptsReadsPastLongLine(t *testing.T) {
4876 t .Errorf ("want both early.js and late.js, got %v" , scripts )
4977 }
5078}
79+
80+ func TestGetPagesRouterScriptsRealisticManifest (t * testing.T ) {
81+ // a realistic pages-router _buildManifest.js: routes map to multi-chunk
82+ // arrays, shared chunks are passed as IIFE args, and non-chunk .js strings
83+ // appear in __rewrites and sortedPages. every chunk must be captured and no
84+ // non-chunk .js string may be, so a hostile manifest cannot steer a fetch to
85+ // an arbitrary url through a rewrite destination.
86+ manifest := `self.__BUILD_MANIFEST=(function(a,b,c){return{` +
87+ `__rewrites:{afterFiles:[{"source":"/proxy/legacy.js","destination":"https://cdn.evil.example/tracker.js"}],beforeFiles:[],fallback:[]},` +
88+ `"/":[a,b,"static/chunks/pages/index-1a2b.js"],` +
89+ `"/_error":[a,"static/chunks/pages/_error-3c4d.js"],` +
90+ `"/blog/[slug]":[a,b,c,"static/chunks/pages/blog/[slug]-5e6f.js"],` +
91+ `sortedPages:["/","/_app","/_error","/blog/[slug]"],` +
92+ `ampFirstPages:[]` +
93+ `}}("static/chunks/webpack-9f8e.js","static/chunks/main-0d1c.js","static/chunks/framework-2b3a.js"));` +
94+ `self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();`
95+
96+ srv := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , _ * http.Request ) {
97+ w .Write ([]byte (manifest ))
98+ }))
99+ defer srv .Close ()
100+
101+ scripts , err := GetPagesRouterScripts (srv .URL + "/_buildManifest.js" )
102+ if err != nil {
103+ t .Fatalf ("GetPagesRouterScripts: %v" , err )
104+ }
105+
106+ found := func (needle string ) bool {
107+ for _ , s := range scripts {
108+ if strings .Contains (s , needle ) {
109+ return true
110+ }
111+ }
112+ return false
113+ }
114+
115+ // every real chunk, including the trailing IIFE-arg shared chunks
116+ wantChunks := []string {
117+ "static/chunks/pages/index-1a2b.js" ,
118+ "static/chunks/pages/_error-3c4d.js" ,
119+ "static/chunks/pages/blog/[slug]-5e6f.js" ,
120+ "static/chunks/webpack-9f8e.js" ,
121+ "static/chunks/main-0d1c.js" ,
122+ "static/chunks/framework-2b3a.js" ,
123+ }
124+ for _ , c := range wantChunks {
125+ if ! found (c ) {
126+ t .Errorf ("missing chunk %q, got %v" , c , scripts )
127+ }
128+ }
129+
130+ // no non-chunk .js string may leak into the fetch list
131+ for _ , bad := range []string {"legacy.js" , "tracker.js" , "cdn.evil.example" } {
132+ if found (bad ) {
133+ t .Errorf ("false positive: captured non-chunk %q in %v" , bad , scripts )
134+ }
135+ }
136+ }
0 commit comments