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