1/*
2 * Copyright (C) 2017-2018 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 "WebSocketStream.h"
28
29#include "DataReference.h"
30#include "NetworkConnectionToWebProcessMessages.h"
31#include "NetworkProcessConnection.h"
32#include "NetworkSocketStreamMessages.h"
33#include "WebCoreArgumentCoders.h"
34#include "WebProcess.h"
35#include <WebCore/CookieRequestHeaderFieldProxy.h>
36#include <WebCore/SocketStreamError.h>
37#include <WebCore/SocketStreamHandleClient.h>
38#include <pal/SessionID.h>
39#include <wtf/NeverDestroyed.h>
40
41namespace WebKit {
42using namespace WebCore;
43
44static Lock globalWebSocketStreamMapLock;
45static HashMap<uint64_t, WebSocketStream*>& globalWebSocketStreamMap()
46{
47 static NeverDestroyed<HashMap<uint64_t, WebSocketStream*>> globalMap;
48 return globalMap;
49}
50
51WebSocketStream* WebSocketStream::streamWithIdentifier(uint64_t identifier)
52{
53 LockHolder locker(globalWebSocketStreamMapLock);
54 return globalWebSocketStreamMap().get(identifier);
55}
56
57void WebSocketStream::networkProcessCrashed()
58{
59 Vector<RefPtr<WebSocketStream>> sockets;
60 {
61 LockHolder locker(globalWebSocketStreamMapLock);
62 sockets.reserveInitialCapacity(globalWebSocketStreamMap().size());
63 for (auto& stream : globalWebSocketStreamMap().values())
64 sockets.uncheckedAppend(stream);
65 }
66
67 for (auto& stream : sockets) {
68 for (auto& callback : stream->m_sendDataCallbacks.values())
69 callback(false);
70 for (auto& callback : stream->m_sendHandshakeCallbacks.values())
71 callback(false, false);
72 stream->m_client.didFailSocketStream(*stream, SocketStreamError(0, { }, "Network process crashed."));
73 stream = nullptr;
74 }
75
76 LockHolder locker(globalWebSocketStreamMapLock);
77 globalWebSocketStreamMap().clear();
78}
79
80Ref<WebSocketStream> WebSocketStream::create(const URL& url, SocketStreamHandleClient& client, PAL::SessionID sessionID, const String& credentialPartition)
81{
82 return adoptRef(*new WebSocketStream(url, client, sessionID, credentialPartition));
83}
84
85WebSocketStream::WebSocketStream(const URL& url, WebCore::SocketStreamHandleClient& client, PAL::SessionID sessionID, const String& cachePartition)
86 : SocketStreamHandle(url, client)
87 , m_client(client)
88{
89 WebProcess::singleton().ensureNetworkProcessConnection().connection().send(Messages::NetworkConnectionToWebProcess::CreateSocketStream(url, sessionID, cachePartition, identifier()), 0);
90
91 LockHolder locker(globalWebSocketStreamMapLock);
92 ASSERT(!globalWebSocketStreamMap().contains(identifier()));
93 globalWebSocketStreamMap().set(identifier(), this);
94}
95
96WebSocketStream::~WebSocketStream()
97{
98 LockHolder locker(globalWebSocketStreamMapLock);
99 ASSERT(globalWebSocketStreamMap().contains(identifier()));
100 globalWebSocketStreamMap().remove(identifier());
101}
102
103IPC::Connection* WebSocketStream::messageSenderConnection() const
104{
105 return &WebProcess::singleton().ensureNetworkProcessConnection().connection();
106}
107
108uint64_t WebSocketStream::messageSenderDestinationID() const
109{
110 return identifier();
111}
112
113void WebSocketStream::platformSend(const uint8_t* data, size_t length, Function<void(bool)>&& completionHandler)
114{
115 static uint64_t nextDataIdentifier = 1;
116 uint64_t dataIdentifier = nextDataIdentifier++;
117 send(Messages::NetworkSocketStream::SendData(IPC::DataReference(data, length), dataIdentifier));
118 ASSERT(!m_sendDataCallbacks.contains(dataIdentifier));
119 m_sendDataCallbacks.add(dataIdentifier, WTFMove(completionHandler));
120}
121
122void WebSocketStream::platformSendHandshake(const uint8_t* data, size_t length, const Optional<CookieRequestHeaderFieldProxy>& headerFieldProxy, Function<void(bool, bool)>&& completionHandler)
123{
124 static uint64_t nextDataIdentifier = 1;
125 uint64_t dataIdentifier = nextDataIdentifier++;
126 send(Messages::NetworkSocketStream::SendHandshake(IPC::DataReference(data, length), headerFieldProxy, dataIdentifier));
127 ASSERT(!m_sendHandshakeCallbacks.contains(dataIdentifier));
128 m_sendHandshakeCallbacks.add(dataIdentifier, WTFMove(completionHandler));
129}
130
131void WebSocketStream::didSendData(uint64_t identifier, bool success)
132{
133 ASSERT(m_sendDataCallbacks.contains(identifier));
134 m_sendDataCallbacks.take(identifier)(success);
135}
136
137void WebSocketStream::didSendHandshake(uint64_t identifier, bool success, bool didAccessSecureCookies)
138{
139 ASSERT(m_sendHandshakeCallbacks.contains(identifier));
140 m_sendHandshakeCallbacks.take(identifier)(success, didAccessSecureCookies);
141}
142
143void WebSocketStream::platformClose()
144{
145 send(Messages::NetworkSocketStream::Close());
146}
147
148size_t WebSocketStream::bufferedAmount()
149{
150 return m_bufferedAmount;
151}
152
153void WebSocketStream::didOpenSocketStream()
154{
155 m_state = Open;
156 m_client.didOpenSocketStream(*this);
157}
158
159void WebSocketStream::didCloseSocketStream()
160{
161 m_state = Closed;
162 m_client.didCloseSocketStream(*this);
163}
164
165void WebSocketStream::didReceiveSocketStreamData(const IPC::DataReference& data)
166{
167 m_client.didReceiveSocketStreamData(*this, reinterpret_cast<const char*>(data.data()), data.size());
168}
169
170void WebSocketStream::didFailToReceiveSocketStreamData()
171{
172 m_client.didFailToReceiveSocketStreamData(*this);
173}
174
175void WebSocketStream::didUpdateBufferedAmount(uint64_t newAmount)
176{
177 m_bufferedAmount = newAmount;
178 m_client.didUpdateBufferedAmount(*this, newAmount);
179}
180
181void WebSocketStream::didFailSocketStream(WebCore::SocketStreamError&& error)
182{
183 m_client.didFailSocketStream(*this, WTFMove(error));
184}
185
186} // namespace WebKit
187