Home | History | Annotate | Download | only in serviceworkers
      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