test_bug1830022.js (5260B)
1 "use strict"; 2 3 const { HttpServer } = ChromeUtils.importESModule( 4 "resource://testing-common/httpd.sys.mjs" 5 ); 6 7 function makeChannel(url) { 8 return NetUtil.newChannel({ 9 uri: url, 10 loadUsingSystemPrincipal: true, 11 }).QueryInterface(Ci.nsIHttpChannel); 12 } 13 14 ChromeUtils.defineLazyGetter(this, "URL", function () { 15 return "http://localhost:" + httpServer.identity.primaryPort; 16 }); 17 18 let httpServer = null; 19 20 function pathHandler(metadata, response) { 21 var body; 22 if (metadata.hasHeader("Idempotency-Key")) { 23 response.setStatusLine(metadata.httpVersion, 200, "OK"); 24 // echo back the header for further validation 25 let IDK = metadata.getHeader("Idempotency-Key"); 26 response.setHeader("Idempotency-Key", IDK, false); 27 body = "success"; 28 } else { 29 response.setStatusLine( 30 metadata.httpVersion, 31 500, 32 "missing Idempotency-Key" 33 ); 34 body = "failed"; 35 } 36 response.bodyOutputStream.write(body, body.length); 37 } 38 39 // Helper-method to validate that the "Idempotency-Key" value that we 40 // generate matches the expected format and is the same in the response. 41 // Meant to be called inside of a test that's been added via add_task. 42 function validateAutomaticallyAddedHeaderVal(chan) { 43 let valueFromRequest = chan.getRequestHeader("Idempotency-Key"); 44 let valueFromResponse = chan.getResponseHeader("Idempotency-Key"); 45 46 // Validate that the header's got a nonempty value, and that the 47 // response matches the request: 48 Assert.notEqual(valueFromRequest, ""); 49 Assert.notEqual(valueFromResponse, ""); 50 Assert.equal(valueFromRequest, valueFromResponse); 51 52 // Further validation on the value (just focusing on valueFromRequest, 53 // since at this point we know that valueFromResponse is equal to it): 54 // * We expect the value to be formatted as a nonempy double-quoted string, 55 // (i.e. length must be at least 3), as part of the "sf-string" syntax: 56 Assert.greaterOrEqual(valueFromRequest.length, 3); 57 Assert.ok(valueFromRequest.startsWith('"')); 58 Assert.ok(valueFromRequest.endsWith('"')); 59 60 // * Inside the double-quotes, we expect the value to be formatted as an 61 // unsigned integer. The spec doesn't require this, but that's the 62 // representation we use for now, so let's be sure we don't inadvertently 63 // stray from that format (except as a deliberate choice, which would 64 // involve an update to this test's expectations). 65 let quotedPortion = valueFromRequest.slice(1, -1); 66 let parsedInteger = Number.parseInt(quotedPortion); 67 Assert.ok(!Number.isNaN(parsedInteger)); 68 Assert.greaterOrEqual(parsedInteger, 0); 69 } 70 71 add_setup(async () => { 72 httpServer = new HttpServer(); 73 httpServer.registerPathHandler("/test_bug1830022", pathHandler); 74 httpServer.start(-1); 75 registerCleanupFunction(async () => await httpServer.stop()); 76 }); 77 78 // tests if we add the header for the POST request 79 add_task(async function idempotency_key_addition_for_post() { 80 let chan = makeChannel(URL + "/test_bug1830022"); 81 chan.requestMethod = "POST"; 82 await new Promise(resolve => { 83 chan.asyncOpen(new ChannelListener(resolve)); 84 }); 85 validateAutomaticallyAddedHeaderVal(chan); 86 }); 87 88 // tests if we add the header for the PATCH request 89 add_task(async function idempotency_key_addition_for_patch() { 90 let chan = makeChannel(URL + "/test_bug1830022"); 91 chan.requestMethod = "PATCH"; 92 await new Promise(resolve => { 93 chan.asyncOpen(new ChannelListener(resolve)); 94 }); 95 validateAutomaticallyAddedHeaderVal(chan); 96 }); 97 98 // tests Idempotency key's uniqueness 99 add_task(async function idempotency_key_uniqueness() { 100 let chan = makeChannel(URL + "/test_bug1830022"); 101 chan.requestMethod = "POST"; 102 await new Promise(resolve => { 103 chan.asyncOpen(new ChannelListener(resolve)); 104 }); 105 106 let chan2 = makeChannel(URL + "/test_bug1830022"); 107 chan2.requestMethod = "POST"; 108 await new Promise(resolve => { 109 chan2.asyncOpen(new ChannelListener(resolve)); 110 }); 111 112 Assert.notEqual( 113 chan.getRequestHeader("Idempotency-Key"), 114 chan2.getRequestHeader("Idempotency-Key") 115 ); 116 117 // tests if the Idempotency key is same for reposts 118 let chan3 = makeChannel(URL + "/test_bug1830022"); 119 chan3.requestMethod = "POST"; 120 await new Promise(resolve => { 121 chan3.asyncOpen(new ChannelListener(resolve)); 122 }); 123 124 let cachekey = chan3.QueryInterface(Ci.nsICacheInfoChannel).cacheKey; 125 126 let chan4 = makeChannel(URL + "/test_bug1830022"); 127 chan4.requestMethod = "POST"; 128 chan4.QueryInterface(Ci.nsICacheInfoChannel).cacheKey = cachekey; 129 await new Promise(resolve => { 130 chan4.asyncOpen(new ChannelListener(resolve)); 131 }); 132 133 Assert.equal( 134 chan3.getRequestHeader("Idempotency-Key"), 135 chan4.getRequestHeader("Idempotency-Key") 136 ); 137 }); 138 139 // tests if we do not overwrite the header that is set before opening the channel 140 add_task(async function idempotency_key_addition_for_post() { 141 // construct the channel 142 let chan = makeChannel(URL + "/test_bug1830022"); 143 chan.setRequestHeader("Idempotency-Key", "U-V-W-X-Y-Z", false); 144 chan.requestMethod = "POST"; 145 await new Promise(resolve => { 146 chan.asyncOpen(new ChannelListener(resolve)); 147 }); 148 Assert.equal(chan.getRequestHeader("Idempotency-Key"), "U-V-W-X-Y-Z"); 149 Assert.equal(chan.getResponseHeader("Idempotency-Key"), "U-V-W-X-Y-Z"); 150 });