Source/WebCore:
[WebKit-https.git] / Source / WebCore / workers / service / FetchEvent.cpp
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "FetchEvent.h"
28
29 #include "JSDOMPromise.h"
30 #include "JSFetchResponse.h"
31
32 #if ENABLE(SERVICE_WORKER)
33
34 namespace WebCore {
35
36 Ref<FetchEvent> FetchEvent::createForTesting(ScriptExecutionContext& context)
37 {
38     FetchEvent::Init init;
39     init.request = FetchRequest::create(context, { }, FetchHeaders::create(FetchHeaders::Guard::Immutable, { }), { }, { }, { });
40     return FetchEvent::create("fetch", WTFMove(init), Event::IsTrusted::Yes);
41 }
42
43 FetchEvent::FetchEvent(const AtomicString& type, Init&& initializer, IsTrusted isTrusted)
44     : ExtendableEvent(type, initializer, isTrusted)
45     , m_request(initializer.request.releaseNonNull())
46     , m_clientId(WTFMove(initializer.clientId))
47     , m_reservedClientId(WTFMove(initializer.reservedClientId))
48     , m_targetClientId(WTFMove(initializer.targetClientId))
49 {
50 }
51
52 FetchEvent::~FetchEvent()
53 {
54     if (auto callback = WTFMove(m_onResponse))
55         callback(nullptr);
56 }
57
58 ExceptionOr<void> FetchEvent::respondWith(Ref<DOMPromise>&& promise)
59 {
60     if (!isBeingDispatched())
61         return Exception { InvalidStateError, ASCIILiteral("Event is not being dispatched") };
62
63     if (m_respondWithEntered)
64         return Exception { InvalidStateError, ASCIILiteral("Event respondWith flag is set") };
65
66     m_respondPromise = WTFMove(promise);
67     addPendingPromise(*m_respondPromise);
68
69     m_respondPromise->whenSettled([this, weakThis = createWeakPtr()] () {
70         if (!weakThis)
71             return;
72         promiseIsSettled();
73     });
74
75     stopPropagation();
76     stopImmediatePropagation();
77
78     m_respondWithEntered = true;
79     m_waitToRespond = true;
80
81     return { };
82 }
83
84 void FetchEvent::onResponse(CompletionHandler<void(FetchResponse*)>&& callback)
85 {
86     ASSERT(!m_onResponse);
87     m_onResponse = WTFMove(callback);
88 }
89
90 void FetchEvent::respondWithError()
91 {
92     m_respondWithError = true;
93     processResponse(nullptr);
94 }
95
96 void FetchEvent::processResponse(FetchResponse* response)
97 {
98     m_respondPromise = nullptr;
99     m_waitToRespond = false;
100     if (auto callback = WTFMove(m_onResponse))
101         callback(response);
102 }
103
104 void FetchEvent::promiseIsSettled()
105 {
106     if (m_respondPromise->status() == DOMPromise::Status::Rejected) {
107         respondWithError();
108         return;
109     }
110
111     ASSERT(m_respondPromise->status() == DOMPromise::Status::Fulfilled);
112     auto response = JSFetchResponse::toWrapped(m_respondPromise->globalObject()->globalExec()->vm(), m_respondPromise->result());
113     if (!response) {
114         respondWithError();
115         return;
116     }
117
118     if (response->isDisturbedOrLocked()) {
119         respondWithError();
120         return;
121     }
122
123     processResponse(response);
124 }
125
126 } // namespace WebCore
127
128 #endif // ENABLE(SERVICE_WORKER)