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
create(PassRefPtr<RespondWithObserver> observer,ResolveType type)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:
ThenFunction(v8::Isolate * isolate,PassRefPtr<RespondWithObserver> observer,ResolveType type)35 ThenFunction(v8::Isolate* isolate, PassRefPtr<RespondWithObserver> observer, ResolveType type)
36 : ScriptFunction(isolate)
37 , m_observer(observer)
38 , m_resolveType(type)
39 {
40 }
41
call(ScriptValue value)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
create(ExecutionContext * context,int eventID)58 PassRefPtr<RespondWithObserver> RespondWithObserver::create(ExecutionContext* context, int eventID)
59 {
60 return adoptRef(new RespondWithObserver(context, eventID));
61 }
62
~RespondWithObserver()63 RespondWithObserver::~RespondWithObserver()
64 {
65 ASSERT(m_state == Done);
66 }
67
contextDestroyed()68 void RespondWithObserver::contextDestroyed()
69 {
70 ContextLifecycleObserver::contextDestroyed();
71 m_state = Done;
72 }
73
didDispatchEvent()74 void RespondWithObserver::didDispatchEvent()
75 {
76 if (m_state == Initial)
77 sendResponse(nullptr);
78 }
79
respondWith(ScriptState * scriptState,const ScriptValue & value)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
sendResponse(PassRefPtr<Response> response)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
responseWasRejected()99 void RespondWithObserver::responseWasRejected()
100 {
101 // FIXME: Throw a NetworkError to service worker's execution context.
102 sendResponse(nullptr);
103 }
104
responseWasFulfilled(const ScriptValue & value)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
RespondWithObserver(ExecutionContext * context,int eventID)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