| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "modules/fetch/Response.h" | 5 #include "modules/fetch/Response.h" |
| 6 | 6 |
| 7 #include "bindings/core/v8/Dictionary.h" | 7 #include "bindings/core/v8/Dictionary.h" |
| 8 #include "bindings/core/v8/ExceptionState.h" | 8 #include "bindings/core/v8/ExceptionState.h" |
| 9 #include "bindings/core/v8/ScriptState.h" | 9 #include "bindings/core/v8/ScriptState.h" |
| 10 #include "bindings/core/v8/V8ArrayBuffer.h" | 10 #include "bindings/core/v8/V8ArrayBuffer.h" |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 112 return create(scriptState, nullptr, String(), ResponseInit(), exceptionState
); | 112 return create(scriptState, nullptr, String(), ResponseInit(), exceptionState
); |
| 113 } | 113 } |
| 114 | 114 |
| 115 Response* Response::create(ScriptState* scriptState, ScriptValue bodyValue, cons
t Dictionary& init, ExceptionState& exceptionState) | 115 Response* Response::create(ScriptState* scriptState, ScriptValue bodyValue, cons
t Dictionary& init, ExceptionState& exceptionState) |
| 116 { | 116 { |
| 117 v8::Local<v8::Value> body = bodyValue.v8Value(); | 117 v8::Local<v8::Value> body = bodyValue.v8Value(); |
| 118 ScriptValue reader; | 118 ScriptValue reader; |
| 119 v8::Isolate* isolate = scriptState->isolate(); | 119 v8::Isolate* isolate = scriptState->isolate(); |
| 120 ExecutionContext* executionContext = scriptState->getExecutionContext(); | 120 ExecutionContext* executionContext = scriptState->getExecutionContext(); |
| 121 | 121 |
| 122 OwnPtr<FetchDataConsumerHandle> bodyHandle; | 122 BodyStreamBuffer* bodyBuffer = nullptr; |
| 123 String contentType; | 123 String contentType; |
| 124 if (bodyValue.isUndefined() || bodyValue.isNull()) { | 124 if (bodyValue.isUndefined() || bodyValue.isNull()) { |
| 125 // Note: The IDL processor cannot handle this situation. See | 125 // Note: The IDL processor cannot handle this situation. See |
| 126 // https://crbug.com/335871. | 126 // https://crbug.com/335871. |
| 127 } else if (V8Blob::hasInstance(body, isolate)) { | 127 } else if (V8Blob::hasInstance(body, isolate)) { |
| 128 Blob* blob = V8Blob::toImpl(body.As<v8::Object>()); | 128 Blob* blob = V8Blob::toImpl(body.As<v8::Object>()); |
| 129 bodyHandle = FetchBlobDataConsumerHandle::create(executionContext, blob-
>blobDataHandle()); | 129 bodyBuffer = new BodyStreamBuffer(scriptState, FetchBlobDataConsumerHand
le::create(executionContext, blob->blobDataHandle())); |
| 130 contentType = blob->type(); | 130 contentType = blob->type(); |
| 131 } else if (V8ArrayBuffer::hasInstance(body, isolate)) { | 131 } else if (V8ArrayBuffer::hasInstance(body, isolate)) { |
| 132 bodyHandle = FetchFormDataConsumerHandle::create(V8ArrayBuffer::toImpl(b
ody.As<v8::Object>())); | 132 bodyBuffer = new BodyStreamBuffer(scriptState, FetchFormDataConsumerHand
le::create(V8ArrayBuffer::toImpl(body.As<v8::Object>()))); |
| 133 } else if (V8ArrayBufferView::hasInstance(body, isolate)) { | 133 } else if (V8ArrayBufferView::hasInstance(body, isolate)) { |
| 134 bodyHandle = FetchFormDataConsumerHandle::create(V8ArrayBufferView::toIm
pl(body.As<v8::Object>())); | 134 bodyBuffer = new BodyStreamBuffer(scriptState, FetchFormDataConsumerHand
le::create(V8ArrayBufferView::toImpl(body.As<v8::Object>()))); |
| 135 } else if (V8FormData::hasInstance(body, isolate)) { | 135 } else if (V8FormData::hasInstance(body, isolate)) { |
| 136 RefPtr<EncodedFormData> formData = V8FormData::toImpl(body.As<v8::Object
>())->encodeMultiPartFormData(); | 136 RefPtr<EncodedFormData> formData = V8FormData::toImpl(body.As<v8::Object
>())->encodeMultiPartFormData(); |
| 137 // Here we handle formData->boundary() as a C-style string. See | 137 // Here we handle formData->boundary() as a C-style string. See |
| 138 // FormDataEncoder::generateUniqueBoundaryString. | 138 // FormDataEncoder::generateUniqueBoundaryString. |
| 139 contentType = AtomicString("multipart/form-data; boundary=") + formData-
>boundary().data(); | 139 contentType = AtomicString("multipart/form-data; boundary=") + formData-
>boundary().data(); |
| 140 bodyHandle = FetchFormDataConsumerHandle::create(executionContext, formD
ata.release()); | 140 bodyBuffer = new BodyStreamBuffer(scriptState, FetchFormDataConsumerHand
le::create(executionContext, formData.release())); |
| 141 } else if (RuntimeEnabledFeatures::responseConstructedWithReadableStreamEnab
led() && ReadableStreamOperations::isReadableStream(scriptState, bodyValue)) { | 141 } else if (RuntimeEnabledFeatures::responseConstructedWithReadableStreamEnab
led() && ReadableStreamOperations::isReadableStream(scriptState, bodyValue)) { |
| 142 bodyHandle = ReadableStreamDataConsumerHandle::create(scriptState, bodyV
alue); | 142 if (RuntimeEnabledFeatures::responseBodyWithV8ExtraStreamEnabled()) { |
| 143 reader = ReadableStreamOperations::getReader(scriptState, bodyValue, exc
eptionState); | 143 bodyBuffer = new BodyStreamBuffer(scriptState, bodyValue); |
| 144 if (exceptionState.hadException()) { | |
| 145 reader = ScriptValue(); | |
| 146 bodyHandle = createFetchDataConsumerHandleFromWebHandle(createUnexpe
ctedErrorDataConsumerHandle()); | |
| 147 exceptionState.clearException(); | |
| 148 } else { | 144 } else { |
| 149 bodyHandle = ReadableStreamDataConsumerHandle::create(scriptState, r
eader); | 145 OwnPtr<FetchDataConsumerHandle> bodyHandle; |
| 146 reader = ReadableStreamOperations::getReader(scriptState, bodyValue,
exceptionState); |
| 147 if (exceptionState.hadException()) { |
| 148 reader = ScriptValue(); |
| 149 bodyHandle = createFetchDataConsumerHandleFromWebHandle(createUn
expectedErrorDataConsumerHandle()); |
| 150 exceptionState.clearException(); |
| 151 } else { |
| 152 bodyHandle = ReadableStreamDataConsumerHandle::create(scriptStat
e, reader); |
| 153 } |
| 154 bodyBuffer = new BodyStreamBuffer(scriptState, std::move(bodyHandle)
); |
| 150 } | 155 } |
| 151 } else { | 156 } else { |
| 152 String string = toUSVString(isolate, body, exceptionState); | 157 String string = toUSVString(isolate, body, exceptionState); |
| 153 if (exceptionState.hadException()) | 158 if (exceptionState.hadException()) |
| 154 return nullptr; | 159 return nullptr; |
| 155 bodyHandle = FetchFormDataConsumerHandle::create(string); | 160 bodyBuffer = new BodyStreamBuffer(scriptState, FetchFormDataConsumerHand
le::create(string)); |
| 156 contentType = "text/plain;charset=UTF-8"; | 161 contentType = "text/plain;charset=UTF-8"; |
| 157 } | 162 } |
| 158 // TODO(yhirano): Add the URLSearchParams case. | 163 // TODO(yhirano): Add the URLSearchParams case. |
| 159 Response* response = create(scriptState, std::move(bodyHandle), contentType,
ResponseInit(init, exceptionState), exceptionState); | 164 Response* response = create(scriptState, bodyBuffer, contentType, ResponseIn
it(init, exceptionState), exceptionState); |
| 160 if (!exceptionState.hadException() && !reader.isEmpty()) { | 165 if (!exceptionState.hadException() && !reader.isEmpty()) { |
| 161 // Add a hidden reference so that the weak persistent in the | 166 // Add a hidden reference so that the weak persistent in the |
| 162 // ReadableStreamDataConsumerHandle will be valid as long as the | 167 // ReadableStreamDataConsumerHandle will be valid as long as the |
| 163 // Response is valid. | 168 // Response is valid. |
| 164 v8::Local<v8::Value> wrapper = toV8(response, scriptState); | 169 v8::Local<v8::Value> wrapper = toV8(response, scriptState); |
| 165 if (wrapper.IsEmpty()) { | 170 if (wrapper.IsEmpty()) { |
| 166 exceptionState.throwTypeError("Cannot create a Response wrapper"); | 171 exceptionState.throwTypeError("Cannot create a Response wrapper"); |
| 167 return nullptr; | 172 return nullptr; |
| 168 } | 173 } |
| 169 ASSERT(wrapper->IsObject()); | 174 ASSERT(wrapper->IsObject()); |
| 170 V8HiddenValue::setHiddenValue(scriptState, wrapper.As<v8::Object>(), V8H
iddenValue::readableStreamReaderInResponse(scriptState->isolate()), reader.v8Val
ue()); | 175 V8HiddenValue::setHiddenValue(scriptState, wrapper.As<v8::Object>(), V8H
iddenValue::readableStreamReaderInResponse(scriptState->isolate()), reader.v8Val
ue()); |
| 171 } | 176 } |
| 172 return response; | 177 return response; |
| 173 } | 178 } |
| 174 | 179 |
| 175 Response* Response::create(ScriptState* scriptState, PassOwnPtr<FetchDataConsume
rHandle> bodyHandle, const String& contentType, const ResponseInit& init, Except
ionState& exceptionState) | 180 Response* Response::create(ScriptState* scriptState, BodyStreamBuffer* body, con
st String& contentType, const ResponseInit& init, ExceptionState& exceptionState
) |
| 176 { | 181 { |
| 177 unsigned short status = init.status; | 182 unsigned short status = init.status; |
| 178 | 183 |
| 179 // "1. If |init|'s status member is not in the range 200 to 599, inclusive,
throw a | 184 // "1. If |init|'s status member is not in the range 200 to 599, inclusive,
throw a |
| 180 // RangeError." | 185 // RangeError." |
| 181 if (status < 200 || 599 < status) { | 186 if (status < 200 || 599 < status) { |
| 182 exceptionState.throwRangeError(ExceptionMessages::indexOutsideRange<unsi
gned>("status", status, 200, ExceptionMessages::InclusiveBound, 599, ExceptionMe
ssages::InclusiveBound)); | 187 exceptionState.throwRangeError(ExceptionMessages::indexOutsideRange<unsi
gned>("status", status, 200, ExceptionMessages::InclusiveBound, 599, ExceptionMe
ssages::InclusiveBound)); |
| 183 return nullptr; | 188 return nullptr; |
| 184 } | 189 } |
| 185 | 190 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 212 } else if (!init.headersDictionary.isUndefinedOrNull()) { | 217 } else if (!init.headersDictionary.isUndefinedOrNull()) { |
| 213 // "1. Empty |r|'s response's header list." | 218 // "1. Empty |r|'s response's header list." |
| 214 r->m_response->headerList()->clearList(); | 219 r->m_response->headerList()->clearList(); |
| 215 // "2. Fill |r|'s Headers object with |init|'s headers member. Rethrow | 220 // "2. Fill |r|'s Headers object with |init|'s headers member. Rethrow |
| 216 // any exceptions." | 221 // any exceptions." |
| 217 r->m_headers->fillWith(init.headersDictionary, exceptionState); | 222 r->m_headers->fillWith(init.headersDictionary, exceptionState); |
| 218 if (exceptionState.hadException()) | 223 if (exceptionState.hadException()) |
| 219 return nullptr; | 224 return nullptr; |
| 220 } | 225 } |
| 221 // "7. If body is given, run these substeps:" | 226 // "7. If body is given, run these substeps:" |
| 222 if (bodyHandle) { | 227 if (body) { |
| 223 // "1. If |init|'s status member is a null body status, throw a | 228 // "1. If |init|'s status member is a null body status, throw a |
| 224 // TypeError." | 229 // TypeError." |
| 225 // "2. Let |stream| and |Content-Type| be the result of extracting | 230 // "2. Let |stream| and |Content-Type| be the result of extracting |
| 226 // body." | 231 // body." |
| 227 // "3. Set |r|'s response's body to |stream|." | 232 // "3. Set |r|'s response's body to |stream|." |
| 228 // "4. If |Content-Type| is non-null and |r|'s response's header list | 233 // "4. If |Content-Type| is non-null and |r|'s response's header list |
| 229 // contains no header named `Content-Type`, append `Content-Type`/ | 234 // contains no header named `Content-Type`, append `Content-Type`/ |
| 230 // |Content-Type| to |r|'s response's header list." | 235 // |Content-Type| to |r|'s response's header list." |
| 231 // https://fetch.spec.whatwg.org/#concept-bodyinit-extract | 236 // https://fetch.spec.whatwg.org/#concept-bodyinit-extract |
| 232 // Step 3, Blob: | 237 // Step 3, Blob: |
| 233 // "If object's type attribute is not the empty byte sequence, set | 238 // "If object's type attribute is not the empty byte sequence, set |
| 234 // Content-Type to its value." | 239 // Content-Type to its value." |
| 235 if (isNullBodyStatus(status)) { | 240 if (isNullBodyStatus(status)) { |
| 236 exceptionState.throwTypeError("Response with null body status cannot
have body"); | 241 exceptionState.throwTypeError("Response with null body status cannot
have body"); |
| 237 return nullptr; | 242 return nullptr; |
| 238 } | 243 } |
| 239 r->m_response->replaceBodyStreamBuffer(new BodyStreamBuffer(scriptState,
std::move(bodyHandle))); | 244 r->m_response->replaceBodyStreamBuffer(body); |
| 240 if (!contentType.isEmpty() && !r->m_response->headerList()->has("Content
-Type")) | 245 if (!contentType.isEmpty() && !r->m_response->headerList()->has("Content
-Type")) |
| 241 r->m_response->headerList()->append("Content-Type", contentType); | 246 r->m_response->headerList()->append("Content-Type", contentType); |
| 242 } | 247 } |
| 243 | 248 |
| 244 // "8. Set |r|'s MIME type to the result of extracting a MIME type | 249 // "8. Set |r|'s MIME type to the result of extracting a MIME type |
| 245 // from |r|'s response's header list." | 250 // from |r|'s response's header list." |
| 246 r->m_response->setMIMEType(r->m_response->headerList()->extractMIMEType()); | 251 r->m_response->setMIMEType(r->m_response->headerList()->extractMIMEType()); |
| 247 | 252 |
| 248 // "9. Return |r|." | 253 // "9. Return |r|." |
| 249 return r; | 254 return r; |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 } | 417 } |
| 413 | 418 |
| 414 DEFINE_TRACE(Response) | 419 DEFINE_TRACE(Response) |
| 415 { | 420 { |
| 416 Body::trace(visitor); | 421 Body::trace(visitor); |
| 417 visitor->trace(m_response); | 422 visitor->trace(m_response); |
| 418 visitor->trace(m_headers); | 423 visitor->trace(m_headers); |
| 419 } | 424 } |
| 420 | 425 |
| 421 } // namespace blink | 426 } // namespace blink |
| OLD | NEW |