~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/platform/network/soup/SocketStreamHandleSoup.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "SocketStreamHandle.h"
 
34
 
 
35
#include "KURL.h"
 
36
#include "Logging.h"
 
37
#include "NotImplemented.h"
 
38
#include "SocketStreamError.h"
 
39
#include "SocketStreamHandleClient.h"
 
40
 
 
41
#include <gio/gio.h>
 
42
#include <glib.h>
 
43
 
 
44
#include <wtf/NotFound.h>
 
45
#include <wtf/Vector.h>
 
46
#include <wtf/gobject/GOwnPtr.h>
 
47
#include <wtf/text/CString.h>
 
48
 
 
49
#define READ_BUFFER_SIZE 1024
 
50
 
 
51
namespace WebCore {
 
52
 
 
53
// These functions immediately call the similarly named SocketStreamHandle methods.
 
54
static void connectedCallback(GSocketClient*, GAsyncResult*, void*);
 
55
static void readReadyCallback(GInputStream*, GAsyncResult*, void*);
 
56
static gboolean writeReadyCallback(GPollableOutputStream*, void*);
 
57
 
 
58
// Having a list of active handles means that we do not have to worry about WebCore
 
59
// reference counting in GLib callbacks. Once the handle is off the active handles list
 
60
// we just ignore it in the callback. We avoid a lot of extra checks and tricky
 
61
// situations this way.
 
62
static HashMap<void*, SocketStreamHandle*> gActiveHandles;
 
63
static SocketStreamHandle* getHandleFromId(void* id)
 
64
{
 
65
    if (!gActiveHandles.contains(id))
 
66
        return 0;
 
67
    return gActiveHandles.get(id);
 
68
}
 
69
 
 
70
static void deactivateHandle(SocketStreamHandle* handle)
 
71
{
 
72
    gActiveHandles.remove(handle->id());
 
73
}
 
74
 
 
75
static void* activateHandle(SocketStreamHandle* handle)
 
76
{
 
77
    // The first id cannot be 0, because it conflicts with the HashMap emptyValue.
 
78
    static gint currentHandleId = 1;
 
79
    void* id = GINT_TO_POINTER(currentHandleId++);
 
80
    gActiveHandles.set(id, handle);
 
81
    return id;
 
82
}
 
83
 
 
84
SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client)
 
85
    : SocketStreamHandleBase(url, client)
 
86
    , m_readBuffer(0)
 
87
{
 
88
    LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
 
89
    unsigned int port = url.hasPort() ? url.port() : (url.protocolIs("wss") ? 443 : 80);
 
90
 
 
91
    m_id = activateHandle(this);
 
92
    GRefPtr<GSocketClient> socketClient = adoptGRef(g_socket_client_new());
 
93
    if (url.protocolIs("wss"))
 
94
        g_socket_client_set_tls(socketClient.get(), TRUE);
 
95
    g_socket_client_connect_to_host_async(socketClient.get(), url.host().utf8().data(), port, 0,
 
96
        reinterpret_cast<GAsyncReadyCallback>(connectedCallback), m_id);
 
97
}
 
98
 
 
99
SocketStreamHandle::SocketStreamHandle(GSocketConnection* socketConnection, SocketStreamHandleClient* client)
 
100
    : SocketStreamHandleBase(KURL(), client)
 
101
    , m_readBuffer(0)
 
102
{
 
103
    LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
 
104
    m_id = activateHandle(this);
 
105
    connected(socketConnection, 0);
 
106
}
 
107
 
 
108
SocketStreamHandle::~SocketStreamHandle()
 
109
{
 
110
    LOG(Network, "SocketStreamHandle %p delete", this);
 
111
    // If for some reason we were destroyed without closing, ensure that we are deactivated.
 
112
    deactivateHandle(this);
 
113
    setClient(0);
 
114
}
 
115
 
 
116
void SocketStreamHandle::connected(GSocketConnection* socketConnection, GError* error)
 
117
{
 
118
    if (error) {
 
119
        m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
 
120
        return;
 
121
    }
 
122
 
 
123
    m_socketConnection = socketConnection;
 
124
    m_outputStream = G_POLLABLE_OUTPUT_STREAM(g_io_stream_get_output_stream(G_IO_STREAM(m_socketConnection.get())));
 
125
    m_inputStream = g_io_stream_get_input_stream(G_IO_STREAM(m_socketConnection.get()));
 
126
 
 
127
    m_readBuffer = new char[READ_BUFFER_SIZE];
 
128
    g_input_stream_read_async(m_inputStream.get(), m_readBuffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, 0,
 
129
        reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), m_id);
 
130
 
 
131
    m_state = Open;
 
132
    m_client->didOpenSocketStream(this);
 
133
}
 
134
 
 
135
void SocketStreamHandle::readBytes(signed long bytesRead, GError* error)
 
136
{
 
137
    if (error) {
 
138
        m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
 
139
        return;
 
140
    }
 
141
 
 
142
    if (!bytesRead) {
 
143
        close();
 
144
        return;
 
145
    }
 
146
 
 
147
    // The client can close the handle, potentially removing the last reference.
 
148
    RefPtr<SocketStreamHandle> protect(this); 
 
149
    m_client->didReceiveSocketStreamData(this, m_readBuffer, bytesRead);
 
150
    if (m_inputStream) // The client may have closed the connection.
 
151
        g_input_stream_read_async(m_inputStream.get(), m_readBuffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, 0,
 
152
            reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), m_id);
 
153
}
 
154
 
 
155
void SocketStreamHandle::writeReady()
 
156
{
 
157
    // We no longer have buffered data, so stop waiting for the socket to be writable.
 
158
    if (!bufferedAmount()) {
 
159
        stopWaitingForSocketWritability();
 
160
        return;
 
161
    }
 
162
 
 
163
    sendPendingData();
 
164
}
 
165
 
 
166
int SocketStreamHandle::platformSend(const char* data, int length)
 
167
{
 
168
    LOG(Network, "SocketStreamHandle %p platformSend", this);
 
169
    if (!m_outputStream || !data)
 
170
        return 0;
 
171
 
 
172
    GOwnPtr<GError> error;
 
173
    gssize written = g_pollable_output_stream_write_nonblocking(m_outputStream.get(), data, length, 0, &error.outPtr());
 
174
    if (error) {
 
175
        if (g_error_matches(error.get(), G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
 
176
            beginWaitingForSocketWritability();
 
177
        else
 
178
            m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
 
179
        return 0;
 
180
    }
 
181
 
 
182
    // If we did not send all the bytes we were given, we know that
 
183
    // SocketStreamHandleBase will need to send more in the future.
 
184
    if (written < length)
 
185
        beginWaitingForSocketWritability();
 
186
 
 
187
    return written;
 
188
}
 
189
 
 
190
void SocketStreamHandle::platformClose()
 
191
{
 
192
    LOG(Network, "SocketStreamHandle %p platformClose", this);
 
193
    // We remove this handle from the active handles list first, to disable all callbacks.
 
194
    deactivateHandle(this);
 
195
    stopWaitingForSocketWritability();
 
196
 
 
197
    if (m_socketConnection) {
 
198
        GOwnPtr<GError> error;
 
199
        g_io_stream_close(G_IO_STREAM(m_socketConnection.get()), 0, &error.outPtr());
 
200
        if (error)
 
201
            m_client->didFailSocketStream(this, SocketStreamError(error->code, error->message));
 
202
        m_socketConnection = 0;
 
203
    }
 
204
 
 
205
    m_outputStream = 0;
 
206
    m_inputStream = 0;
 
207
    delete m_readBuffer;
 
208
    m_readBuffer = 0;
 
209
 
 
210
    m_client->didCloseSocketStream(this);
 
211
}
 
212
 
 
213
void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&)
 
214
{
 
215
    notImplemented();
 
216
}
 
217
 
 
218
void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&)
 
219
{
 
220
    notImplemented();
 
221
}
 
222
 
 
223
void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&)
 
224
{
 
225
    notImplemented();
 
226
}
 
227
 
 
228
void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&)
 
229
{
 
230
    notImplemented();
 
231
}
 
232
 
 
233
void SocketStreamHandle::beginWaitingForSocketWritability()
 
234
{
 
235
    if (m_writeReadySource) // Already waiting.
 
236
        return;
 
237
 
 
238
    m_writeReadySource = adoptGRef(g_pollable_output_stream_create_source(m_outputStream.get(), 0));
 
239
    g_source_set_callback(m_writeReadySource.get(), reinterpret_cast<GSourceFunc>(writeReadyCallback), m_id, 0);
 
240
    g_source_attach(m_writeReadySource.get(), 0);
 
241
}
 
242
 
 
243
void SocketStreamHandle::stopWaitingForSocketWritability()
 
244
{
 
245
    if (!m_writeReadySource) // Not waiting.
 
246
        return;
 
247
 
 
248
    g_source_remove(g_source_get_id(m_writeReadySource.get()));
 
249
    m_writeReadySource = 0;
 
250
}
 
251
 
 
252
static void connectedCallback(GSocketClient* client, GAsyncResult* result, void* id)
 
253
{
 
254
    // Always finish the connection, even if this SocketStreamHandle was deactivated earlier.
 
255
    GOwnPtr<GError> error;
 
256
    GSocketConnection* socketConnection = g_socket_client_connect_to_host_finish(client, result, &error.outPtr());
 
257
 
 
258
    // The SocketStreamHandle has been deactivated, so just close the connection, ignoring errors.
 
259
    SocketStreamHandle* handle = getHandleFromId(id);
 
260
    if (!handle) {
 
261
        if (socketConnection)
 
262
            g_io_stream_close(G_IO_STREAM(socketConnection), 0, 0);
 
263
        return;
 
264
    }
 
265
 
 
266
    handle->connected(socketConnection, error.get());
 
267
}
 
268
 
 
269
static void readReadyCallback(GInputStream* stream, GAsyncResult* result, void* id)
 
270
{
 
271
    // Always finish the read, even if this SocketStreamHandle was deactivated earlier.
 
272
    GOwnPtr<GError> error;
 
273
    gssize bytesRead = g_input_stream_read_finish(stream, result, &error.outPtr());
 
274
 
 
275
    SocketStreamHandle* handle = getHandleFromId(id);
 
276
    if (!handle)
 
277
        return;
 
278
 
 
279
    handle->readBytes(bytesRead, error.get());
 
280
}
 
281
 
 
282
static gboolean writeReadyCallback(GPollableOutputStream*, void* id)
 
283
{
 
284
    SocketStreamHandle* handle = getHandleFromId(id);
 
285
    if (!handle)
 
286
        return FALSE;
 
287
 
 
288
    handle->writeReady();
 
289
    return TRUE;
 
290
}
 
291
 
 
292
} // namespace WebCore