InspectorServerQt.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /*
  2. Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
  3. This library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Library General Public
  5. License as published by the Free Software Foundation; either
  6. version 2 of the License, or (at your option) any later version.
  7. This library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Library General Public License for more details.
  11. You should have received a copy of the GNU Library General Public License
  12. along with this library; see the file COPYING.LIB. If not, write to
  13. the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  14. Boston, MA 02110-1301, USA.
  15. */
  16. #include "config.h"
  17. #include "InspectorServerQt.h"
  18. #include "InspectorClientQt.h"
  19. #include "InspectorController.h"
  20. #include "Page.h"
  21. #include "QWebFrameAdapter.h"
  22. #include "QWebPageAdapter.h"
  23. #include "qhttpheader_p.h"
  24. #include <QFile>
  25. #include <QString>
  26. #include <QStringList>
  27. #include <QTcpServer>
  28. #include <QTcpSocket>
  29. #include <QUrl>
  30. #include <qendian.h>
  31. #include <wtf/SHA1.h>
  32. #include <wtf/text/Base64.h>
  33. #include <wtf/text/CString.h>
  34. namespace WebCore {
  35. /*!
  36. Computes the WebSocket handshake response given the input key
  37. */
  38. static QByteArray generateWebSocketChallengeResponse(const QByteArray& key)
  39. {
  40. SHA1 sha1;
  41. Vector<uint8_t, 20> digest;
  42. Vector<char> encoded;
  43. QByteArray toHash("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
  44. toHash.prepend(key);
  45. sha1.addBytes((uint8_t*)toHash.data(), toHash.size());
  46. sha1.computeHash(digest);
  47. base64Encode((char*)digest.data(), digest.size(), encoded);
  48. return QByteArray(encoded.data(), encoded.size());
  49. }
  50. static InspectorServerQt* s_inspectorServer;
  51. InspectorServerQt* InspectorServerQt::server()
  52. {
  53. // s_inspectorServer is deleted in unregisterClient() when the last client is unregistered.
  54. if (!s_inspectorServer)
  55. s_inspectorServer = new InspectorServerQt();
  56. return s_inspectorServer;
  57. }
  58. InspectorServerQt::InspectorServerQt()
  59. : QObject()
  60. , m_tcpServer(0)
  61. , m_pageNumber(1)
  62. {
  63. }
  64. InspectorServerQt::~InspectorServerQt()
  65. {
  66. close();
  67. }
  68. void InspectorServerQt::listen(quint16 port)
  69. {
  70. if (m_tcpServer)
  71. return;
  72. m_tcpServer = new QTcpServer();
  73. m_tcpServer->listen(QHostAddress::Any, port);
  74. connect(m_tcpServer, SIGNAL(newConnection()), SLOT(newConnection()));
  75. }
  76. void InspectorServerQt::close()
  77. {
  78. if (m_tcpServer) {
  79. m_tcpServer->close();
  80. delete m_tcpServer;
  81. }
  82. m_tcpServer = 0;
  83. }
  84. InspectorClientQt* InspectorServerQt::inspectorClientForPage(int pageNum)
  85. {
  86. InspectorClientQt* client = m_inspectorClients.value(pageNum);
  87. return client;
  88. }
  89. void InspectorServerQt::registerClient(InspectorClientQt* client)
  90. {
  91. if (!m_inspectorClients.key(client))
  92. m_inspectorClients.insert(m_pageNumber++, client);
  93. }
  94. void InspectorServerQt::unregisterClient(InspectorClientQt* client)
  95. {
  96. int pageNum = m_inspectorClients.key(client, -1);
  97. if (pageNum >= 0)
  98. m_inspectorClients.remove(pageNum);
  99. if (!m_inspectorClients.size()) {
  100. // s_inspectorServer points to this.
  101. s_inspectorServer = 0;
  102. close();
  103. deleteLater();
  104. }
  105. }
  106. void InspectorServerQt::newConnection()
  107. {
  108. QTcpSocket* tcpConnection = m_tcpServer->nextPendingConnection();
  109. InspectorServerRequestHandlerQt* handler = new InspectorServerRequestHandlerQt(tcpConnection, this);
  110. handler->setParent(this);
  111. }
  112. InspectorServerRequestHandlerQt::InspectorServerRequestHandlerQt(QTcpSocket* tcpConnection, InspectorServerQt* server)
  113. : QObject(server)
  114. , m_tcpConnection(tcpConnection)
  115. , m_server(server)
  116. , m_inspectorClient(0)
  117. {
  118. m_endOfHeaders = false;
  119. m_contentLength = 0;
  120. connect(m_tcpConnection, SIGNAL(readyRead()), SLOT(tcpReadyRead()));
  121. connect(m_tcpConnection, SIGNAL(disconnected()), SLOT(tcpConnectionDisconnected()));
  122. }
  123. InspectorServerRequestHandlerQt::~InspectorServerRequestHandlerQt()
  124. {
  125. }
  126. void InspectorServerRequestHandlerQt::tcpReadyRead()
  127. {
  128. WebKit::QHttpRequestHeader header;
  129. bool isWebSocket = false;
  130. if (!m_tcpConnection)
  131. return;
  132. if (!m_endOfHeaders) {
  133. while (m_tcpConnection->bytesAvailable() && !m_endOfHeaders) {
  134. QByteArray line = m_tcpConnection->readLine();
  135. m_data.append(line);
  136. if (line == "\r\n")
  137. m_endOfHeaders = true;
  138. }
  139. if (m_endOfHeaders) {
  140. header = WebKit::QHttpRequestHeader(QString::fromLatin1(m_data));
  141. if (header.isValid()) {
  142. m_path = header.path();
  143. m_contentType = header.contentType().toLatin1();
  144. m_contentLength = header.contentLength();
  145. if (header.hasKey(QLatin1String("Upgrade")) && (header.value(QLatin1String("Upgrade")) == QLatin1String("websocket")))
  146. isWebSocket = true;
  147. m_data.clear();
  148. }
  149. }
  150. }
  151. if (m_endOfHeaders) {
  152. QStringList pathAndQuery = m_path.split(QLatin1Char('?'));
  153. m_path = pathAndQuery[0];
  154. QStringList words = m_path.split(QLatin1Char('/'));
  155. if (isWebSocket) {
  156. // switch to websocket-style WebSocketService messaging
  157. if (m_tcpConnection) {
  158. m_tcpConnection->disconnect(SIGNAL(readyRead()));
  159. connect(m_tcpConnection, SIGNAL(readyRead()), SLOT(webSocketReadyRead()), Qt::QueuedConnection);
  160. QByteArray key = header.value(QLatin1String("Sec-WebSocket-Key")).toLatin1();
  161. QString accept = QString::fromLatin1(generateWebSocketChallengeResponse(key));
  162. WebKit::QHttpResponseHeader responseHeader(101, QLatin1String("WebSocket Protocol Handshake"), 1, 1);
  163. responseHeader.setValue(QLatin1String("Upgrade"), header.value(QLatin1String("Upgrade")));
  164. responseHeader.setValue(QLatin1String("Connection"), header.value(QLatin1String("Connection")));
  165. responseHeader.setValue(QLatin1String("Sec-WebSocket-Accept"), accept);
  166. m_tcpConnection->write(responseHeader.toString().toLatin1());
  167. m_tcpConnection->flush();
  168. if ((words.size() == 4)
  169. && (words[1] == QString::fromLatin1("devtools"))
  170. && (words[2] == QString::fromLatin1("page"))) {
  171. int pageNum = words[3].toInt();
  172. m_inspectorClient = m_server->inspectorClientForPage(pageNum);
  173. // Attach remoteFrontendChannel to inspector, also transferring ownership.
  174. if (m_inspectorClient)
  175. m_inspectorClient->attachAndReplaceRemoteFrontend(this);
  176. }
  177. }
  178. return;
  179. }
  180. if (m_contentLength && (m_tcpConnection->bytesAvailable() < m_contentLength))
  181. return;
  182. QByteArray content = m_tcpConnection->read(m_contentLength);
  183. m_endOfHeaders = false;
  184. QByteArray response;
  185. int code = 200;
  186. QString text = QString::fromLatin1("OK");
  187. // If no path is specified, generate an index page.
  188. if (m_path.isEmpty() || (m_path == QString(QLatin1Char('/')))) {
  189. QString indexHtml = QLatin1String("<html><head><title>Remote Web Inspector</title></head><body><ul>\n");
  190. for (QMap<int, InspectorClientQt* >::const_iterator it = m_server->m_inspectorClients.begin(); it != m_server->m_inspectorClients.end(); ++it) {
  191. indexHtml.append(QString::fromLatin1("<li><a href=\"/webkit/inspector/inspector.html?page=%1\">%2</li>\n")
  192. .arg(it.key())
  193. .arg(QUrl(it.value()->m_inspectedWebPage->mainFrameAdapter()->url).toString()));
  194. }
  195. indexHtml.append(QLatin1String("</ul></body></html>"));
  196. response = indexHtml.toLatin1();
  197. } else {
  198. QString path = QString::fromLatin1(":%1").arg(m_path);
  199. QFile file(path);
  200. // It seems that there should be an enum or define for these status codes somewhere in Qt or WebKit,
  201. // but grep fails to turn one up.
  202. // QNetwork uses the numeric values directly.
  203. if (file.exists()) {
  204. file.open(QIODevice::ReadOnly);
  205. response = file.readAll();
  206. } else {
  207. code = 404;
  208. text = QString::fromLatin1("Not OK");
  209. }
  210. }
  211. WebKit::QHttpResponseHeader responseHeader(code, text, 1, 0);
  212. responseHeader.setContentLength(response.size());
  213. if (!m_contentType.isEmpty())
  214. responseHeader.setContentType(QString::fromLatin1(m_contentType));
  215. QByteArray asciiHeader = responseHeader.toString().toLatin1();
  216. m_tcpConnection->write(asciiHeader);
  217. m_tcpConnection->write(response);
  218. m_tcpConnection->flush();
  219. m_tcpConnection->close();
  220. return;
  221. }
  222. }
  223. void InspectorServerRequestHandlerQt::tcpConnectionDisconnected()
  224. {
  225. if (m_inspectorClient)
  226. m_inspectorClient->detachRemoteFrontend();
  227. m_tcpConnection->deleteLater();
  228. m_tcpConnection = 0;
  229. }
  230. int InspectorServerRequestHandlerQt::webSocketSend(const QString& message)
  231. {
  232. QByteArray payload = message.toUtf8();
  233. return webSocketSend(payload.data(), payload.size());
  234. }
  235. int InspectorServerRequestHandlerQt::webSocketSend(const char* data, size_t length)
  236. {
  237. Q_ASSERT(m_tcpConnection);
  238. m_tcpConnection->putChar(0x81);
  239. if (length <= 125)
  240. m_tcpConnection->putChar(static_cast<uint8_t>(length));
  241. else if (length <= pow(2, 16)) {
  242. m_tcpConnection->putChar(126);
  243. quint16 length16 = qToBigEndian<quint16>(static_cast<quint16>(length));
  244. m_tcpConnection->write(reinterpret_cast<char*>(&length16), 2);
  245. } else {
  246. m_tcpConnection->putChar(127);
  247. quint64 length64 = qToBigEndian<quint64>(static_cast<quint64>(length));
  248. m_tcpConnection->write(reinterpret_cast<char*>(&length64), 8);
  249. }
  250. int nBytes = m_tcpConnection->write(data, length);
  251. m_tcpConnection->flush();
  252. return nBytes;
  253. }
  254. static QByteArray applyMask(const QByteArray& payload, const QByteArray& maskingKey)
  255. {
  256. Q_ASSERT(maskingKey.size() == 4);
  257. QByteArray unmaskedPayload;
  258. for (int i = 0; i < payload.size(); ++i) {
  259. char unmaskedByte = payload[i] ^ maskingKey[i % 4];
  260. unmaskedPayload.append(unmaskedByte);
  261. }
  262. return unmaskedPayload;
  263. }
  264. void InspectorServerRequestHandlerQt::webSocketReadyRead()
  265. {
  266. Q_ASSERT(m_tcpConnection);
  267. if (!m_tcpConnection->bytesAvailable())
  268. return;
  269. QByteArray content = m_tcpConnection->read(m_tcpConnection->bytesAvailable());
  270. m_data.append(content);
  271. while (m_data.size() > 0) {
  272. const bool isMasked = m_data[1] & 0x80;
  273. quint64 payloadLen = m_data[1] & 0x7F;
  274. int pos = 2;
  275. if (payloadLen == 126) {
  276. payloadLen = qFromBigEndian<quint16>(*reinterpret_cast<quint16*>(m_data.mid(pos, 2).data()));
  277. pos = 4;
  278. } else if (payloadLen == 127) {
  279. payloadLen = qFromBigEndian<quint64>(*reinterpret_cast<quint64*>(m_data.mid(pos, 8).data()));
  280. pos = 8;
  281. }
  282. QByteArray payload;
  283. if (isMasked) {
  284. QByteArray maskingKey = m_data.mid(pos, 4);
  285. pos += 4;
  286. payload = applyMask(m_data.mid(pos, payloadLen), maskingKey);
  287. } else
  288. payload = m_data.mid(pos, payloadLen);
  289. // Handle fragmentation
  290. if (!(m_data[0] & 0x80)) { // Non-last fragmented payload
  291. m_fragmentedPayload.append(payload);
  292. m_data = m_data.mid(pos + payloadLen);
  293. continue;
  294. }
  295. if (!(m_data[0] & 0x0F)) { // Last fragment
  296. m_fragmentedPayload.append(payload);
  297. payload = m_fragmentedPayload;
  298. m_fragmentedPayload.clear();
  299. }
  300. // Remove this WebSocket message from m_data (payload, start-of-frame byte, end-of-frame byte).
  301. // Truncate data before delivering message in case of re-entrancy.
  302. m_data = m_data.mid(pos + payloadLen);
  303. #if ENABLE(INSPECTOR)
  304. if (m_inspectorClient) {
  305. InspectorController* inspectorController = m_inspectorClient->m_inspectedWebPage->page->inspectorController();
  306. inspectorController->dispatchMessageFromFrontend(QString::fromUtf8(payload));
  307. }
  308. #endif
  309. }
  310. }
  311. }
  312. #include "moc_InspectorServerQt.cpp"