7f123f889d33633d0874f03d5a4bf33ba9028331
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / serviceworkers / RespondWithObserver.cpp
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, WebURLRequest::FetchRequestMode requestMode, WebURLRequest::FrameType frameType)
67 {
68     return new RespondWithObserver(context, eventID, requestMode, frameType);
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     Response* response = V8Response::toImplWithTypeCheck(toIsolate(executionContext()), value.v8Value());
118     // "If either |response|'s type is |opaque| and |request|'s mode is not
119     // |no CORS| or |response|'s type is |error|, return a network error."
120     const FetchResponseData::Type responseType = response->response()->type();
121     if ((responseType == FetchResponseData::OpaqueType && m_requestMode != WebURLRequest::FetchRequestModeNoCORS) || responseType == FetchResponseData::ErrorType) {
122         responseWasRejected();
123         return;
124     }
125     // Treat the opaque response as a network error for frame loading.
126     if (responseType == FetchResponseData::OpaqueType && m_frameType != WebURLRequest::FrameTypeNone) {
127         responseWasRejected();
128         return;
129     }
130     WebServiceWorkerResponse webResponse;
131     response->populateWebServiceWorkerResponse(webResponse);
132     ServiceWorkerGlobalScopeClient::from(executionContext())->didHandleFetchEvent(m_eventID, webResponse);
133     m_state = Done;
134 }
135
136 RespondWithObserver::RespondWithObserver(ExecutionContext* context, int eventID, WebURLRequest::FetchRequestMode requestMode, WebURLRequest::FrameType frameType)
137     : ContextLifecycleObserver(context)
138     , m_eventID(eventID)
139     , m_requestMode(requestMode)
140     , m_frameType(frameType)
141     , m_state(Initial)
142 {
143 }
144
145 } // namespace blink