38bf016e8f49effdb5c6b12aa53289d11306d7a6
[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 FetchEvent::FetchEvent(const AtomicString& type, Init&& initializer, IsTrusted isTrusted)
37     : ExtendableEvent(type, initializer, isTrusted)
38     , m_request(initializer.request.releaseNonNull())
39     , m_clientId(WTFMove(initializer.clientId))
40     , m_reservedClientId(WTFMove(initializer.reservedClientId))
41     , m_targetClientId(WTFMove(initializer.targetClientId))
42 {
43 }
44
45 ExceptionOr<void> FetchEvent::respondWith(Ref<DOMPromise>&& promise)
46 {
47     if (isBeingDispatched())
48         return Exception { InvalidStateError, ASCIILiteral("Event is being dispatched") };
49
50     if (m_respondWithEntered)
51         return Exception { InvalidStateError, ASCIILiteral("Event respondWith flag is set") };
52
53     m_respondPromise = WTFMove(promise);
54     addPendingPromise(*m_respondPromise);
55
56     m_respondPromise->whenSettled([this, weakThis = createWeakPtr()] () {
57         if (!weakThis)
58             return;
59         promiseIsSettled();
60     });
61
62     stopPropagation();
63     stopImmediatePropagation();
64
65     m_respondWithEntered = true;
66     m_waitToRespond = true;
67
68     return { };
69 }
70
71 void FetchEvent::onResponse(WTF::Function<void()>&& callback)
72 {
73     ASSERT(!m_onResponse);
74     m_onResponse = WTFMove(callback);
75 }
76
77 void FetchEvent::respondWithError()
78 {
79     m_respondWithError = true;
80     processResponse();
81 }
82
83 void FetchEvent::processResponse()
84 {
85     m_respondPromise = nullptr;
86     m_waitToRespond = false;
87     if (auto callback = WTFMove(m_onResponse))
88         callback();
89 }
90
91 void FetchEvent::promiseIsSettled()
92 {
93     if (m_respondPromise->status() == DOMPromise::Status::Rejected) {
94         respondWithError();
95         return;
96     }
97
98     ASSERT(m_respondPromise->status() == DOMPromise::Status::Fulfilled);
99     auto response = JSFetchResponse::toWrapped(m_respondPromise->globalObject()->globalExec()->vm(), m_respondPromise->result());
100     if (!response) {
101         respondWithError();
102         return;
103     }
104
105     if (response->isDisturbedOrLocked()) {
106         respondWithError();
107         return;
108     }
109
110     m_response = WTFMove(response);
111
112     // FIXME: We should process the response and send the body in streaming.
113     if (m_response->hasReadableStreamBody()) {
114         m_response->consumeBodyFromReadableStream([this, protectedThis = makeRef(*this)] (ExceptionOr<RefPtr<SharedBuffer>>&& result) mutable {
115             if (result.hasException()) {
116                 respondWithError();
117                 return;
118             }
119             m_responseBody = result.releaseReturnValue();
120             processResponse();
121         });
122         return;
123     }
124     if (m_response->isLoading()) {
125         m_response->consumeBodyWhenLoaded([this, protectedThis = makeRef(*this)] (ExceptionOr<RefPtr<SharedBuffer>>&& result) mutable {
126             if (result.hasException()) {
127                 respondWithError();
128                 return;
129             }
130             m_responseBody = result.releaseReturnValue();
131             processResponse();
132         });
133         return;
134     }
135
136     auto body = m_response->consumeBody();
137     WTF::switchOn(body, 
138         [] (Ref<FormData>&) {
139             // FIXME: Support FormData response bodies.
140         },
141         [this] (Ref<SharedBuffer>& buffer) {
142             m_responseBody = WTFMove(buffer);
143         }, 
144         [] (std::nullptr_t&) {
145         }
146     );
147
148     processResponse();
149 }
150
151 } // namespace WebCore
152
153 #endif // ENABLE(SERVICE_WORKER)