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 "modules/serviceworkers/RespondWithObserver.h"
      7 
      8 #include "bindings/core/v8/ScriptFunction.h"
      9 #include "bindings/core/v8/ScriptPromise.h"
     10 #include "bindings/core/v8/ScriptValue.h"
     11 #include "bindings/core/v8/V8Binding.h"
     12 #include "bindings/modules/v8/V8Response.h"
     13 #include "core/dom/ExecutionContext.h"
     14 #include "modules/serviceworkers/ServiceWorkerGlobalScopeClient.h"
     15 #include "platform/RuntimeEnabledFeatures.h"
     16 #include "public/platform/WebServiceWorkerResponse.h"
     17 #include "wtf/Assertions.h"
     18 #include "wtf/RefPtr.h"
     19 #include <v8.h>
     20 
     21 namespace blink {
     22 
     23 class RespondWithObserver::ThenFunction FINAL : public ScriptFunction {
     24 public:
     25     enum ResolveType {
     26         Fulfilled,
     27         Rejected,
     28     };
     29 
     30     static v8::Handle<v8::Function> createFunction(ScriptState* scriptState, RespondWithObserver* observer, ResolveType type)
     31     {
     32         ThenFunction* self = new ThenFunction(scriptState, observer, type);
     33         return self->bindToV8Function();
     34     }
     35 
     36     virtual void trace(Visitor* visitor) OVERRIDE
     37     {
     38         visitor->trace(m_observer);
     39         ScriptFunction::trace(visitor);
     40     }
     41 
     42 private:
     43     ThenFunction(ScriptState* scriptState, RespondWithObserver* observer, ResolveType type)
     44         : ScriptFunction(scriptState)
     45         , m_observer(observer)
     46         , m_resolveType(type)
     47     {
     48     }
     49 
     50     virtual ScriptValue call(ScriptValue value) OVERRIDE
     51     {
     52         ASSERT(m_observer);
     53         ASSERT(m_resolveType == Fulfilled || m_resolveType == Rejected);
     54         if (m_resolveType == Rejected)
     55             m_observer->responseWasRejected();
     56         else
     57             m_observer->responseWasFulfilled(value);
     58         m_observer = nullptr;
     59         return value;
     60     }
     61 
     62     Member<RespondWithObserver> m_observer;
     63     ResolveType m_resolveType;
     64 };
     65 
     66 RespondWithObserver* RespondWithObserver::create(ExecutionContext* context, int eventID)
     67 {
     68     return new RespondWithObserver(context, eventID);
     69 }
     70 
     71 void RespondWithObserver::contextDestroyed()
     72 {
     73     ContextLifecycleObserver::contextDestroyed();
     74     m_state = Done;
     75 }
     76 
     77 void RespondWithObserver::didDispatchEvent()
     78 {
     79     ASSERT(executionContext());
     80     if (m_state != Initial)
     81         return;
     82     ServiceWorkerGlobalScopeClient::from(executionContext())->didHandleFetchEvent(m_eventID);
     83     m_state = Done;
     84 }
     85 
     86 void RespondWithObserver::respondWith(ScriptState* scriptState, const ScriptValue& value, ExceptionState& exceptionState)
     87 {
     88     ASSERT(RuntimeEnabledFeatures::serviceWorkerOnFetchEnabled());
     89     if (m_state != Initial) {
     90         exceptionState.throwDOMException(InvalidStateError, "respondWith is already called.");
     91         return;
     92     }
     93 
     94     m_state = Pending;
     95     ScriptPromise::cast(scriptState, value).then(
     96         ThenFunction::createFunction(scriptState, this, ThenFunction::Fulfilled),
     97         ThenFunction::createFunction(scriptState, this, ThenFunction::Rejected));
     98 }
     99 
    100 void RespondWithObserver::responseWasRejected()
    101 {
    102     ASSERT(executionContext());
    103     // The default value of WebServiceWorkerResponse's status is 0, which maps
    104     // to a network error.
    105     WebServiceWorkerResponse webResponse;
    106     ServiceWorkerGlobalScopeClient::from(executionContext())->didHandleFetchEvent(m_eventID, webResponse);
    107     m_state = Done;
    108 }
    109 
    110 void RespondWithObserver::responseWasFulfilled(const ScriptValue& value)
    111 {
    112     ASSERT(executionContext());
    113     if (!V8Response::hasInstance(value.v8Value(), toIsolate(executionContext()))) {
    114         responseWasRejected();
    115         return;
    116     }
    117     WebServiceWorkerResponse webResponse;
    118     V8Response::toImplWithTypeCheck(toIsolate(executionContext()), value.v8Value())->populateWebServiceWorkerResponse(webResponse);
    119     ServiceWorkerGlobalScopeClient::from(executionContext())->didHandleFetchEvent(m_eventID, webResponse);
    120     m_state = Done;
    121 }
    122 
    123 RespondWithObserver::RespondWithObserver(ExecutionContext* context, int eventID)
    124     : ContextLifecycleObserver(context)
    125     , m_eventID(eventID)
    126     , m_state(Initial)
    127 {
    128 }
    129 
    130 } // namespace blink
    131