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 "V8Response.h" 9 #include "bindings/v8/ScriptFunction.h" 10 #include "bindings/v8/ScriptPromise.h" 11 #include "bindings/v8/ScriptValue.h" 12 #include "bindings/v8/V8Binding.h" 13 #include "core/dom/ExecutionContext.h" 14 #include "modules/serviceworkers/ServiceWorkerGlobalScopeClient.h" 15 #include "wtf/Assertions.h" 16 #include "wtf/RefPtr.h" 17 #include <v8.h> 18 19 namespace WebCore { 20 21 class RespondWithObserver::ThenFunction FINAL : public ScriptFunction { 22 public: 23 enum ResolveType { 24 Fulfilled, 25 Rejected, 26 }; 27 28 static PassOwnPtr<ScriptFunction> create(PassRefPtr<RespondWithObserver> observer, ResolveType type) 29 { 30 ExecutionContext* executionContext = observer->executionContext(); 31 return adoptPtr(new ThenFunction(toIsolate(executionContext), observer, type)); 32 } 33 34 private: 35 ThenFunction(v8::Isolate* isolate, PassRefPtr<RespondWithObserver> observer, ResolveType type) 36 : ScriptFunction(isolate) 37 , m_observer(observer) 38 , m_resolveType(type) 39 { 40 } 41 42 virtual ScriptValue call(ScriptValue value) OVERRIDE 43 { 44 ASSERT(m_observer); 45 ASSERT(m_resolveType == Fulfilled || m_resolveType == Rejected); 46 if (m_resolveType == Rejected) 47 m_observer->responseWasRejected(); 48 else 49 m_observer->responseWasFulfilled(value); 50 m_observer = nullptr; 51 return value; 52 } 53 54 RefPtr<RespondWithObserver> m_observer; 55 ResolveType m_resolveType; 56 }; 57 58 PassRefPtr<RespondWithObserver> RespondWithObserver::create(ExecutionContext* context, int eventID) 59 { 60 return adoptRef(new RespondWithObserver(context, eventID)); 61 } 62 63 RespondWithObserver::~RespondWithObserver() 64 { 65 ASSERT(m_state == Done); 66 } 67 68 void RespondWithObserver::contextDestroyed() 69 { 70 ContextLifecycleObserver::contextDestroyed(); 71 m_state = Done; 72 } 73 74 void RespondWithObserver::didDispatchEvent() 75 { 76 if (m_state == Initial) 77 sendResponse(nullptr); 78 } 79 80 void RespondWithObserver::respondWith(ScriptState* scriptState, const ScriptValue& value) 81 { 82 if (m_state != Initial) 83 return; 84 85 m_state = Pending; 86 ScriptPromise::cast(scriptState, value).then( 87 ThenFunction::create(this, ThenFunction::Fulfilled), 88 ThenFunction::create(this, ThenFunction::Rejected)); 89 } 90 91 void RespondWithObserver::sendResponse(PassRefPtr<Response> response) 92 { 93 if (!executionContext()) 94 return; 95 ServiceWorkerGlobalScopeClient::from(executionContext())->didHandleFetchEvent(m_eventID, response); 96 m_state = Done; 97 } 98 99 void RespondWithObserver::responseWasRejected() 100 { 101 // FIXME: Throw a NetworkError to service worker's execution context. 102 sendResponse(nullptr); 103 } 104 105 void RespondWithObserver::responseWasFulfilled(const ScriptValue& value) 106 { 107 if (!executionContext()) 108 return; 109 if (!V8Response::hasInstance(value.v8Value(), toIsolate(executionContext()))) { 110 responseWasRejected(); 111 return; 112 } 113 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value.v8Value()); 114 sendResponse(V8Response::toNative(object)); 115 } 116 117 RespondWithObserver::RespondWithObserver(ExecutionContext* context, int eventID) 118 : ContextLifecycleObserver(context) 119 , m_eventID(eventID) 120 , m_state(Initial) 121 { 122 } 123 124 } // namespace WebCore 125