1 /*
2 * Copyright (C) 2010 Nokia Inc. All rights reserved.
3 * Copyright (C) 2009 Google Inc. 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 "SocketStreamHandleClient.h"
39 #include "SocketStreamHandlePrivate.h"
40
41 namespace WebCore {
42
SocketStreamHandlePrivate(SocketStreamHandle * streamHandle,const KURL & url)43 SocketStreamHandlePrivate::SocketStreamHandlePrivate(SocketStreamHandle* streamHandle, const KURL& url) : QObject()
44 {
45 m_streamHandle = streamHandle;
46 m_socket = 0;
47 bool isSecure = url.protocolIs("wss");
48
49 if (isSecure) {
50 #ifndef QT_NO_OPENSSL
51 m_socket = new QSslSocket(this);
52 #endif
53 } else
54 m_socket = new QTcpSocket(this);
55
56 if (!m_socket)
57 return;
58
59 connect(m_socket, SIGNAL(connected()), this, SLOT(socketConnected()));
60 connect(m_socket, SIGNAL(readyRead()), this, SLOT(socketReadyRead()));
61 connect(m_socket, SIGNAL(disconnected()), this, SLOT(socketClosed()));
62 connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
63 if (isSecure)
64 connect(m_socket, SIGNAL(sslErrors(const QList<QSslError>&)), this, SLOT(socketSslErrors(const QList<QSslError>&)));
65
66 unsigned int port = url.hasPort() ? url.port() : (isSecure ? 443 : 80);
67
68 QString host = url.host();
69 if (isSecure) {
70 #ifndef QT_NO_OPENSSL
71 static_cast<QSslSocket*>(m_socket)->connectToHostEncrypted(host, port);
72 #endif
73 } else
74 m_socket->connectToHost(host, port);
75 }
76
~SocketStreamHandlePrivate()77 SocketStreamHandlePrivate::~SocketStreamHandlePrivate()
78 {
79 Q_ASSERT(!(m_socket && m_socket->state() == QAbstractSocket::ConnectedState));
80 }
81
socketConnected()82 void SocketStreamHandlePrivate::socketConnected()
83 {
84 if (m_streamHandle && m_streamHandle->client()) {
85 m_streamHandle->m_state = SocketStreamHandleBase::Open;
86 m_streamHandle->client()->didOpen(m_streamHandle);
87 }
88 }
89
socketReadyRead()90 void SocketStreamHandlePrivate::socketReadyRead()
91 {
92 if (m_streamHandle && m_streamHandle->client()) {
93 QByteArray data = m_socket->read(m_socket->bytesAvailable());
94 m_streamHandle->client()->didReceiveData(m_streamHandle, data.constData(), data.size());
95 }
96 }
97
send(const char * data,int len)98 int SocketStreamHandlePrivate::send(const char* data, int len)
99 {
100 if (!m_socket || m_socket->state() != QAbstractSocket::ConnectedState)
101 return 0;
102 quint64 sentSize = m_socket->write(data, len);
103 QMetaObject::invokeMethod(this, "socketSentData", Qt::QueuedConnection);
104 return sentSize;
105 }
106
close()107 void SocketStreamHandlePrivate::close()
108 {
109 if (m_socket && m_socket->state() == QAbstractSocket::ConnectedState)
110 m_socket->close();
111 }
112
socketSentdata()113 void SocketStreamHandlePrivate::socketSentdata()
114 {
115 if (m_streamHandle)
116 m_streamHandle->sendPendingData();
117 }
118
socketClosed()119 void SocketStreamHandlePrivate::socketClosed()
120 {
121 QMetaObject::invokeMethod(this, "socketClosedCallback", Qt::QueuedConnection);
122 }
123
socketError(QAbstractSocket::SocketError error)124 void SocketStreamHandlePrivate::socketError(QAbstractSocket::SocketError error)
125 {
126 QMetaObject::invokeMethod(this, "socketErrorCallback", Qt::QueuedConnection, Q_ARG(int, error));
127 }
128
socketClosedCallback()129 void SocketStreamHandlePrivate::socketClosedCallback()
130 {
131 if (m_streamHandle && m_streamHandle->client()) {
132 SocketStreamHandle* streamHandle = m_streamHandle;
133 m_streamHandle = 0;
134 // This following call deletes _this_. Nothing should be after it.
135 streamHandle->client()->didClose(streamHandle);
136 }
137 }
138
socketErrorCallback(int error)139 void SocketStreamHandlePrivate::socketErrorCallback(int error)
140 {
141 // FIXME - in the future, we might not want to treat all errors as fatal.
142 if (m_streamHandle && m_streamHandle->client()) {
143 SocketStreamHandle* streamHandle = m_streamHandle;
144 m_streamHandle = 0;
145 // This following call deletes _this_. Nothing should be after it.
146 streamHandle->client()->didClose(streamHandle);
147 }
148 }
149
150 #ifndef QT_NO_OPENSSL
socketSslErrors(const QList<QSslError> &)151 void SocketStreamHandlePrivate::socketSslErrors(const QList<QSslError>&)
152 {
153 // FIXME: based on http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-68#page-15
154 // we should abort on certificate errors.
155 // We don't abort while this is still work in progress.
156 static_cast<QSslSocket*>(m_socket)->ignoreSslErrors();
157 }
158 #endif
159
SocketStreamHandle(const KURL & url,SocketStreamHandleClient * client)160 SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client)
161 : SocketStreamHandleBase(url, client)
162 {
163 LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
164 m_p = new SocketStreamHandlePrivate(this, url);
165 }
166
~SocketStreamHandle()167 SocketStreamHandle::~SocketStreamHandle()
168 {
169 LOG(Network, "SocketStreamHandle %p delete", this);
170 setClient(0);
171 delete m_p;
172 }
173
platformSend(const char * data,int len)174 int SocketStreamHandle::platformSend(const char* data, int len)
175 {
176 LOG(Network, "SocketStreamHandle %p platformSend", this);
177 return m_p->send(data, len);
178 }
179
platformClose()180 void SocketStreamHandle::platformClose()
181 {
182 LOG(Network, "SocketStreamHandle %p platformClose", this);
183 m_p->close();
184 }
185
didReceiveAuthenticationChallenge(const AuthenticationChallenge &)186 void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&)
187 {
188 notImplemented();
189 }
190
receivedCredential(const AuthenticationChallenge &,const Credential &)191 void SocketStreamHandle::receivedCredential(const AuthenticationChallenge&, const Credential&)
192 {
193 notImplemented();
194 }
195
receivedRequestToContinueWithoutCredential(const AuthenticationChallenge &)196 void SocketStreamHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&)
197 {
198 notImplemented();
199 }
200
receivedCancellation(const AuthenticationChallenge &)201 void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&)
202 {
203 notImplemented();
204 }
205
206 } // namespace WebCore
207
208 #include "moc_SocketStreamHandlePrivate.cpp"
209