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

« back to all changes in this revision

Viewing changes to Source/WebKit2/UIProcess/InspectorServer/WebSocketServerConnection.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) 2011 Apple Inc. All Rights Reserved.
 
3
 * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies)
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 * 1. Redistributions of source code must retain the above copyright
 
9
 *    notice, this list of conditions and the following disclaimer.
 
10
 * 2. Redistributions in binary form must reproduce the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer in the
 
12
 *    documentation and/or other materials provided with the distribution.
 
13
 *
 
14
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 
15
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
17
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 
18
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
19
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
20
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
21
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 
22
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
23
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 
24
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
25
 */
 
26
 
 
27
#include "config.h"
 
28
 
 
29
#if ENABLE(INSPECTOR_SERVER)
 
30
 
 
31
#include "WebSocketServerConnection.h"
 
32
 
 
33
#include "WebSocketServer.h"
 
34
#include "WebSocketServerClient.h"
 
35
#include <WebCore/HTTPRequest.h>
 
36
#include <WebCore/NotImplemented.h>
 
37
#include <WebCore/SocketStreamError.h>
 
38
#include <WebCore/SocketStreamHandle.h>
 
39
#include <WebCore/WebSocketChannel.h>
 
40
#include <WebCore/WebSocketHandshake.h>
 
41
#include <wtf/text/CString.h>
 
42
#include <wtf/text/StringBuilder.h>
 
43
 
 
44
using namespace WebCore;
 
45
 
 
46
namespace WebKit {
 
47
 
 
48
WebSocketServerConnection::WebSocketServerConnection(WebSocketServerClient* client, WebSocketServer* server)
 
49
    : m_identifier(0)
 
50
    , m_mode(HTTP)
 
51
    , m_server(server)
 
52
    , m_client(client)
 
53
    , m_shutdownAfterSend(false)
 
54
{
 
55
}
 
56
 
 
57
WebSocketServerConnection::~WebSocketServerConnection()
 
58
{
 
59
    shutdownNow();
 
60
}
 
61
 
 
62
void WebSocketServerConnection::setSocketHandle(PassRefPtr<WebCore::SocketStreamHandle> socket)
 
63
{
 
64
    ASSERT(!m_socket);
 
65
    m_socket = socket;
 
66
}
 
67
 
 
68
void WebSocketServerConnection::shutdownNow()
 
69
{
 
70
    if (!m_socket)
 
71
        return;
 
72
    RefPtr<SocketStreamHandle> socket = m_socket.release();
 
73
    socket->close();
 
74
    m_shutdownAfterSend = false;
 
75
}
 
76
 
 
77
void WebSocketServerConnection::shutdownAfterSendOrNow()
 
78
{
 
79
    if (m_socket->bufferedAmount()) {
 
80
        m_shutdownAfterSend = true;
 
81
        return;
 
82
    }
 
83
 
 
84
    shutdownNow();
 
85
}
 
86
 
 
87
void WebSocketServerConnection::sendWebSocketMessage(const String& message)
 
88
{
 
89
    CString payload = message.utf8();
 
90
    const bool final = true, compress = false, masked = false;
 
91
    WebSocketFrame frame(WebSocketFrame::OpCodeText, final, compress, masked, payload.data(), payload.length());
 
92
 
 
93
    Vector<char> frameData;
 
94
    frame.makeFrameData(frameData);
 
95
 
 
96
    m_socket->send(frameData.data(), frameData.size());
 
97
}
 
98
 
 
99
void WebSocketServerConnection::sendHTTPResponseHeader(int statusCode, const String& statusText, const HTTPHeaderMap& headerFields)
 
100
{
 
101
    StringBuilder builder;
 
102
    builder.appendLiteral("HTTP/1.1 ");
 
103
    builder.appendNumber(statusCode);
 
104
    builder.append(' ');
 
105
    builder.append(statusText);
 
106
    builder.appendLiteral("\r\n");
 
107
    HTTPHeaderMap::const_iterator end = headerFields.end();
 
108
    for (HTTPHeaderMap::const_iterator it = headerFields.begin(); it != end; ++it) {
 
109
        builder.append(it->key);
 
110
        builder.appendLiteral(": ");
 
111
        builder.append(it->value);
 
112
        builder.appendLiteral("\r\n");
 
113
    }
 
114
    builder.appendLiteral("\r\n");
 
115
 
 
116
    CString header = builder.toString().latin1();
 
117
    m_socket->send(header.data(), header.length());
 
118
}
 
119
 
 
120
void WebSocketServerConnection::sendRawData(const char* data, size_t length)
 
121
{
 
122
    m_socket->send(data, length);
 
123
}
 
124
 
 
125
void WebSocketServerConnection::didCloseSocketStream(SocketStreamHandle*)
 
126
{
 
127
    // Destroy the SocketStreamHandle now to prevent closing an already closed socket later.
 
128
    m_socket.clear();
 
129
 
 
130
    // Web Socket Mode.
 
131
    if (m_mode == WebSocket)
 
132
        m_client->didCloseWebSocketConnection(this);
 
133
 
 
134
    // Tell the server to get rid of this.
 
135
    m_server->didCloseWebSocketServerConnection(this);
 
136
}
 
137
 
 
138
void WebSocketServerConnection::didReceiveSocketStreamData(SocketStreamHandle*, const char* data, int length)
 
139
{
 
140
    // Each didReceiveData call adds more data to our buffer.
 
141
    // We clear the buffer when we have handled data from it.
 
142
    m_bufferedData.append(data, length);
 
143
 
 
144
    switch (m_mode) {
 
145
    case HTTP:
 
146
        readHTTPMessage();
 
147
        break;
 
148
    case WebSocket:
 
149
        readWebSocketFrames();
 
150
        break;
 
151
    default:
 
152
        // For any new modes added in the future.
 
153
        ASSERT_NOT_REACHED();
 
154
    }
 
155
}
 
156
 
 
157
void WebSocketServerConnection::didUpdateBufferedAmount(WebCore::SocketStreamHandle*, size_t)
 
158
{
 
159
    if (m_shutdownAfterSend && !m_socket->bufferedAmount())
 
160
        shutdownNow();
 
161
}
 
162
 
 
163
void WebSocketServerConnection::didFailSocketStream(SocketStreamHandle*, const SocketStreamError&)
 
164
{
 
165
    // Possible read or write error.
 
166
}
 
167
 
 
168
void WebSocketServerConnection::readHTTPMessage()
 
169
{
 
170
    String failureReason;
 
171
    RefPtr<HTTPRequest> request = HTTPRequest::parseHTTPRequestFromBuffer(m_bufferedData.data(), m_bufferedData.size(), failureReason);
 
172
    if (!request)
 
173
        return;
 
174
 
 
175
    // Assume all the input has been read if we are reading an HTTP Request.
 
176
    m_bufferedData.clear();
 
177
 
 
178
    // If this is a WebSocket request, perform the WebSocket Handshake.
 
179
    const HTTPHeaderMap& headers = request->headerFields();
 
180
    String upgradeHeaderValue = headers.get("Upgrade");
 
181
    if (upgradeHeaderValue == "websocket") {
 
182
        upgradeToWebSocketServerConnection(request);
 
183
        return;
 
184
    }
 
185
    if (upgradeHeaderValue == "WebSocket") {
 
186
        LOG_ERROR("WebSocket protocol version < Hybi-10 not supported. Upgrade your client.");
 
187
        return;
 
188
    }
 
189
 
 
190
    // Otherwise, this is an HTTP Request we don't know how to deal with.
 
191
    m_client->didReceiveUnrecognizedHTTPRequest(this, request);
 
192
}
 
193
 
 
194
void WebSocketServerConnection::upgradeToWebSocketServerConnection(PassRefPtr<HTTPRequest> request)
 
195
{
 
196
    ASSERT(request);
 
197
    ASSERT(m_mode == HTTP);
 
198
    m_mode = WebSocket;
 
199
    RefPtr<HTTPRequest> protectedRequest(request);
 
200
 
 
201
    // Ask the client if we should upgrade for this or not.
 
202
    if (!m_client->didReceiveWebSocketUpgradeHTTPRequest(this, protectedRequest)) {
 
203
        shutdownNow();
 
204
        return;
 
205
    }
 
206
 
 
207
    // Build and send the WebSocket handshake response.
 
208
    const HTTPHeaderMap& requestHeaders = protectedRequest->headerFields();
 
209
    String accept = WebSocketHandshake::getExpectedWebSocketAccept(requestHeaders.get("Sec-WebSocket-Key"));
 
210
    HTTPHeaderMap responseHeaders;
 
211
    responseHeaders.add("Upgrade", requestHeaders.get("Upgrade"));
 
212
    responseHeaders.add("Connection", requestHeaders.get("Connection"));
 
213
    responseHeaders.add("Sec-WebSocket-Accept", accept);
 
214
 
 
215
    sendHTTPResponseHeader(101, "WebSocket Protocol Handshake", responseHeaders);
 
216
 
 
217
    m_client->didEstablishWebSocketConnection(this, protectedRequest);
 
218
}
 
219
 
 
220
void WebSocketServerConnection::readWebSocketFrames()
 
221
{
 
222
    while (true) {
 
223
        bool didReadOneFrame = readWebSocketFrame();
 
224
        if (!didReadOneFrame)
 
225
            break;
 
226
        if (m_bufferedData.isEmpty())
 
227
            break;
 
228
    }
 
229
}
 
230
 
 
231
bool WebSocketServerConnection::readWebSocketFrame()
 
232
{
 
233
    WebSocketFrame frame;
 
234
    const char* frameEnd;
 
235
    String errorString;
 
236
    WebSocketFrame::ParseFrameResult result = WebSocketFrame::parseFrame(m_bufferedData.data(), m_bufferedData.size(), frame, frameEnd, errorString);
 
237
 
 
238
    // Incomplete frame. Wait to receive more data.
 
239
    if (result == WebSocketFrame::FrameIncomplete)
 
240
        return false;
 
241
 
 
242
    if (result == WebSocketFrame::FrameError) {
 
243
        shutdownNow();
 
244
    } else if (frame.opCode == WebSocketFrame::OpCodeText) {
 
245
        // Delegate Text frames to our client.
 
246
        String msg = String::fromUTF8(frame.payload, frame.payloadLength);
 
247
        m_client->didReceiveWebSocketMessage(this, msg);
 
248
    } else
 
249
        notImplemented();
 
250
 
 
251
    // Remove the frame from our buffer.
 
252
    m_bufferedData.remove(0, frameEnd - m_bufferedData.data());
 
253
 
 
254
    return true;
 
255
}
 
256
 
 
257
}
 
258
 
 
259
#endif // ENABLE(INSPECTOR_SERVER)