blob-range.any.js (7232B)
1 // See also /fetch/range/blob.any.js 2 3 const supportedBlobRange = [ 4 { 5 name: "A simple blob range request.", 6 data: ["A simple Hello, World! example"], 7 type: "text/plain", 8 range: "bytes=9-21", 9 content_length: 13, 10 content_range: "bytes 9-21/30", 11 result: "Hello, World!", 12 }, 13 { 14 name: "A blob range request with no type.", 15 data: ["A simple Hello, World! example"], 16 type: undefined, 17 range: "bytes=9-21", 18 content_length: 13, 19 content_range: "bytes 9-21/30", 20 result: "Hello, World!", 21 }, 22 { 23 name: "A blob range request with no end.", 24 data: ["Range with no end"], 25 type: "text/plain", 26 range: "bytes=11-", 27 content_length: 6, 28 content_range: "bytes 11-16/17", 29 result: "no end", 30 }, 31 { 32 name: "A blob range request with no start.", 33 data: ["Range with no start"], 34 type: "text/plain", 35 range: "bytes=-8", 36 content_length: 8, 37 content_range: "bytes 11-18/19", 38 result: "no start", 39 }, 40 { 41 name: "A simple blob range request with whitespace.", 42 data: ["A simple Hello, World! example"], 43 type: "text/plain", 44 range: "bytes= \t9-21", 45 content_length: 13, 46 content_range: "bytes 9-21/30", 47 result: "Hello, World!", 48 }, 49 { 50 name: "Blob content with short content and a large range end", 51 data: ["Not much here"], 52 type: "text/plain", 53 range: "bytes=4-100000000000", 54 content_length: 9, 55 content_range: "bytes 4-12/13", 56 result: "much here", 57 }, 58 { 59 name: "Blob content with short content and a range end matching content length", 60 data: ["Not much here"], 61 type: "text/plain", 62 range: "bytes=4-13", 63 content_length: 9, 64 content_range: "bytes 4-12/13", 65 result: "much here", 66 }, 67 { 68 name: "Blob range with whitespace before and after hyphen", 69 data: ["Valid whitespace #1"], 70 type: "text/plain", 71 range: "bytes=5 - 10", 72 content_length: 6, 73 content_range: "bytes 5-10/19", 74 result: " white", 75 }, 76 { 77 name: "Blob range with whitespace after hyphen", 78 data: ["Valid whitespace #2"], 79 type: "text/plain", 80 range: "bytes=-\t 5", 81 content_length: 5, 82 content_range: "bytes 14-18/19", 83 result: "ce #2", 84 }, 85 { 86 name: "Blob range with whitespace around equals sign", 87 data: ["Valid whitespace #3"], 88 type: "text/plain", 89 range: "bytes \t =\t 6-", 90 content_length: 13, 91 content_range: "bytes 6-18/19", 92 result: "whitespace #3", 93 }, 94 ]; 95 96 const unsupportedBlobRange = [ 97 { 98 name: "Blob range with no value", 99 data: ["Blob range should have a value"], 100 type: "text/plain", 101 range: "", 102 }, 103 { 104 name: "Blob range with incorrect range header", 105 data: ["A"], 106 type: "text/plain", 107 range: "byte=0-" 108 }, 109 { 110 name: "Blob range with incorrect range header #2", 111 data: ["A"], 112 type: "text/plain", 113 range: "bytes" 114 }, 115 { 116 name: "Blob range with incorrect range header #3", 117 data: ["A"], 118 type: "text/plain", 119 range: "bytes\t \t" 120 }, 121 { 122 name: "Blob range request with multiple range values", 123 data: ["Multiple ranges are not currently supported"], 124 type: "text/plain", 125 range: "bytes=0-5,15-", 126 }, 127 { 128 name: "Blob range request with multiple range values and whitespace", 129 data: ["Multiple ranges are not currently supported"], 130 type: "text/plain", 131 range: "bytes=0-5, 15-", 132 }, 133 { 134 name: "Blob range request with trailing comma", 135 data: ["Range with invalid trailing comma"], 136 type: "text/plain", 137 range: "bytes=0-5,", 138 }, 139 { 140 name: "Blob range with no start or end", 141 data: ["Range with no start or end"], 142 type: "text/plain", 143 range: "bytes=-", 144 }, 145 { 146 name: "Blob range request with short range end", 147 data: ["Range end should be greater than range start"], 148 type: "text/plain", 149 range: "bytes=10-5", 150 }, 151 { 152 name: "Blob range start should be an ASCII digit", 153 data: ["Range start must be an ASCII digit"], 154 type: "text/plain", 155 range: "bytes=x-5", 156 }, 157 { 158 name: "Blob range should have a dash", 159 data: ["Blob range should have a dash"], 160 type: "text/plain", 161 range: "bytes=5", 162 }, 163 { 164 name: "Blob range end should be an ASCII digit", 165 data: ["Range end must be an ASCII digit"], 166 type: "text/plain", 167 range: "bytes=5-x", 168 }, 169 { 170 name: "Blob range should include '-'", 171 data: ["Range end must include '-'"], 172 type: "text/plain", 173 range: "bytes=x", 174 }, 175 { 176 name: "Blob range should include '='", 177 data: ["Range end must include '='"], 178 type: "text/plain", 179 range: "bytes 5-", 180 }, 181 { 182 name: "Blob range should include 'bytes='", 183 data: ["Range end must include 'bytes='"], 184 type: "text/plain", 185 range: "5-", 186 }, 187 { 188 name: "Blob content with short content and a large range start", 189 data: ["Not much here"], 190 type: "text/plain", 191 range: "bytes=100000-", 192 }, 193 { 194 name: "Blob content with short content and a range start matching the content length", 195 data: ["Not much here"], 196 type: "text/plain", 197 range: "bytes=13-", 198 }, 199 ]; 200 201 supportedBlobRange.forEach(({ name, data, type, range, content_length, content_range, result }) => { 202 promise_test(async t => { 203 const blob = new Blob(data, { "type" : type }); 204 const blobURL = URL.createObjectURL(blob); 205 t.add_cleanup(() => URL.revokeObjectURL(blobURL)); 206 const xhr = new XMLHttpRequest(); 207 xhr.open("GET", blobURL); 208 xhr.responseType = "text"; 209 xhr.setRequestHeader("Range", range); 210 await new Promise(resolve => { 211 xhr.onloadend = resolve; 212 xhr.send(); 213 }); 214 assert_equals(xhr.status, 206, "HTTP status is 206"); 215 assert_equals(xhr.getResponseHeader("Content-Type"), type || "", "Content-Type is " + xhr.getResponseHeader("Content-Type")); 216 assert_equals(xhr.getResponseHeader("Content-Length"), content_length.toString(), "Content-Length is " + xhr.getResponseHeader("Content-Length")); 217 assert_equals(xhr.getResponseHeader("Content-Range"), content_range, "Content-Range is " + xhr.getResponseHeader("Content-Range")); 218 assert_equals(xhr.responseText, result, "Response's body is correct"); 219 const all = xhr.getAllResponseHeaders().toLowerCase(); 220 assert_true(all.includes(`content-type: ${type || ""}`), "Expected Content-Type in getAllResponseHeaders()"); 221 assert_true(all.includes(`content-length: ${content_length}`), "Expected Content-Length in getAllResponseHeaders()"); 222 assert_true(all.includes(`content-range: ${content_range}`), "Expected Content-Range in getAllResponseHeaders()") 223 }, name); 224 }); 225 226 unsupportedBlobRange.forEach(({ name, data, type, range }) => { 227 promise_test(t => { 228 const blob = new Blob(data, { "type" : type }); 229 const blobURL = URL.createObjectURL(blob); 230 t.add_cleanup(() => URL.revokeObjectURL(blobURL)); 231 232 const xhr = new XMLHttpRequest(); 233 xhr.open("GET", blobURL, false); 234 xhr.setRequestHeader("Range", range); 235 assert_throws_dom("NetworkError", () => xhr.send()); 236 237 xhr.open("GET", blobURL); 238 xhr.setRequestHeader("Range", range); 239 xhr.responseType = "text"; 240 return new Promise((resolve, reject) => { 241 xhr.onload = reject; 242 xhr.onerror = resolve; 243 xhr.send(); 244 }); 245 }, name); 246 });