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
3 // found in the LICENSE file.
8 #include "bindings/core/v8/Dictionary.h"
9 #include "bindings/core/v8/ExceptionState.h"
10 #include "core/dom/DOMArrayBuffer.h"
11 #include "core/dom/DOMArrayBufferView.h"
12 #include "core/fileapi/Blob.h"
13 #include "modules/serviceworkers/ResponseInit.h"
14 #include "public/platform/WebServiceWorkerResponse.h"
15 #include "wtf/RefPtr.h"
21 FetchResponseData* createFetchResponseDataFromWebResponse(const WebServiceWorkerResponse& webResponse)
23 FetchResponseData* response = 0;
24 if (200 <= webResponse.status() && webResponse.status() < 300)
25 response = FetchResponseData::create();
27 response = FetchResponseData::createNetworkErrorResponse();
29 response->setURL(webResponse.url());
30 response->setStatus(webResponse.status());
31 response->setStatusMessage(webResponse.statusText());
33 for (HTTPHeaderMap::const_iterator i = webResponse.headers().begin(), end = webResponse.headers().end(); i != end; ++i) {
34 response->headerList()->append(i->key, i->value);
37 response->setBlobDataHandle(webResponse.blobDataHandle());
39 // Filter the response according to |webResponse|'s ResponseType.
40 switch (webResponse.responseType()) {
41 case WebServiceWorkerResponseTypeBasic:
42 response = response->createBasicFilteredResponse();
44 case WebServiceWorkerResponseTypeCORS:
45 response = response->createCORSFilteredResponse();
47 case WebServiceWorkerResponseTypeOpaque:
48 response = response->createOpaqueFilteredResponse();
50 case WebServiceWorkerResponseTypeDefault:
52 case WebServiceWorkerResponseTypeError:
53 ASSERT(response->type() == FetchResponseData::ErrorType);
62 Response* Response::create(ExecutionContext* context, Blob* body, const Dictionary& responseInit, ExceptionState& exceptionState)
64 return create(context, body, ResponseInit(responseInit, exceptionState), exceptionState);
67 Response* Response::create(ExecutionContext* context, const String& body, const Dictionary& responseInit, ExceptionState& exceptionState)
69 OwnPtr<BlobData> blobData = BlobData::create();
70 blobData->appendText(body, false);
71 // "Set |Content-Type| to `text/plain;charset=UTF-8`."
72 blobData->setContentType("text/plain;charset=UTF-8");
73 const long long length = blobData->length();
74 Blob* blob = Blob::create(BlobDataHandle::create(blobData.release(), length));
75 return create(context, blob, ResponseInit(responseInit, exceptionState), exceptionState);
78 Response* Response::create(ExecutionContext* context, const DOMArrayBuffer* body, const Dictionary& responseInit, ExceptionState& exceptionState)
80 OwnPtr<BlobData> blobData = BlobData::create();
81 blobData->appendArrayBuffer(body->buffer());
82 const long long length = blobData->length();
83 Blob* blob = Blob::create(BlobDataHandle::create(blobData.release(), length));
84 return create(context, blob, ResponseInit(responseInit, exceptionState), exceptionState);
87 Response* Response::create(ExecutionContext* context, const DOMArrayBufferView* body, const Dictionary& responseInit, ExceptionState& exceptionState)
89 OwnPtr<BlobData> blobData = BlobData::create();
90 blobData->appendArrayBufferView(body->view());
91 const long long length = blobData->length();
92 Blob* blob = Blob::create(BlobDataHandle::create(blobData.release(), length));
93 return create(context, blob, ResponseInit(responseInit, exceptionState), exceptionState);
96 Response* Response::create(ExecutionContext* context, Blob* body, const ResponseInit& responseInit, ExceptionState& exceptionState)
98 // "1. If |init|'s status member is not in the range 200 to 599, throw a
100 if (responseInit.status < 200 || 599 < responseInit.status) {
101 exceptionState.throwRangeError("Invalid status");
105 // FIXME: "2. If |init|'s statusText member does not match the Reason-Phrase
106 // token production, throw a TypeError."
108 // "3. Let |r| be a new Response object, associated with a new response,
109 // Headers object, and Body object."
110 Response* r = new Response(context);
111 r->suspendIfNeeded();
113 // "4. Set |r|'s response's status to |init|'s status member."
114 r->m_response->setStatus(responseInit.status);
116 // "5. Set |r|'s response's status message to |init|'s statusText member."
117 r->m_response->setStatusMessage(AtomicString(responseInit.statusText));
119 // "6. If |init|'s headers member is present, run these substeps:"
120 if (responseInit.headers) {
121 // "1. Empty |r|'s response's header list."
122 r->m_response->headerList()->clearList();
123 // "2. Fill |r|'s Headers object with |init|'s headers member. Rethrow
125 r->m_headers->fillWith(responseInit.headers.get(), exceptionState);
126 if (exceptionState.hadException())
128 } else if (!responseInit.headersDictionary.isUndefinedOrNull()) {
129 // "1. Empty |r|'s response's header list."
130 r->m_response->headerList()->clearList();
131 // "2. Fill |r|'s Headers object with |init|'s headers member. Rethrow
133 r->m_headers->fillWith(responseInit.headersDictionary, exceptionState);
134 if (exceptionState.hadException())
137 // "7. If body is given, run these substeps:"
139 // "1. Let |stream| and |Content-Type| be the result of extracting body."
140 // "2. Set |r|'s response's body to |stream|."
141 // "3. If |Content-Type| is non-null and |r|'s response's header list
142 // contains no header named `Content-Type`, append `Content-Type`/
143 // |Content-Type| to |r|'s response's header list."
144 r->m_response->setBlobDataHandle(body->blobDataHandle());
145 if (!body->type().isNull() && !r->m_response->headerList()->has("Content-Type"))
146 r->m_response->headerList()->append("Content-Type", body->type());
149 // FIXME: "8. Set |r|'s MIME type to the result of extracting a MIME type
150 // from |r|'s response's header list."
156 Response* Response::create(ExecutionContext* context, FetchResponseData* response)
158 Response* r = new Response(context, response);
159 r->suspendIfNeeded();
163 Response* Response::create(ExecutionContext* context, const WebServiceWorkerResponse& webResponse)
165 FetchResponseData* responseData = createFetchResponseDataFromWebResponse(webResponse);
166 Response* r = new Response(context, responseData);
167 r->suspendIfNeeded();
171 Response* Response::create(const Response& copyFrom)
173 Response* r = new Response(copyFrom);
174 r->suspendIfNeeded();
178 String Response::type() const
180 // "The type attribute's getter must return response's type."
181 switch (m_response->type()) {
182 case FetchResponseData::BasicType:
184 case FetchResponseData::CORSType:
186 case FetchResponseData::DefaultType:
188 case FetchResponseData::ErrorType:
190 case FetchResponseData::OpaqueType:
193 ASSERT_NOT_REACHED();
197 String Response::url() const
199 // "The url attribute's getter must return the empty string if response's
200 // url is null and response's url, serialized with the exclude fragment
201 // flag set, otherwise."
202 if (!m_response->url().hasFragmentIdentifier())
203 return m_response->url();
204 KURL url(m_response->url());
205 url.removeFragmentIdentifier();
209 unsigned short Response::status() const
211 // "The status attribute's getter must return response's status."
212 return m_response->status();
215 String Response::statusText() const
217 // "The statusText attribute's getter must return response's status message."
218 return m_response->statusMessage();
221 Headers* Response::headers() const
223 // "The headers attribute's getter must return the associated Headers object."
227 Response* Response::clone() const
229 return Response::create(*this);
232 void Response::populateWebServiceWorkerResponse(WebServiceWorkerResponse& response)
234 m_response->populateWebServiceWorkerResponse(response);
237 Response::Response(ExecutionContext* context)
239 , m_response(FetchResponseData::create())
240 , m_headers(Headers::create(m_response->headerList()))
242 m_headers->setGuard(Headers::ResponseGuard);
245 Response::Response(const Response& copy_from)
247 , m_response(copy_from.m_response)
248 , m_headers(copy_from.m_headers->createCopy())
252 Response::Response(ExecutionContext* context, FetchResponseData* response)
254 , m_response(response)
255 , m_headers(Headers::create(m_response->headerList()))
257 m_headers->setGuard(Headers::ResponseGuard);
261 PassRefPtr<BlobDataHandle> Response::blobDataHandle()
263 return m_response->blobDataHandle();
266 void Response::trace(Visitor* visitor)
268 Body::trace(visitor);
269 visitor->trace(m_response);
270 visitor->trace(m_headers);