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. 4 5#include "config.h" 6#include "Response.h" 7 8#include "bindings/core/v8/Dictionary.h" 9#include "bindings/core/v8/ExceptionState.h" 10#include "core/fileapi/Blob.h" 11#include "modules/serviceworkers/ResponseInit.h" 12#include "public/platform/WebServiceWorkerResponse.h" 13#include "wtf/ArrayBuffer.h" 14#include "wtf/ArrayBufferView.h" 15#include "wtf/RefPtr.h" 16 17namespace blink { 18 19namespace { 20 21FetchResponseData* createFetchResponseDataFromWebResponse(const WebServiceWorkerResponse& webResponse) 22{ 23 FetchResponseData* response = 0; 24 if (200 <= webResponse.status() && webResponse.status() < 300) 25 response = FetchResponseData::create(); 26 else 27 response = FetchResponseData::createNetworkErrorResponse(); 28 29 response->setURL(webResponse.url()); 30 response->setStatus(webResponse.status()); 31 response->setStatusMessage(webResponse.statusText()); 32 return response; 33} 34 35Headers* createHeadersFromWebResponse(const WebServiceWorkerResponse& webResponse) 36{ 37 Headers* headers = Headers::create(); 38 TrackExceptionState exceptionState; 39 for (HTTPHeaderMap::const_iterator i = webResponse.headers().begin(), end = webResponse.headers().end(); i != end; ++i) { 40 headers->append(i->key, i->value, exceptionState); 41 if (exceptionState.hadException()) 42 return 0; 43 } 44 return headers; 45} 46 47} 48 49Response* Response::create(ExecutionContext* context, Blob* body, const Dictionary& responseInit, ExceptionState& exceptionState) 50{ 51 return create(context, body, ResponseInit(responseInit), exceptionState); 52} 53 54Response* Response::create(ExecutionContext* context, const String& body, const Dictionary& responseInit, ExceptionState& exceptionState) 55{ 56 OwnPtr<BlobData> blobData = BlobData::create(); 57 blobData->appendText(body, false); 58 // "Set |Content-Type| to `text/plain;charset=UTF-8`." 59 blobData->setContentType("text/plain;charset=UTF-8"); 60 const long long length = blobData->length(); 61 RefPtrWillBeRawPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData.release(), length)); 62 return create(context, blob.get(), ResponseInit(responseInit), exceptionState); 63} 64 65Response* Response::create(ExecutionContext* context, const ArrayBuffer* body, const Dictionary& responseInit, ExceptionState& exceptionState) 66{ 67 OwnPtr<BlobData> blobData = BlobData::create(); 68 blobData->appendArrayBuffer(body); 69 const long long length = blobData->length(); 70 RefPtrWillBeRawPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData.release(), length)); 71 return create(context, blob.get(), ResponseInit(responseInit), exceptionState); 72} 73 74Response* Response::create(ExecutionContext* context, const ArrayBufferView* body, const Dictionary& responseInit, ExceptionState& exceptionState) 75{ 76 OwnPtr<BlobData> blobData = BlobData::create(); 77 blobData->appendArrayBufferView(body); 78 const long long length = blobData->length(); 79 RefPtrWillBeRawPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData.release(), length)); 80 return create(context, blob.get(), ResponseInit(responseInit), exceptionState); 81} 82 83Response* Response::create(ExecutionContext* context, Blob* body, const ResponseInit& responseInit, ExceptionState& exceptionState) 84{ 85 // "1. If |init|'s status member is not in the range 200 to 599, throw a 86 // RangeError." 87 if (responseInit.status < 200 || 599 < responseInit.status) { 88 exceptionState.throwRangeError("Invalid status"); 89 return 0; 90 } 91 92 // FIXME: "2. If |init|'s statusText member does not match the Reason-Phrase 93 // token production, throw a TypeError." 94 95 // "3. Let |r| be a new Response object, associated with a new response, 96 // Headers object, and Body object." 97 Response* r = new Response(context); 98 r->suspendIfNeeded(); 99 100 // "4. Set |r|'s response's status to |init|'s status member." 101 r->m_response->setStatus(responseInit.status); 102 103 // "5. Set |r|'s response's status message to |init|'s statusText member." 104 r->m_response->setStatusMessage(AtomicString(responseInit.statusText)); 105 106 // "6. If |init|'s headers member is present, run these substeps:" 107 if (responseInit.headers) { 108 // "1. Empty |r|'s response's header list." 109 r->m_response->headerList()->clearList(); 110 // "2. Fill |r|'s Headers object with |init|'s headers member. Rethrow 111 // any exceptions." 112 r->m_headers->fillWith(responseInit.headers.get(), exceptionState); 113 if (exceptionState.hadException()) 114 return 0; 115 } else if (!responseInit.headersDictionary.isUndefinedOrNull()) { 116 // "1. Empty |r|'s response's header list." 117 r->m_response->headerList()->clearList(); 118 // "2. Fill |r|'s Headers object with |init|'s headers member. Rethrow 119 // any exceptions." 120 r->m_headers->fillWith(responseInit.headersDictionary, exceptionState); 121 if (exceptionState.hadException()) 122 return 0; 123 } 124 // "7. If body is given, run these substeps:" 125 if (body) { 126 // "1. Let |stream| and |Content-Type| be the result of extracting body." 127 // "2. Set |r|'s response's body to |stream|." 128 // "3. If |Content-Type| is non-null and |r|'s response's header list 129 // contains no header named `Content-Type`, append `Content-Type`/ 130 // |Content-Type| to |r|'s response's header list." 131 r->m_response->setBlobDataHandle(body->blobDataHandle()); 132 if (!body->type().isNull() && !r->m_response->headerList()->has("Content-Type")) 133 r->m_response->headerList()->append("Content-Type", body->type()); 134 } 135 136 // FIXME: "8. Set |r|'s MIME type to the result of extracting a MIME type 137 // from |r|'s response's header list." 138 139 // "9. Return |r|." 140 return r; 141} 142 143Response* Response::create(ExecutionContext* context, FetchResponseData* response) 144{ 145 Response* r = new Response(context, response); 146 r->suspendIfNeeded(); 147 return r; 148} 149 150Response* Response::create(ExecutionContext* context, const WebServiceWorkerResponse& webResponse) 151{ 152 Response* r = new Response(context, webResponse); 153 r->suspendIfNeeded(); 154 return r; 155} 156 157Response* Response::create(const Response& copyFrom) 158{ 159 Response* r = new Response(copyFrom); 160 r->suspendIfNeeded(); 161 return r; 162} 163 164String Response::type() const 165{ 166 // "The type attribute's getter must return response's type." 167 switch (m_response->type()) { 168 case FetchResponseData::BasicType: 169 return "basic"; 170 case FetchResponseData::CORSType: 171 return "cors"; 172 case FetchResponseData::DefaultType: 173 return "default"; 174 case FetchResponseData::ErrorType: 175 return "error"; 176 case FetchResponseData::OpaqueType: 177 return "opaque"; 178 } 179 ASSERT_NOT_REACHED(); 180 return ""; 181} 182 183String Response::url() const 184{ 185 // "The url attribute's getter must return the empty string if response's 186 // url is null and response's url, serialized with the exclude fragment 187 // flag set, otherwise." 188 if (!m_response->url().hasFragmentIdentifier()) 189 return m_response->url(); 190 KURL url(m_response->url()); 191 url.removeFragmentIdentifier(); 192 return url; 193} 194 195unsigned short Response::status() const 196{ 197 // "The status attribute's getter must return response's status." 198 return m_response->status(); 199} 200 201String Response::statusText() const 202{ 203 // "The statusText attribute's getter must return response's status message." 204 return m_response->statusMessage(); 205} 206 207Headers* Response::headers() const 208{ 209 // "The headers attribute's getter must return the associated Headers object." 210 return m_headers; 211} 212 213Response* Response::clone() const 214{ 215 return Response::create(*this); 216} 217 218void Response::populateWebServiceWorkerResponse(WebServiceWorkerResponse& response) 219{ 220 m_response->populateWebServiceWorkerResponse(response); 221} 222 223Response::Response(ExecutionContext* context) 224 : Body(context) 225 , m_response(FetchResponseData::create()) 226 , m_headers(Headers::create(m_response->headerList())) 227{ 228 m_headers->setGuard(Headers::ResponseGuard); 229} 230 231Response::Response(const Response& copy_from) 232 : Body(copy_from) 233 , m_response(copy_from.m_response) 234 , m_headers(copy_from.m_headers->createCopy()) 235{ 236} 237 238Response::Response(ExecutionContext* context, FetchResponseData* response) 239 : Body(context) 240 , m_response(response) 241 , m_headers(Headers::create(m_response->headerList())) 242{ 243 m_headers->setGuard(Headers::ResponseGuard); 244} 245 246// FIXME: Handle response body data. 247Response::Response(ExecutionContext* context, const WebServiceWorkerResponse& webResponse) 248 : Body(context) 249 , m_response(createFetchResponseDataFromWebResponse(webResponse)) 250 , m_headers(createHeadersFromWebResponse(webResponse)) 251{ 252 m_headers->setGuard(Headers::ResponseGuard); 253} 254 255PassRefPtr<BlobDataHandle> Response::blobDataHandle() 256{ 257 return m_response->blobDataHandle(); 258} 259 260void Response::trace(Visitor* visitor) 261{ 262 Body::trace(visitor); 263 visitor->trace(m_response); 264 visitor->trace(m_headers); 265} 266 267} // namespace blink 268