| 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 "config.h" | 5 #include "config.h" |
| 6 #include "modules/fetch/Response.h" | 6 #include "modules/fetch/Response.h" |
| 7 | 7 |
| 8 #include "bindings/core/v8/Dictionary.h" | 8 #include "bindings/core/v8/Dictionary.h" |
| 9 #include "bindings/core/v8/ExceptionState.h" | 9 #include "bindings/core/v8/ExceptionState.h" |
| 10 #include "core/dom/DOMArrayBuffer.h" | 10 #include "core/dom/DOMArrayBuffer.h" |
| 11 #include "core/dom/DOMArrayBufferView.h" | 11 #include "core/dom/DOMArrayBufferView.h" |
| 12 #include "core/fileapi/Blob.h" | 12 #include "core/fileapi/Blob.h" |
| 13 #include "core/html/DOMFormData.h" | 13 #include "core/html/DOMFormData.h" |
| 14 #include "modules/fetch/BodyStreamBuffer.h" | 14 #include "modules/fetch/BodyStreamBuffer.h" |
| 15 #include "modules/fetch/FetchBlobDataConsumerHandle.h" | 15 #include "modules/fetch/FetchBlobDataConsumerHandle.h" |
| 16 #include "modules/fetch/ResponseInit.h" | 16 #include "modules/fetch/ResponseInit.h" |
| 17 #include "platform/network/FormData.h" | 17 #include "platform/network/FormData.h" |
| 18 #include "platform/network/HTTPHeaderMap.h" | 18 #include "platform/network/HTTPHeaderMap.h" |
| 19 #include "public/platform/WebServiceWorkerResponse.h" | 19 #include "public/platform/WebServiceWorkerResponse.h" |
| 20 #include "wtf/RefPtr.h" | 20 #include "wtf/RefPtr.h" |
| 21 | 21 |
| 22 namespace blink { | 22 namespace blink { |
| 23 | 23 |
| 24 namespace { | 24 namespace { |
| 25 | 25 |
| 26 FetchResponseData* createFetchResponseDataFromWebResponse(ExecutionContext* exec
utionContext, const WebServiceWorkerResponse& webResponse) | 26 FetchResponseData* createFetchResponseDataFromWebResponse(ExecutionContext* exec
utionContext, const WebServiceWorkerResponse& webResponse) |
| 27 { | 27 { |
| 28 FetchResponseData* response = 0; | 28 FetchResponseData* response = nullptr; |
| 29 if (webResponse.status() > 0) | 29 if (webResponse.status() > 0) |
| 30 response = FetchResponseData::create(); | 30 response = FetchResponseData::create(); |
| 31 else | 31 else |
| 32 response = FetchResponseData::createNetworkErrorResponse(); | 32 response = FetchResponseData::createNetworkErrorResponse(); |
| 33 | 33 |
| 34 response->setURL(webResponse.url()); | 34 response->setURL(webResponse.url()); |
| 35 response->setStatus(webResponse.status()); | 35 response->setStatus(webResponse.status()); |
| 36 response->setStatusMessage(webResponse.statusText()); | 36 response->setStatusMessage(webResponse.statusText()); |
| 37 | 37 |
| 38 for (HTTPHeaderMap::const_iterator i = webResponse.headers().begin(), end =
webResponse.headers().end(); i != end; ++i) { | 38 for (HTTPHeaderMap::const_iterator i = webResponse.headers().begin(), end =
webResponse.headers().end(); i != end; ++i) { |
| 39 response->headerList()->append(i->key, i->value); | 39 response->headerList()->append(i->key, i->value); |
| 40 } | 40 } |
| 41 | 41 |
| 42 response->replaceBodyStreamBuffer(BodyStreamBuffer::create(FetchBlobDataCons
umerHandle::create(executionContext, webResponse.blobDataHandle()))); | 42 response->replaceBodyStreamBuffer(new BodyStreamBuffer(FetchBlobDataConsumer
Handle::create(executionContext, webResponse.blobDataHandle()))); |
| 43 | 43 |
| 44 // Filter the response according to |webResponse|'s ResponseType. | 44 // Filter the response according to |webResponse|'s ResponseType. |
| 45 switch (webResponse.responseType()) { | 45 switch (webResponse.responseType()) { |
| 46 case WebServiceWorkerResponseTypeBasic: | 46 case WebServiceWorkerResponseTypeBasic: |
| 47 response = response->createBasicFilteredResponse(); | 47 response = response->createBasicFilteredResponse(); |
| 48 break; | 48 break; |
| 49 case WebServiceWorkerResponseTypeCORS: | 49 case WebServiceWorkerResponseTypeCORS: |
| 50 response = response->createCORSFilteredResponse(); | 50 response = response->createCORSFilteredResponse(); |
| 51 break; | 51 break; |
| 52 case WebServiceWorkerResponseTypeOpaque: | 52 case WebServiceWorkerResponseTypeOpaque: |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 // "2. If |init|'s statusText member does not match the Reason-Phrase | 163 // "2. If |init|'s statusText member does not match the Reason-Phrase |
| 164 // token production, throw a TypeError." | 164 // token production, throw a TypeError." |
| 165 if (!isValidReasonPhrase(responseInit.statusText)) { | 165 if (!isValidReasonPhrase(responseInit.statusText)) { |
| 166 exceptionState.throwTypeError("Invalid statusText"); | 166 exceptionState.throwTypeError("Invalid statusText"); |
| 167 return 0; | 167 return 0; |
| 168 } | 168 } |
| 169 | 169 |
| 170 // "3. Let |r| be a new Response object, associated with a new response, | 170 // "3. Let |r| be a new Response object, associated with a new response, |
| 171 // Headers object, and Body object." | 171 // Headers object, and Body object." |
| 172 Response* r = new Response(context); | 172 Response* r = new Response(context); |
| 173 r->suspendIfNeeded(); | |
| 174 | 173 |
| 175 // "4. Set |r|'s response's status to |init|'s status member." | 174 // "4. Set |r|'s response's status to |init|'s status member." |
| 176 r->m_response->setStatus(responseInit.status); | 175 r->m_response->setStatus(responseInit.status); |
| 177 | 176 |
| 178 // "5. Set |r|'s response's status message to |init|'s statusText member." | 177 // "5. Set |r|'s response's status message to |init|'s statusText member." |
| 179 r->m_response->setStatusMessage(AtomicString(responseInit.statusText)); | 178 r->m_response->setStatusMessage(AtomicString(responseInit.statusText)); |
| 180 | 179 |
| 181 // "6. If |init|'s headers member is present, run these substeps:" | 180 // "6. If |init|'s headers member is present, run these substeps:" |
| 182 if (responseInit.headers) { | 181 if (responseInit.headers) { |
| 183 // "1. Empty |r|'s response's header list." | 182 // "1. Empty |r|'s response's header list." |
| (...skipping 16 matching lines...) Expand all Loading... |
| 200 if (body) { | 199 if (body) { |
| 201 // "1. Let |stream| and |Content-Type| be the result of extracting body.
" | 200 // "1. Let |stream| and |Content-Type| be the result of extracting body.
" |
| 202 // "2. Set |r|'s response's body to |stream|." | 201 // "2. Set |r|'s response's body to |stream|." |
| 203 // "3. If |Content-Type| is non-null and |r|'s response's header list | 202 // "3. If |Content-Type| is non-null and |r|'s response's header list |
| 204 // contains no header named `Content-Type`, append `Content-Type`/ | 203 // contains no header named `Content-Type`, append `Content-Type`/ |
| 205 // |Content-Type| to |r|'s response's header list." | 204 // |Content-Type| to |r|'s response's header list." |
| 206 // https://fetch.spec.whatwg.org/#concept-bodyinit-extract | 205 // https://fetch.spec.whatwg.org/#concept-bodyinit-extract |
| 207 // Step 3, Blob: | 206 // Step 3, Blob: |
| 208 // "If object's type attribute is not the empty byte sequence, set | 207 // "If object's type attribute is not the empty byte sequence, set |
| 209 // Content-Type to its value." | 208 // Content-Type to its value." |
| 210 r->m_response->replaceBodyStreamBuffer(BodyStreamBuffer::create(FetchBlo
bDataConsumerHandle::create(context, body->blobDataHandle()))); | 209 r->m_response->replaceBodyStreamBuffer(new BodyStreamBuffer(FetchBlobDat
aConsumerHandle::create(context, body->blobDataHandle()))); |
| 211 r->refreshBody(); | |
| 212 if (!body->type().isEmpty() && !r->m_response->headerList()->has("Conten
t-Type")) | 210 if (!body->type().isEmpty() && !r->m_response->headerList()->has("Conten
t-Type")) |
| 213 r->m_response->headerList()->append("Content-Type", body->type()); | 211 r->m_response->headerList()->append("Content-Type", body->type()); |
| 214 } | 212 } |
| 215 | 213 |
| 216 // "8. Set |r|'s MIME type to the result of extracting a MIME type | 214 // "8. Set |r|'s MIME type to the result of extracting a MIME type |
| 217 // from |r|'s response's header list." | 215 // from |r|'s response's header list." |
| 218 r->m_response->setMIMEType(r->m_response->headerList()->extractMIMEType()); | 216 r->m_response->setMIMEType(r->m_response->headerList()->extractMIMEType()); |
| 219 | 217 |
| 220 // "9. Return |r|." | 218 // "9. Return |r|." |
| 221 return r; | 219 return r; |
| 222 } | 220 } |
| 223 | 221 |
| 224 Response* Response::create(ExecutionContext* context, FetchResponseData* respons
e) | 222 Response* Response::create(ExecutionContext* context, FetchResponseData* respons
e) |
| 225 { | 223 { |
| 226 Response* r = new Response(context, response); | 224 return new Response(context, response); |
| 227 r->suspendIfNeeded(); | |
| 228 return r; | |
| 229 } | 225 } |
| 230 | 226 |
| 231 Response* Response::create(ExecutionContext* context, const WebServiceWorkerResp
onse& webResponse) | 227 Response* Response::create(ExecutionContext* context, const WebServiceWorkerResp
onse& webResponse) |
| 232 { | 228 { |
| 233 FetchResponseData* responseData = createFetchResponseDataFromWebResponse(con
text, webResponse); | 229 FetchResponseData* responseData = createFetchResponseDataFromWebResponse(con
text, webResponse); |
| 234 Response* r = new Response(context, responseData); | 230 return new Response(context, responseData); |
| 235 r->suspendIfNeeded(); | |
| 236 return r; | |
| 237 } | 231 } |
| 238 | 232 |
| 239 Response* Response::error(ExecutionContext* context) | 233 Response* Response::error(ExecutionContext* context) |
| 240 { | 234 { |
| 241 FetchResponseData* responseData = FetchResponseData::createNetworkErrorRespo
nse(); | 235 FetchResponseData* responseData = FetchResponseData::createNetworkErrorRespo
nse(); |
| 242 Response* r = new Response(context, responseData); | 236 Response* r = new Response(context, responseData); |
| 243 r->m_headers->setGuard(Headers::ImmutableGuard); | 237 r->m_headers->setGuard(Headers::ImmutableGuard); |
| 244 r->suspendIfNeeded(); | |
| 245 return r; | 238 return r; |
| 246 } | 239 } |
| 247 | 240 |
| 248 Response* Response::redirect(ExecutionContext* context, const String& url, unsig
ned short status, ExceptionState& exceptionState) | 241 Response* Response::redirect(ExecutionContext* context, const String& url, unsig
ned short status, ExceptionState& exceptionState) |
| 249 { | 242 { |
| 250 KURL parsedURL = context->completeURL(url); | 243 KURL parsedURL = context->completeURL(url); |
| 251 if (!parsedURL.isValid()) { | 244 if (!parsedURL.isValid()) { |
| 252 exceptionState.throwTypeError("Failed to parse URL from " + url); | 245 exceptionState.throwTypeError("Failed to parse URL from " + url); |
| 253 return nullptr; | 246 return nullptr; |
| 254 } | 247 } |
| 255 | 248 |
| 256 if (status != 301 && status != 302 && status != 303 && status != 307 && stat
us != 308) { | 249 if (status != 301 && status != 302 && status != 303 && status != 307 && stat
us != 308) { |
| 257 exceptionState.throwRangeError("Invalid status code"); | 250 exceptionState.throwRangeError("Invalid status code"); |
| 258 return nullptr; | 251 return nullptr; |
| 259 } | 252 } |
| 260 | 253 |
| 261 Response* r = new Response(context); | 254 Response* r = new Response(context); |
| 262 r->suspendIfNeeded(); | |
| 263 r->m_headers->setGuard(Headers::ImmutableGuard); | 255 r->m_headers->setGuard(Headers::ImmutableGuard); |
| 264 r->m_response->setStatus(status); | 256 r->m_response->setStatus(status); |
| 265 r->m_response->headerList()->set("Location", parsedURL); | 257 r->m_response->headerList()->set("Location", parsedURL); |
| 266 | 258 |
| 267 return r; | 259 return r; |
| 268 } | 260 } |
| 269 | 261 |
| 270 String Response::type() const | 262 String Response::type() const |
| 271 { | 263 { |
| 272 // "The type attribute's getter must return response's type." | 264 // "The type attribute's getter must return response's type." |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 return m_headers; | 315 return m_headers; |
| 324 } | 316 } |
| 325 | 317 |
| 326 Response* Response::clone(ExceptionState& exceptionState) | 318 Response* Response::clone(ExceptionState& exceptionState) |
| 327 { | 319 { |
| 328 if (bodyUsed()) { | 320 if (bodyUsed()) { |
| 329 exceptionState.throwTypeError("Response body is already used"); | 321 exceptionState.throwTypeError("Response body is already used"); |
| 330 return nullptr; | 322 return nullptr; |
| 331 } | 323 } |
| 332 | 324 |
| 333 if (OwnPtr<DrainingBodyStreamBuffer> buffer = createDrainingStream()) | |
| 334 m_response->replaceBodyStreamBuffer(buffer->leakBuffer()); | |
| 335 | |
| 336 FetchResponseData* response = m_response->clone(executionContext()); | 325 FetchResponseData* response = m_response->clone(executionContext()); |
| 337 Headers* headers = Headers::create(response->headerList()); | 326 Headers* headers = Headers::create(response->headerList()); |
| 338 headers->setGuard(m_headers->guard()); | 327 headers->setGuard(m_headers->guard()); |
| 339 Response* r = new Response(executionContext(), response, headers); | 328 return new Response(executionContext(), response, headers); |
| 340 r->suspendIfNeeded(); | |
| 341 | |
| 342 // Lock the old body and set |body| property to the new one. | |
| 343 lockBody(); | |
| 344 refreshBody(); | |
| 345 | |
| 346 return r; | |
| 347 } | 329 } |
| 348 | 330 |
| 349 bool Response::hasPendingActivity() const | 331 bool Response::hasPendingActivity() const |
| 350 { | 332 { |
| 351 if (!executionContext() || executionContext()->activeDOMObjectsAreStopped()) | 333 if (!executionContext() || executionContext()->activeDOMObjectsAreStopped()) |
| 352 return false; | 334 return false; |
| 353 if (m_isInternalDrained) | 335 if (internalBodyBuffer()->hasPendingActivity()) |
| 354 return true; | 336 return true; |
| 355 return Body::hasPendingActivity(); | 337 return Body::hasPendingActivity(); |
| 356 } | 338 } |
| 357 | 339 |
| 358 void Response::populateWebServiceWorkerResponse(WebServiceWorkerResponse& respon
se) | 340 void Response::populateWebServiceWorkerResponse(WebServiceWorkerResponse& respon
se) |
| 359 { | 341 { |
| 360 m_response->populateWebServiceWorkerResponse(response); | 342 m_response->populateWebServiceWorkerResponse(response); |
| 361 } | 343 } |
| 362 | 344 |
| 363 Response::Response(ExecutionContext* context) | 345 Response::Response(ExecutionContext* context) |
| 364 : Body(context) | 346 : Body(context) |
| 365 , m_response(FetchResponseData::create()) | 347 , m_response(FetchResponseData::create()) |
| 366 , m_headers(Headers::create(m_response->headerList())) | 348 , m_headers(Headers::create(m_response->headerList())) |
| 367 , m_isInternalDrained(false) | |
| 368 { | 349 { |
| 369 m_headers->setGuard(Headers::ResponseGuard); | 350 m_headers->setGuard(Headers::ResponseGuard); |
| 370 } | 351 } |
| 371 | 352 |
| 372 Response::Response(ExecutionContext* context, FetchResponseData* response) | 353 Response::Response(ExecutionContext* context, FetchResponseData* response) |
| 373 : Body(context) | 354 : Body(context) |
| 374 , m_response(response) | 355 , m_response(response) |
| 375 , m_headers(Headers::create(m_response->headerList())) | 356 , m_headers(Headers::create(m_response->headerList())) |
| 376 , m_isInternalDrained(false) | |
| 377 { | 357 { |
| 378 m_headers->setGuard(Headers::ResponseGuard); | 358 m_headers->setGuard(Headers::ResponseGuard); |
| 379 | |
| 380 refreshBody(); | |
| 381 } | 359 } |
| 382 | 360 |
| 383 Response::Response(ExecutionContext* context, FetchResponseData* response, Heade
rs* headers) | 361 Response::Response(ExecutionContext* context, FetchResponseData* response, Heade
rs* headers) |
| 384 : Body(context) , m_response(response) , m_headers(headers), m_isInternalDra
ined(false) | 362 : Body(context) , m_response(response) , m_headers(headers) {} |
| 385 { | |
| 386 refreshBody(); | |
| 387 } | |
| 388 | 363 |
| 389 bool Response::hasBody() const | 364 bool Response::hasBody() const |
| 390 { | 365 { |
| 391 return m_response->internalBuffer(); | 366 return m_response->internalBuffer()->hasBody(); |
| 392 } | |
| 393 | |
| 394 void* Response::bufferForTest() const | |
| 395 { | |
| 396 return m_response->buffer(); | |
| 397 } | 367 } |
| 398 | 368 |
| 399 String Response::mimeType() const | 369 String Response::mimeType() const |
| 400 { | 370 { |
| 401 return m_response->mimeType(); | 371 return m_response->mimeType(); |
| 402 } | 372 } |
| 403 | 373 |
| 404 void* Response::internalBufferForTest() const | |
| 405 { | |
| 406 return m_response->internalBuffer(); | |
| 407 } | |
| 408 | |
| 409 String Response::internalMIMEType() const | 374 String Response::internalMIMEType() const |
| 410 { | 375 { |
| 411 return m_response->internalMIMEType(); | 376 return m_response->internalMIMEType(); |
| 412 } | 377 } |
| 413 | 378 |
| 414 PassOwnPtr<DrainingBodyStreamBuffer> Response::createInternalDrainingStream() | |
| 415 { | |
| 416 if (BodyStreamBuffer* buffer = m_response->internalBuffer()) { | |
| 417 if (buffer == m_response->buffer()) | |
| 418 return createDrainingStream(); | |
| 419 m_isInternalDrained = true; | |
| 420 return DrainingBodyStreamBuffer::create(buffer, this); | |
| 421 } | |
| 422 return nullptr; | |
| 423 } | |
| 424 | |
| 425 void Response::didFetchDataLoadFinishedFromDrainingStream() | |
| 426 { | |
| 427 ASSERT(m_isInternalDrained); | |
| 428 m_isInternalDrained = false; | |
| 429 } | |
| 430 | |
| 431 void Response::refreshBody() | |
| 432 { | |
| 433 setBody(m_response->buffer()); | |
| 434 } | |
| 435 | |
| 436 DEFINE_TRACE(Response) | 379 DEFINE_TRACE(Response) |
| 437 { | 380 { |
| 438 Body::trace(visitor); | 381 Body::trace(visitor); |
| 439 visitor->trace(m_response); | 382 visitor->trace(m_response); |
| 440 visitor->trace(m_headers); | 383 visitor->trace(m_headers); |
| 441 } | 384 } |
| 442 | 385 |
| 443 } // namespace blink | 386 } // namespace blink |
| OLD | NEW |