[SOUP] Provide logging for SocketStreamHandleSoup
[WebKit-https.git] / Source / WebCore / platform / network / soup / SocketStreamHandleSoup.cpp
1 /*
2  * Copyright (C) 2009, 2011 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "SocketStreamHandle.h"
33
34 #include "KURL.h"
35 #include "Logging.h"
36 #include "NotImplemented.h"
37 #include "SocketStreamError.h"
38 #include "SocketStreamHandleClient.h"
39
40 #include <gio/gio.h>
41 #include <glib.h>
42
43 #include <wtf/NotFound.h>
44 #include <wtf/Vector.h>
45 #include <wtf/gobject/GOwnPtr.h>
46 #include <wtf/text/CString.h>
47
48 #define READ_BUFFER_SIZE 1024
49
50 namespace WebCore {
51
52 // These functions immediately call the similarly named SocketStreamHandle methods.
53 static void connectedCallback(GSocketClient*, GAsyncResult*, void*);
54 static void readReadyCallback(GInputStream*, GAsyncResult*, void*);
55 static gboolean writeReadyCallback(GPollableOutputStream*, void*);
56
57 // Having a list of active handles means that we do not have to worry about WebCore
58 // reference counting in GLib callbacks. Once the handle is off the active handles list
59 // we just ignore it in the callback. We avoid a lot of extra checks and tricky
60 // situations this way.
61 static HashMap<void*, SocketStreamHandle*> gActiveHandles;
62 static SocketStreamHandle* getHandleFromId(void* id)
63 {
64     if (!gActiveHandles.contains(id))
65         return 0;
66     return gActiveHandles.get(id);
67 }
68
69 static void deactivateHandle(SocketStreamHandle* handle)
70 {
71     gActiveHandles.remove(handle->id());
72 }
73
74 static void* activateHandle(SocketStreamHandle* handle)
75 {
76     // The first id cannot be 0, because it conflicts with the HashMap emptyValue.
77     static gint currentHandleId = 1;
78     void* id = GINT_TO_POINTER(currentHandleId++);
79     gActiveHandles.set(id, handle);
80     return id;
81 }
82
83 SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client)
84     : SocketStreamHandleBase(url, client)
85     , m_readBuffer(0)
86 {
87     LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
88     unsigned int port = url.hasPort() ? url.port() : (url.protocolIs("wss") ? 443 : 80);
89
90     m_id = activateHandle(this);
91     GRefPtr<GSocketClient> socketClient = adoptGRef(g_socket_client_new());
92     if (url.protocolIs("wss"))
93         g_socket_client_set_tls(socketClient.get(), TRUE);
94     g_socket_client_connect_to_host_async(socketClient.get(), url.host().utf8().data(), port, 0,
95         reinterpret_cast<GAsyncReadyCallback>(connectedCallback), m_id);
96 }
97
98 SocketStreamHandle::~SocketStreamHandle()
99 {
100     LOG(Network, "SocketStreamHandle %p delete", this);
101     // If for some reason we were destroyed without closing, ensure that we are deactivated.
102     deactivateHandle(this);
103     setClient(0);
104 }
105
106 void SocketStreamHandle::connected(GSocketConnection* socketConnection, GError* error)
107 {
108     if (error) {
109         m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
110         return;
111     }
112
113     m_socketConnection = adoptGRef(socketConnection);
114     m_outputStream = G_POLLABLE_OUTPUT_STREAM(g_io_stream_get_output_stream(G_IO_STREAM(m_socketConnection.get())));
115     m_inputStream = g_io_stream_get_input_stream(G_IO_STREAM(m_socketConnection.get()));
116
117     m_readBuffer = new char[READ_BUFFER_SIZE];
118     g_input_stream_read_async(m_inputStream.get(), m_readBuffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, 0,
119         reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), m_id);
120
121     m_state = Open;
122     m_client->didOpenSocketStream(this);
123 }
124
125 void SocketStreamHandle::readBytes(signed long bytesRead, GError* error)
126 {
127     if (error) {
128         m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
129         return;
130     }
131
132     if (!bytesRead) {
133         close();
134         return;
135     }
136
137     // The client can close the handle, potentially removing the last reference.
138     RefPtr<SocketStreamHandle> protect(this); 
139     m_client->didReceiveSocketStreamData(this, m_readBuffer, bytesRead);
140     if (m_inputStream) // The client may have closed the connection.
141         g_input_stream_read_async(m_inputStream.get(), m_readBuffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, 0,
142             reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), m_id);
143 }
144
145 void SocketStreamHandle::writeReady()
146 {
147     // We no longer have buffered data, so stop waiting for the socket to be writable.
148     if (!bufferedAmount()) {
149         stopWaitingForSocketWritability();
150         return;
151     }
152
153     sendPendingData();
154 }
155
156 int SocketStreamHandle::platformSend(const char* data, int length)
157 {
158     LOG(Network, "SocketStreamHandle %p platformSend", this);
159     GOwnPtr<GError> error;
160     gssize written = g_pollable_output_stream_write_nonblocking(m_outputStream.get(), data, length, 0, &error.outPtr());
161     if (error) {
162         if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
163             beginWaitingForSocketWritability();
164         else
165             m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
166         return 0;
167     }
168
169     // If we did not send all the bytes we were given, we know that
170     // SocketStreamHandleBase will need to send more in the future.
171     if (written < length)
172         beginWaitingForSocketWritability();
173
174     return written;
175 }
176
177 void SocketStreamHandle::platformClose()
178 {
179     LOG(Network, "SocketStreamHandle %p platformClose", this);
180     // We remove this handle from the active handles list first, to disable all callbacks.
181     deactivateHandle(this);
182     stopWaitingForSocketWritability();
183
184     if (m_socketConnection) {
185         GOwnPtr<GError> error;
186         g_io_stream_close(G_IO_STREAM(m_socketConnection.get()), 0, &error.outPtr());
187         if (error)
188             m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
189         m_socketConnection = 0;
190     }
191
192     m_outputStream = 0;
193     m_inputStream = 0;
194     delete m_readBuffer;
195
196     m_client->didCloseSocketStream(this);
197 }
198
199 void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&)
200 {
201     notImplemented();
202 }
203
204 void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&)
205 {
206     notImplemented();
207 }
208
209 void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&)
210 {
211     notImplemented();
212 }
213
214 void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&)
215 {
216     notImplemented();
217 }
218
219 void SocketStreamHandle::beginWaitingForSocketWritability()
220 {
221     if (m_writeReadySource) // Already waiting.
222         return;
223
224     m_writeReadySource = adoptGRef(g_pollable_output_stream_create_source(m_outputStream.get(), 0));
225     g_source_set_callback(m_writeReadySource.get(), reinterpret_cast<GSourceFunc>(writeReadyCallback), m_id, 0);
226     g_source_attach(m_writeReadySource.get(), 0);
227 }
228
229 void SocketStreamHandle::stopWaitingForSocketWritability()
230 {
231     if (!m_writeReadySource) // Not waiting.
232         return;
233
234     g_source_remove(g_source_get_id(m_writeReadySource.get()));
235     m_writeReadySource = 0;
236 }
237
238 static void connectedCallback(GSocketClient* client, GAsyncResult* result, void* id)
239 {
240     // Always finish the connection, even if this SocketStreamHandle was deactivated earlier.
241     GOwnPtr<GError> error;
242     GSocketConnection* socketConnection = g_socket_client_connect_to_host_finish(client, result, &error.outPtr());
243
244     // The SocketStreamHandle has been deactivated, so just close the connection, ignoring errors.
245     SocketStreamHandle* handle = getHandleFromId(id);
246     if (!handle) {
247         if (socketConnection)
248             g_io_stream_close(G_IO_STREAM(socketConnection), 0, 0);
249         return;
250     }
251
252     handle->connected(socketConnection, error.get());
253 }
254
255 static void readReadyCallback(GInputStream* stream, GAsyncResult* result, void* id)
256 {
257     // Always finish the read, even if this SocketStreamHandle was deactivated earlier.
258     GOwnPtr<GError> error;
259     gssize bytesRead = g_input_stream_read_finish(stream, result, &error.outPtr());
260
261     SocketStreamHandle* handle = getHandleFromId(id);
262     if (!handle)
263         return;
264
265     handle->readBytes(bytesRead, error.get());
266 }
267
268 static gboolean writeReadyCallback(GPollableOutputStream*, void* id)
269 {
270     SocketStreamHandle* handle = getHandleFromId(id);
271     if (!handle)
272         return FALSE;
273
274     handle->writeReady();
275     return TRUE;
276 }
277
278 } // namespace WebCore