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 17 namespace blink { 18 19 namespace { 20 21 FetchResponseData* 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 35 Headers* 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 49 Response* Response::create(ExecutionContext* context, Blob* body, const Dictionary& responseInit, ExceptionState& exceptionState) 50 { 51 return create(context, body, ResponseInit(responseInit), exceptionState); 52 } 53 54 Response* 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 65 Response* 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 74 Response* 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 83 Response* 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 143 Response* Response::create(ExecutionContext* context, FetchResponseData* response) 144 { 145 Response* r = new Response(context, response); 146 r->suspendIfNeeded(); 147 return r; 148 } 149 150 Response* Response::create(ExecutionContext* context, const WebServiceWorkerResponse& webResponse) 151 { 152 Response* r = new Response(context, webResponse); 153 r->suspendIfNeeded(); 154 return r; 155 } 156 157 Response* Response::create(const Response& copyFrom) 158 { 159 Response* r = new Response(copyFrom); 160 r->suspendIfNeeded(); 161 return r; 162 } 163 164 String 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 183 String 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 195 unsigned short Response::status() const 196 { 197 // "The status attribute's getter must return response's status." 198 return m_response->status(); 199 } 200 201 String Response::statusText() const 202 { 203 // "The statusText attribute's getter must return response's status message." 204 return m_response->statusMessage(); 205 } 206 207 Headers* Response::headers() const 208 { 209 // "The headers attribute's getter must return the associated Headers object." 210 return m_headers; 211 } 212 213 Response* Response::clone() const 214 { 215 return Response::create(*this); 216 } 217 218 void Response::populateWebServiceWorkerResponse(WebServiceWorkerResponse& response) 219 { 220 m_response->populateWebServiceWorkerResponse(response); 221 } 222 223 Response::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 231 Response::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 238 Response::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. 247 Response::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 255 PassRefPtr<BlobDataHandle> Response::blobDataHandle() 256 { 257 return m_response->blobDataHandle(); 258 } 259 260 void 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