| 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 | 
|---|