browser_set_response_override.js (6768B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 // Test for the nsIHttpChannelInternal helper setResponseOverride. 8 // which allows to bypass the network for a request before connect, and 9 // reply with a mocked response instead. 10 add_task(async function test_set_response_override() { 11 let observer = { 12 QueryInterface: ChromeUtils.generateQI(["nsIObserver"]), 13 observe(aSubject, aTopic) { 14 aSubject = aSubject.QueryInterface(Ci.nsIHttpChannelInternal); 15 if ( 16 aTopic == "http-on-before-connect" && 17 aSubject.URI.spec == 18 "https://example.com/browser/netwerk/test/browser/dummy.html" 19 ) { 20 const replacedHttpResponse = Cc[ 21 "@mozilla.org/network/replaced-http-response;1" 22 ].createInstance(Ci.nsIReplacedHttpResponse); 23 replacedHttpResponse.responseStatus = 200; 24 replacedHttpResponse.responseStatusText = "Och Aye"; 25 replacedHttpResponse.responseBody = 26 "<div id=from-response-override>From setResponseOverride"; 27 replacedHttpResponse.setResponseHeader( 28 "some-header", 29 "some-value", 30 false 31 ); 32 replacedHttpResponse.setResponseHeader( 33 "Set-Cookie", 34 "foo=bar;Path=/", 35 false 36 ); 37 aSubject.setResponseOverride(replacedHttpResponse); 38 } 39 }, 40 }; 41 Services.obs.addObserver(observer, "http-on-before-connect"); 42 43 const onTabLoaded = BrowserTestUtils.withNewTab( 44 { 45 gBrowser, 46 url: "https://example.com/browser/netwerk/test/browser/dummy.html", 47 waitForLoad: true, 48 }, 49 async function (browser) { 50 await ContentTask.spawn(browser, [], async function () { 51 Assert.ok( 52 !!content.document.getElementById("from-response-override"), 53 "Page was loaded using the response override" 54 ); 55 Assert.equal( 56 content.document.cookie, 57 "foo=bar", 58 "Cookie was set from the response override headers" 59 ); 60 61 // Perform another request to the same URL to check status and headers override. 62 const response = await content.fetch( 63 "https://example.com/browser/netwerk/test/browser/dummy.html" 64 ); 65 Assert.equal( 66 response.status, 67 200, 68 "Status was set from the response override" 69 ); 70 Assert.equal( 71 response.statusText, 72 "Och Aye", 73 "Status text was set from the response override" 74 ); 75 Assert.equal( 76 response.headers.get("some-header"), 77 "some-value", 78 "same-header header was set from the response override" 79 ); 80 }); 81 } 82 ); 83 await onTabLoaded; 84 85 Services.obs.removeObserver(observer, "http-on-before-connect"); 86 }); 87 88 // Test that a response override with 302 Found status + Location header 89 // redirects to the URL specified in the Location header. 90 add_task(async function test_set_response_override_redirects() { 91 let observer = { 92 QueryInterface: ChromeUtils.generateQI(["nsIObserver"]), 93 observe(aSubject, aTopic) { 94 aSubject = aSubject.QueryInterface(Ci.nsIHttpChannelInternal); 95 if ( 96 aTopic == "http-on-before-connect" && 97 aSubject.URI.spec == 98 "https://example.com/browser/netwerk/test/browser/dummy.html" 99 ) { 100 const replacedHttpResponse = Cc[ 101 "@mozilla.org/network/replaced-http-response;1" 102 ].createInstance(Ci.nsIReplacedHttpResponse); 103 replacedHttpResponse.responseStatus = 302; 104 replacedHttpResponse.responseStatusText = "Found"; 105 replacedHttpResponse.setResponseHeader( 106 "Location", 107 "https://example.com/browser/netwerk/test/browser/dummy.html?redirected=true", 108 false 109 ); 110 aSubject.setResponseOverride(replacedHttpResponse); 111 } 112 }, 113 }; 114 Services.obs.addObserver(observer, "http-on-before-connect"); 115 116 const onTabLoaded = BrowserTestUtils.withNewTab( 117 { 118 gBrowser, 119 url: "https://example.com/browser/netwerk/test/browser/dummy.html", 120 waitForLoad: true, 121 }, 122 async function (browser) { 123 await ContentTask.spawn(browser, [], async function () { 124 Assert.equal( 125 content.location.href, 126 "https://example.com/browser/netwerk/test/browser/dummy.html?redirected=true", 127 "Navigation was redirected based on the overridden response" 128 ); 129 }); 130 } 131 ); 132 await onTabLoaded; 133 134 Services.obs.removeObserver(observer, "http-on-before-connect"); 135 }); 136 137 // Test that a response override for a requst with CORS preflight succeeds without 138 // crashing Firefox. 139 add_task(async function test_set_response_override_cors_preflight() { 140 let observer = { 141 QueryInterface: ChromeUtils.generateQI(["nsIObserver"]), 142 observe(aSubject, aTopic) { 143 aSubject = aSubject.QueryInterface(Ci.nsIHttpChannelInternal); 144 if ( 145 aTopic == "http-on-before-connect" && 146 aSubject.URI.spec == "https://example.org/cors" 147 ) { 148 const replacedHttpResponse = Cc[ 149 "@mozilla.org/network/replaced-http-response;1" 150 ].createInstance(Ci.nsIReplacedHttpResponse); 151 replacedHttpResponse.responseStatus = 200; 152 replacedHttpResponse.responseStatusText = "OK"; 153 replacedHttpResponse.responseBody = "From setResponseOverride"; 154 replacedHttpResponse.setResponseHeader( 155 "Access-Control-Allow-Origin", 156 "*", 157 false 158 ); 159 160 aSubject.setResponseOverride(replacedHttpResponse); 161 } 162 }, 163 }; 164 Services.obs.addObserver(observer, "http-on-before-connect"); 165 166 await BrowserTestUtils.withNewTab( 167 { 168 gBrowser, 169 url: "https://example.com/browser/netwerk/test/browser/dummy.html", 170 waitForLoad: true, 171 }, 172 async function (browser) { 173 await ContentTask.spawn(browser, [], async function () { 174 const response = await content.fetch("https://example.org/cors", { 175 // extra header to force a CORS preflight request. 176 headers: { "X-PINGOTHER": "pingpong" }, 177 }); 178 // Note: https://example.org/cors does not exist, so simply receiving 179 // a response here already means the override was successful. 180 Assert.equal( 181 response.status, 182 200, 183 "Status was set from the response override" 184 ); 185 Assert.equal( 186 await response.text(), 187 "From setResponseOverride", 188 "Text content was set from the response override" 189 ); 190 }); 191 } 192 ); 193 194 Services.obs.removeObserver(observer, "http-on-before-connect"); 195 });