[WTF] Import std::optional reference implementation as WTF::Optional
[WebKit-https.git] / Source / WebCore / platform / network / soup / SocketStreamHandleImplSoup.cpp
1 /*
2  * Copyright (C) 2009, 2011 Google Inc.  All rights reserved.
3  * Copyright (C) 2012 Samsung Electronics Ltd. All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "SocketStreamHandleImpl.h"
34
35 #if USE(SOUP)
36
37 #include "Logging.h"
38 #include "SocketStreamError.h"
39 #include "SocketStreamHandleClient.h"
40 #include "URL.h"
41 #include <gio/gio.h>
42 #include <glib.h>
43 #include <wtf/Vector.h>
44 #include <wtf/glib/GUniquePtr.h>
45 #include <wtf/text/CString.h>
46
47 #define READ_BUFFER_SIZE 1024
48
49 namespace WebCore {
50
51 Ref<SocketStreamHandleImpl> SocketStreamHandleImpl::create(const URL& url, SocketStreamHandleClient& client, SessionID)
52 {
53     Ref<SocketStreamHandleImpl> socket = adoptRef(*new SocketStreamHandleImpl(url, client));
54
55     unsigned port = url.port() ? url.port().value() : (url.protocolIs("wss") ? 443 : 80);
56     GRefPtr<GSocketClient> socketClient = adoptGRef(g_socket_client_new());
57     if (url.protocolIs("wss"))
58         g_socket_client_set_tls(socketClient.get(), TRUE);
59     Ref<SocketStreamHandle> protectedSocketStreamHandle = socket.copyRef();
60     g_socket_client_connect_to_host_async(socketClient.get(), url.host().utf8().data(), port, socket->m_cancellable.get(),
61         reinterpret_cast<GAsyncReadyCallback>(connectedCallback), &protectedSocketStreamHandle.leakRef());
62     return socket;
63 }
64
65 Ref<SocketStreamHandle> SocketStreamHandleImpl::create(GSocketConnection* socketConnection, SocketStreamHandleClient& client)
66 {
67     Ref<SocketStreamHandleImpl> socket = adoptRef(*new SocketStreamHandleImpl(URL(), client));
68
69     GRefPtr<GSocketConnection> connection = socketConnection;
70     socket->connected(WTFMove(connection));
71     return WTFMove(socket);
72 }
73
74 SocketStreamHandleImpl::SocketStreamHandleImpl(const URL& url, SocketStreamHandleClient& client)
75     : SocketStreamHandle(url, client)
76     , m_cancellable(adoptGRef(g_cancellable_new()))
77 {
78     LOG(Network, "SocketStreamHandle %p new client %p", this, &m_client);
79 }
80
81 SocketStreamHandleImpl::~SocketStreamHandleImpl()
82 {
83     LOG(Network, "SocketStreamHandle %p delete", this);
84 }
85
86 void SocketStreamHandleImpl::connected(GRefPtr<GSocketConnection>&& socketConnection)
87 {
88     m_socketConnection = WTFMove(socketConnection);
89     m_outputStream = G_POLLABLE_OUTPUT_STREAM(g_io_stream_get_output_stream(G_IO_STREAM(m_socketConnection.get())));
90     m_inputStream = g_io_stream_get_input_stream(G_IO_STREAM(m_socketConnection.get()));
91     m_readBuffer = std::make_unique<char[]>(READ_BUFFER_SIZE);
92
93     RefPtr<SocketStreamHandleImpl> protectedThis(this);
94     g_input_stream_read_async(m_inputStream.get(), m_readBuffer.get(), READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, m_cancellable.get(),
95         reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), protectedThis.leakRef());
96
97     m_state = Open;
98     m_client.didOpenSocketStream(*this);
99 }
100
101 void SocketStreamHandleImpl::connectedCallback(GSocketClient* client, GAsyncResult* result, SocketStreamHandleImpl* handle)
102 {
103     RefPtr<SocketStreamHandle> protectedThis = adoptRef(handle);
104
105     // Always finish the connection, even if this SocketStreamHandle was cancelled earlier.
106     GUniqueOutPtr<GError> error;
107     GRefPtr<GSocketConnection> socketConnection = adoptGRef(g_socket_client_connect_to_host_finish(client, result, &error.outPtr()));
108
109     // The SocketStreamHandle has been cancelled, so just close the connection, ignoring errors.
110     if (g_cancellable_is_cancelled(handle->m_cancellable.get())) {
111         if (socketConnection)
112             g_io_stream_close(G_IO_STREAM(socketConnection.get()), nullptr, nullptr);
113         return;
114     }
115
116     if (error)
117         handle->didFail(SocketStreamError(error->code, String(), error->message));
118     else
119         handle->connected(WTFMove(socketConnection));
120 }
121
122 void SocketStreamHandleImpl::readBytes(gssize bytesRead)
123 {
124     if (!bytesRead) {
125         close();
126         return;
127     }
128
129     // The client can close the handle, potentially removing the last reference.
130     RefPtr<SocketStreamHandle> protectedThis(this);
131     std::optional<size_t> optionalLength;
132     if (bytesRead != -1)
133         optionalLength = static_cast<size_t>(bytesRead);
134     m_client.didReceiveSocketStreamData(*this, m_readBuffer.get(), optionalLength);
135     if (m_inputStream) {
136         g_input_stream_read_async(m_inputStream.get(), m_readBuffer.get(), READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, m_cancellable.get(),
137             reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), protectedThis.leakRef());
138     }
139 }
140
141 void SocketStreamHandleImpl::readReadyCallback(GInputStream* stream, GAsyncResult* result, SocketStreamHandleImpl* handle)
142 {
143     RefPtr<SocketStreamHandle> protectedThis = adoptRef(handle);
144
145     // Always finish the read, even if this SocketStreamHandle was cancelled earlier.
146     GUniqueOutPtr<GError> error;
147     gssize bytesRead = g_input_stream_read_finish(stream, result, &error.outPtr());
148
149     if (g_cancellable_is_cancelled(handle->m_cancellable.get()))
150         return;
151
152     if (error)
153         handle->didFail(SocketStreamError(error->code, String(), error->message));
154     else
155         handle->readBytes(bytesRead);
156 }
157
158 void SocketStreamHandleImpl::didFail(SocketStreamError&& error)
159 {
160     m_client.didFailSocketStream(*this, WTFMove(error));
161 }
162
163 void SocketStreamHandleImpl::writeReady()
164 {
165     // We no longer have buffered data, so stop waiting for the socket to be writable.
166     if (!bufferedAmount()) {
167         stopWaitingForSocketWritability();
168         return;
169     }
170
171     sendPendingData();
172 }
173
174 std::optional<size_t> SocketStreamHandleImpl::platformSend(const char* data, size_t length)
175 {
176     LOG(Network, "SocketStreamHandle %p platformSend", this);
177     if (!m_outputStream || !data)
178         return std::nullopt;
179
180     GUniqueOutPtr<GError> error;
181     gssize written = g_pollable_output_stream_write_nonblocking(m_outputStream.get(), data, length, m_cancellable.get(), &error.outPtr());
182     if (error) {
183         if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
184             beginWaitingForSocketWritability();
185         else
186             didFail(SocketStreamError(error->code, String(), error->message));
187         return std::nullopt;
188     }
189
190     // If we did not send all the bytes we were given, we know that
191     // SocketStreamHandle will need to send more in the future.
192     if (written == -1 || static_cast<size_t>(written) < length)
193         beginWaitingForSocketWritability();
194
195     if (written == -1)
196         return std::nullopt;
197
198     return static_cast<size_t>(written);
199 }
200
201 void SocketStreamHandleImpl::platformClose()
202 {
203     LOG(Network, "SocketStreamHandle %p platformClose", this);
204     // We cancel this handle first to disable all callbacks.
205     g_cancellable_cancel(m_cancellable.get());
206     stopWaitingForSocketWritability();
207
208     if (m_socketConnection) {
209         GUniqueOutPtr<GError> error;
210         g_io_stream_close(G_IO_STREAM(m_socketConnection.get()), nullptr, &error.outPtr());
211         if (error)
212             didFail(SocketStreamError(error->code, String(), error->message));
213         m_socketConnection = nullptr;
214     }
215
216     m_outputStream = nullptr;
217     m_inputStream = nullptr;
218     m_readBuffer = nullptr;
219
220     m_client.didCloseSocketStream(*this);
221 }
222
223 void SocketStreamHandleImpl::beginWaitingForSocketWritability()
224 {
225     if (m_writeReadySource) // Already waiting.
226         return;
227
228     m_writeReadySource = adoptGRef(g_pollable_output_stream_create_source(m_outputStream.get(), m_cancellable.get()));
229     ref();
230     g_source_set_callback(m_writeReadySource.get(), reinterpret_cast<GSourceFunc>(writeReadyCallback), this, [](gpointer handle) { 
231         static_cast<SocketStreamHandleImpl*>(handle)->deref();
232     });
233     g_source_attach(m_writeReadySource.get(), g_main_context_get_thread_default());
234 }
235
236 void SocketStreamHandleImpl::stopWaitingForSocketWritability()
237 {
238     if (!m_writeReadySource) // Not waiting.
239         return;
240
241     g_source_destroy(m_writeReadySource.get());
242     m_writeReadySource = nullptr;
243 }
244
245 gboolean SocketStreamHandleImpl::writeReadyCallback(GPollableOutputStream*, SocketStreamHandleImpl* handle)
246 {
247     if (g_cancellable_is_cancelled(handle->m_cancellable.get()))
248         return G_SOURCE_REMOVE;
249
250     handle->writeReady();
251     return G_SOURCE_CONTINUE;
252 }
253
254 } // namespace WebCore
255
256 #endif