OLD | NEW |
(Empty) | |
| 1 <!doctype html> |
| 2 <html> |
| 3 <head> |
| 4 <meta charset="utf-8"> |
| 5 <title>Response consume</title> |
| 6 <meta name="help" href="https://fetch.spec.whatwg.org/#response"> |
| 7 <meta name="help" href="https://fetch.spec.whatwg.org/#body-mixin"> |
| 8 <meta name="author" title="Canon Research France" href="https://www.crf.cano
n.fr"> |
| 9 <script src="/resources/testharness.js"></script> |
| 10 <script src="/resources/testharnessreport.js"></script> |
| 11 <script src="../resources/utils.js"></script> |
| 12 </head> |
| 13 <body> |
| 14 <script> |
| 15 function blobToFormDataResponse(name, blob) { |
| 16 var formData = new FormData(); |
| 17 formData.append(name, blob); |
| 18 return new Response(formData); |
| 19 } |
| 20 |
| 21 function readBlobAsArrayBuffer(blob) { |
| 22 return new Promise(function(resolve, reject) { |
| 23 var reader = new FileReader(); |
| 24 reader.onload = function(evt) { |
| 25 resolve(reader.result); |
| 26 }; |
| 27 reader.onerror = function(evt) { |
| 28 reject("Blob's reader failed"); |
| 29 }; |
| 30 reader.readAsArrayBuffer(blob); |
| 31 }); |
| 32 } |
| 33 |
| 34 function responsePromise(body, responseInit) { |
| 35 return new Promise(function(resolve, reject) { |
| 36 resolve(new Response(body, responseInit)); |
| 37 }); |
| 38 } |
| 39 |
| 40 function responseStringToMultipartFormTextData(response, name, value) { |
| 41 assert_true(response.headers.has("Content-Type"), "Response contains Con
tent-Type header"); |
| 42 var boundaryMatches = response.headers.get("Content-Type").match(/;\s*bo
undary=("?)([^";\s]*)\1/); |
| 43 assert_true(!!boundaryMatches, "Response contains boundary parameter"); |
| 44 return stringToMultipartFormTextData(boundaryMatches[2], name, value); |
| 45 } |
| 46 |
| 47 function streamResponsePromise(streamData, responseInit) { |
| 48 return new Promise(function(resolve, reject) { |
| 49 var stream = new ReadableStream({ |
| 50 start: function(controller) { |
| 51 controller.enqueue(stringToArray(streamData)); |
| 52 controller.close(); |
| 53 } |
| 54 }); |
| 55 resolve(new Response(stream, responseInit)); |
| 56 }); |
| 57 } |
| 58 |
| 59 function stringToMultipartFormTextData(multipartBoundary, name, value) { |
| 60 return ('--' + multipartBoundary + '\r\n' + |
| 61 'Content-Disposition: form-data;name="' + name + '"\r\n' + |
| 62 '\r\n' + |
| 63 value + '\r\n' + |
| 64 '--' + multipartBoundary + '--\r\n'); |
| 65 } |
| 66 |
| 67 function checkBodyText(test, response, expectedBody) { |
| 68 return response.text().then( function(bodyAsText) { |
| 69 assert_equals(bodyAsText, expectedBody, "Retrieve and verify response's
body"); |
| 70 assert_true(response.bodyUsed, "body as text: bodyUsed turned true"); |
| 71 }); |
| 72 } |
| 73 |
| 74 function checkBodyBlob(test, response, expectedBody, expectedType) { |
| 75 return response.blob().then(function(bodyAsBlob) { |
| 76 assert_equals(bodyAsBlob.type, expectedType || "text/plain", "Blob body
type should be computed from the response Content-Type"); |
| 77 |
| 78 var promise = new Promise( function (resolve, reject) { |
| 79 var reader = new FileReader(); |
| 80 reader.onload = function(evt) { |
| 81 resolve(reader.result) |
| 82 }; |
| 83 reader.onerror = function () { |
| 84 reject("Blob's reader failed"); |
| 85 }; |
| 86 reader.readAsText(bodyAsBlob); |
| 87 }); |
| 88 return promise.then(function(body) { |
| 89 assert_equals(body, expectedBody, "Retrieve and verify response's body
"); |
| 90 assert_true(response.bodyUsed, "body as blob: bodyUsed turned true"); |
| 91 }); |
| 92 }); |
| 93 } |
| 94 |
| 95 function checkBodyArrayBuffer(test, response, expectedBody) { |
| 96 return response.arrayBuffer().then( function(bodyAsArrayBuffer) { |
| 97 validateBufferFromString(bodyAsArrayBuffer, expectedBody, "Retrieve and
verify response's body"); |
| 98 assert_true(response.bodyUsed, "body as arrayBuffer: bodyUsed turned tru
e"); |
| 99 }); |
| 100 } |
| 101 |
| 102 function checkBodyJSON(test, response, expectedBody) { |
| 103 return response.json().then(function(bodyAsJSON) { |
| 104 var strBody = JSON.stringify(bodyAsJSON) |
| 105 assert_equals(strBody, expectedBody, "Retrieve and verify response's bod
y"); |
| 106 assert_true(response.bodyUsed, "body as json: bodyUsed turned true"); |
| 107 }); |
| 108 } |
| 109 |
| 110 function checkBodyFormDataMultipart(test, response, expectedBody) { |
| 111 return response.formData().then(function(bodyAsFormData) { |
| 112 assert_true(bodyAsFormData instanceof FormData, "Should receive a FormDa
ta"); |
| 113 var entryName = "name"; |
| 114 var strBody = responseStringToMultipartFormTextData(response, entryName,
bodyAsFormData.get(entryName)); |
| 115 assert_equals(strBody, expectedBody, "Retrieve and verify response's bod
y"); |
| 116 assert_true(response.bodyUsed, "body as formData: bodyUsed turned true")
; |
| 117 }); |
| 118 } |
| 119 |
| 120 function checkBodyFormDataUrlencoded(test, response, expectedBody) { |
| 121 return response.formData().then(function(bodyAsFormData) { |
| 122 assert_true(bodyAsFormData instanceof FormData, "Should receive a FormDa
ta"); |
| 123 var entryName = "name"; |
| 124 var strBody = entryName + "=" + bodyAsFormData.get(entryName); |
| 125 assert_equals(strBody, expectedBody, "Retrieve and verify response's bod
y"); |
| 126 assert_true(response.bodyUsed, "body as formData: bodyUsed turned true")
; |
| 127 }); |
| 128 } |
| 129 |
| 130 function checkBodyFormDataError(test, response, expectedBody) { |
| 131 return promise_rejects(test, new TypeError(), response.formData()).then(fu
nction() { |
| 132 assert_true(response.bodyUsed, "body as formData: bodyUsed turned true")
; |
| 133 }); |
| 134 } |
| 135 |
| 136 function checkResponseBody(responsePromise, expectedBody, checkFunction, bod
yTypes) { |
| 137 promise_test(function(test) { |
| 138 return responsePromise.then(function(response) { |
| 139 assert_false(response.bodyUsed, "bodyUsed is false at init"); |
| 140 return checkFunction(test, response, expectedBody); |
| 141 }); |
| 142 }, "Consume response's body: " + bodyTypes); |
| 143 } |
| 144 |
| 145 var textData = JSON.stringify("This is response's body"); |
| 146 var textResponseInit = { "headers": [["Content-Type", "text/PLAIN"]] }; |
| 147 var blob = new Blob([textData], { "type": "application/octet-stream" }); |
| 148 var multipartBoundary = "boundary-" + Math.random(); |
| 149 var formData = new FormData(); |
| 150 var formTextResponseInit = { "headers": [["Content-Type", 'multipart/FORM-da
ta; boundary="' + multipartBoundary + '"']] }; |
| 151 var formTextData = stringToMultipartFormTextData(multipartBoundary, "name",
textData); |
| 152 var formBlob = new Blob([formTextData]); |
| 153 var urlSearchParamsData = "name=value"; |
| 154 var urlSearchParams = new URLSearchParams(urlSearchParamsData); |
| 155 var urlSearchParamsType = "application/x-www-form-urlencoded;charset=UTF-8"; |
| 156 var urlSearchParamsResponseInit = { "headers": [["Content-Type", urlSearchPa
ramsType]] }; |
| 157 var urlSearchParamsBlob = new Blob([urlSearchParamsData], { "type": urlSearc
hParamsType }); |
| 158 formData.append("name", textData); |
| 159 |
| 160 checkResponseBody(responsePromise(textData, textResponseInit), textData, che
ckBodyText, "from text to text"); |
| 161 checkResponseBody(responsePromise(textData, textResponseInit), textData, che
ckBodyBlob, "from text to blob"); |
| 162 checkResponseBody(responsePromise(textData, textResponseInit), textData, che
ckBodyArrayBuffer, "from text to arrayBuffer"); |
| 163 checkResponseBody(responsePromise(textData, textResponseInit), textData, che
ckBodyJSON, "from text to json"); |
| 164 checkResponseBody(responsePromise(formTextData, formTextResponseInit), formT
extData, checkBodyFormDataMultipart, "from text with correct multipart type to f
ormData"); |
| 165 checkResponseBody(responsePromise(formTextData, textResponseInit), undefined
, checkBodyFormDataError, "from text without correct multipart type to formData
(error case)"); |
| 166 checkResponseBody(responsePromise(urlSearchParamsData, urlSearchParamsRespon
seInit), urlSearchParamsData, checkBodyFormDataUrlencoded, "from text with corre
ct urlencoded type to formData"); |
| 167 checkResponseBody(responsePromise(urlSearchParamsData, textResponseInit), un
defined, checkBodyFormDataError, "from text without correct urlencoded type to f
ormData (error case)"); |
| 168 |
| 169 checkResponseBody(responsePromise(blob, textResponseInit), textData, checkBo
dyBlob, "from blob to blob"); |
| 170 checkResponseBody(responsePromise(blob), textData, checkBodyText, "from blob
to text"); |
| 171 checkResponseBody(responsePromise(blob), textData, checkBodyArrayBuffer, "fr
om blob to arrayBuffer"); |
| 172 checkResponseBody(responsePromise(blob), textData, checkBodyJSON, "from blob
to json"); |
| 173 checkResponseBody(responsePromise(formBlob, formTextResponseInit), formTextD
ata, checkBodyFormDataMultipart, "from blob with correct multipart type to formD
ata"); |
| 174 checkResponseBody(responsePromise(formBlob, textResponseInit), undefined, ch
eckBodyFormDataError, "from blob without correct multipart type to formData (err
or case)"); |
| 175 checkResponseBody(responsePromise(urlSearchParamsBlob, urlSearchParamsRespon
seInit), urlSearchParamsData, checkBodyFormDataUrlencoded, "from blob with corre
ct urlencoded type to formData"); |
| 176 checkResponseBody(responsePromise(urlSearchParamsBlob, textResponseInit), un
defined, checkBodyFormDataError, "from blob without correct urlencoded type to f
ormData (error case)"); |
| 177 |
| 178 function checkFormDataResponseBody(responsePromise, expectedName, expectedVa
lue, checkFunction, bodyTypes) { |
| 179 promise_test(function(test) { |
| 180 return responsePromise.then(function(response) { |
| 181 assert_false(response.bodyUsed, "bodyUsed is false at init"); |
| 182 var expectedBody = responseStringToMultipartFormTextData(response, exp
ectedName, expectedValue); |
| 183 return Promise.resolve().then(function() { |
| 184 if (checkFunction === checkBodyFormDataMultipart) |
| 185 return expectedBody; |
| 186 // Modify expectedBody to use the same spacing for |
| 187 // Content-Disposition parameters as Response and FormData does. |
| 188 var response2 = new Response(formData); |
| 189 return response2.text().then(function(formDataAsText) { |
| 190 var reName = /[ \t]*;[ \t]*name=/; |
| 191 var nameMatches = formDataAsText.match(reName); |
| 192 return expectedBody.replace(reName, nameMatches[0]); |
| 193 }); |
| 194 }).then(function(expectedBody) { |
| 195 return checkFunction(test, response, expectedBody); |
| 196 }); |
| 197 }); |
| 198 }, "Consume response's body: " + bodyTypes); |
| 199 } |
| 200 |
| 201 checkFormDataResponseBody(responsePromise(formData), "name", textData, check
BodyFormDataMultipart, "from FormData to formData"); |
| 202 checkResponseBody(responsePromise(formData, textResponseInit), undefined, ch
eckBodyFormDataError, "from FormData without correct type to formData (error cas
e)"); |
| 203 checkFormDataResponseBody(responsePromise(formData), "name", textData, funct
ion(test, response, expectedBody) { return checkBodyBlob(test, response, expecte
dBody, response.headers.get('Content-Type').toLowerCase()); }, "from FormData to
blob"); |
| 204 checkFormDataResponseBody(responsePromise(formData), "name", textData, check
BodyText, "from FormData to text"); |
| 205 checkFormDataResponseBody(responsePromise(formData), "name", textData, check
BodyArrayBuffer, "from FormData to arrayBuffer"); |
| 206 |
| 207 checkResponseBody(responsePromise(urlSearchParams), urlSearchParamsData, che
ckBodyFormDataUrlencoded, "from URLSearchParams to formData"); |
| 208 checkResponseBody(responsePromise(urlSearchParams, textResponseInit), urlSea
rchParamsData, checkBodyFormDataError, "from URLSearchParams without correct typ
e to formData (error case)"); |
| 209 checkResponseBody(responsePromise(urlSearchParams), urlSearchParamsData, fun
ction(test, response, expectedBody) { return checkBodyBlob(test, response, expec
tedBody, "application/x-www-form-urlencoded;charset=utf-8"); }, "from URLSearchP
arams to blob"); |
| 210 checkResponseBody(responsePromise(urlSearchParams), urlSearchParamsData, che
ckBodyText, "from URLSearchParams to text"); |
| 211 checkResponseBody(responsePromise(urlSearchParams), urlSearchParamsData, che
ckBodyArrayBuffer, "from URLSearchParams to arrayBuffer"); |
| 212 |
| 213 checkResponseBody(streamResponsePromise(textData, textResponseInit), textDat
a, checkBodyBlob, "from stream to blob"); |
| 214 checkResponseBody(streamResponsePromise(textData), textData, checkBodyText,
"from stream to text"); |
| 215 checkResponseBody(streamResponsePromise(textData), textData, checkBodyArrayB
uffer, "from stream to arrayBuffer"); |
| 216 checkResponseBody(streamResponsePromise(textData), textData, checkBodyJSON,
"from stream to json"); |
| 217 checkResponseBody(streamResponsePromise(formTextData, formTextResponseInit),
formTextData, checkBodyFormDataMultipart, "from stream with correct multipart t
ype to formData"); |
| 218 checkResponseBody(streamResponsePromise(formTextData), formTextData, checkBo
dyFormDataError, "from stream without correct multipart type to formData (error
case)"); |
| 219 checkResponseBody(streamResponsePromise(urlSearchParamsData, urlSearchParams
ResponseInit), urlSearchParamsData, checkBodyFormDataUrlencoded, "from stream wi
th correct urlencoded type to formData"); |
| 220 checkResponseBody(streamResponsePromise(urlSearchParamsData), urlSearchParam
sData, checkBodyFormDataError, "from stream without correct urlencoded type to f
ormData (error case)"); |
| 221 |
| 222 checkResponseBody(fetch("../resources/top.txt"), "top", checkBodyBlob, "from
fetch to blob"); |
| 223 checkResponseBody(fetch("../resources/top.txt"), "top", checkBodyText, "from
fetch to text"); |
| 224 checkResponseBody(fetch("../resources/top.txt"), "top", checkBodyArrayBuffer
, "from fetch to arrayBuffer"); |
| 225 checkResponseBody(fetch("../resources/top.txt"), "top", checkBodyFormDataErr
or, "from fetch without correct type to formData (error case)"); |
| 226 |
| 227 promise_test(function(test) { |
| 228 var response = new Response(new Blob([ |
| 229 "--boundary\r\n", |
| 230 "Content-Disposition: form-data; name=string\r\n", |
| 231 "\r\nvalue", new Uint8Array([0xC2, 0xA0]), "1\r\n", |
| 232 "--boundary\r\n", |
| 233 "Content-Disposition: form-data; name=string-with-default-charset\r\n", |
| 234 "Content-Type: text/plain; charset=utf-8\r\n", |
| 235 "\r\nvalue", new Uint8Array([0xC2, 0xA0]), "2\r\n", |
| 236 "--boundary\r\n", |
| 237 "Content-Disposition: form-data; name=string-with-non-default-charset\r\
n", |
| 238 "Content-Type: text/plain; charset=iso-8859-1\r\n", |
| 239 "\r\nvalue", new Uint8Array([0xC2, 0xA0]), "3\r\n", |
| 240 "--boundary\r\n", |
| 241 "Content-Disposition: form-data; name=string-with-non-default-type\r\n", |
| 242 "Content-Type: application/octet-stream\r\n", |
| 243 "\r\nvalue", new Uint8Array([0xC2, 0xA0]), "4\r\n", |
| 244 "--boundary\r\n", |
| 245 "Content-Disposition: form-data; name=file; filename=file1\r\n", |
| 246 "Content-Type: application/octet-stream; x-param=x-value\r\n", |
| 247 "\r\n", new Uint8Array([5, 0x0, 0xFF]), "\r\n", |
| 248 "--boundary\r\n", |
| 249 "Content-Disposition: form-data; name=\"file-without-type\"; filename=\"
file2\"\r\n", |
| 250 "\r\n", new Uint8Array([6, 0x0, 0x7F, 0xFF]), "\r\n", |
| 251 "--boundary--\r\n" |
| 252 ]), { "headers": [["Content-Type", 'multipart/form-data; boundary="boundar
y"']] }); |
| 253 return response.formData().then(function(bodyAsFormData) { |
| 254 // Non-file parts must always be decoded using utf-8 encoding. |
| 255 assert_equals(bodyAsFormData.get("string"), "value\u00A01", "Retrieve an
d verify response's 1st entry value"); |
| 256 assert_equals(bodyAsFormData.get("string-with-default-charset"), "value\
u00A02", "Retrieve and verify response's 2nd entry value"); |
| 257 assert_equals(bodyAsFormData.get("string-with-non-default-charset"), "va
lue\u00A03", "Retrieve and verify response's 3rd entry value"); |
| 258 assert_equals(bodyAsFormData.get("string-with-non-default-type"), "value
\u00A04", "Retrieve and verify response's 4th entry value"); |
| 259 // The name of a File must be taken from the filename parameter in |
| 260 // the Content-Disposition header field. |
| 261 assert_equals(bodyAsFormData.get("file").name, "file1", "Retrieve and ve
rify response's 5th entry name property"); |
| 262 assert_equals(bodyAsFormData.get("file-without-type").name, "file2", "Re
trieve and verify response's 6th entry name property"); |
| 263 // The type of a File must be taken from the Content-Type header field |
| 264 // which defaults to "text/plain". |
| 265 assert_equals(bodyAsFormData.get("file").type, "application/octet-stream
; x-param=x-value", "Retrieve and verify response's 5th entry type property"); |
| 266 assert_equals(bodyAsFormData.get("file-without-type").type, "text/plain"
, "Retrieve and verify response's 6th entry type property"); |
| 267 |
| 268 return Promise.resolve().then(function() { |
| 269 return blobToFormDataResponse("file", bodyAsFormData.get("file")).text
().then(function(bodyAsText) { |
| 270 // Verify that filename, name and type are preserved. |
| 271 assert_regexp_match(bodyAsText, /\r\nContent-Disposition: *form-data
;([^\r\n]*;)* *filename=("?)file1\2[;\r]/i, "Retrieve and verify response's 5th
entry filename parameter"); |
| 272 assert_regexp_match(bodyAsText, /\r\nContent-Disposition: *form-data
;([^\r\n]*;)* *name=("?)file\2[;\r]/i, "Retrieve and verify response's 5th entry
name parameter"); |
| 273 assert_regexp_match(bodyAsText, /\r\nContent-Type: *application\/oct
et-stream; x-param=x-value\r\n/i, "Retrieve and verify response's 5th entry type
field"); |
| 274 // Verify that the content is preserved. |
| 275 return readBlobAsArrayBuffer(bodyAsFormData.get("file")).then(functi
on(arrayBuffer) { |
| 276 assert_array_equals(new Uint8Array(arrayBuffer), new Uint8Array([5
, 0x0, 0xFF]), "Retrieve and verify response's 5th entry content"); |
| 277 }); |
| 278 }); |
| 279 }).then(function() { |
| 280 return blobToFormDataResponse("file-without-type", bodyAsFormData.get(
"file-without-type")).text().then(function(bodyAsText) { |
| 281 // Verify that filename, name and type are preserved. |
| 282 assert_regexp_match(bodyAsText, /\r\nContent-Disposition: *form-data
;([^\r\n]*;)* *filename=("?)file2\2[;\r]/i, "Retrieve and verify response's 6th
entry filename parameter"); |
| 283 assert_regexp_match(bodyAsText, /\r\nContent-Disposition: *form-data
;([^\r\n]*;)* *name=("?)file-without-type\2[;\r]/i, "Retrieve and verify respons
e's 6th entry name parameter"); |
| 284 assert_regexp_match(bodyAsText, /\r\nContent-Type: *text\/plain\r\n/
i, "Retrieve and verify response's 6th entry type field"); |
| 285 // Verify that the content is preserved. |
| 286 return readBlobAsArrayBuffer(bodyAsFormData.get("file-without-type")
).then(function(arrayBuffer) { |
| 287 assert_array_equals(new Uint8Array(arrayBuffer), new Uint8Array([6
, 0x0, 0x7F, 0xFF]), "Retrieve and verify response's 6th entry content"); |
| 288 }); |
| 289 }); |
| 290 }); |
| 291 }); |
| 292 }, "Consume response's body: from multipart form data blob to formData"); |
| 293 |
| 294 </script> |
| 295 </body> |
| 296 </html> |
OLD | NEW |