2010-09-08 Martin Robinson <mrobinson@igalia.com>
authormrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 8 Sep 2010 15:27:17 +0000 (15:27 +0000)
committermrobinson@webkit.org <mrobinson@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 8 Sep 2010 15:27:17 +0000 (15:27 +0000)
        Reviewed by Xan Lopez.

        [GTK] Need a WebSocket implementation
        https://bugs.webkit.org/show_bug.cgi?id=45197

        * configure.ac: Enable WebSocket by default.
2010-09-08  Martin Robinson  <mrobinson@igalia.com>

        Reviewed by Xan Lopez.

        [GTK] Need a WebSocket implementation
        https://bugs.webkit.org/show_bug.cgi?id=45197

        Add a GIO-based WebSocket implementation.

        * wtf/gobject/GRefPtr.cpp: Added PlatformRefPtr support for GSource.
        (WTF::refPlatformPtr):
        (WTF::derefPlatformPtr):
        * wtf/gobject/GRefPtr.h: Added new template specialization declarations.
        * wtf/gobject/GTypedefs.h: Add some more GLib/GIO forward declarations.
2010-09-08  Martin Robinson  <mrobinson@igalia.com>

        Reviewed by Xan Lopez.

        [GTK] Need a WebSocket implementation
        https://bugs.webkit.org/show_bug.cgi?id=45197

        * platform/gtk/Skipped: Unskip all WebSocket tests, as they are passing.
2010-09-08  Martin Robinson  <mrobinson@igalia.com>

        Reviewed by Xan Lopez.

        [GTK] Need a WebSocket implementation
        https://bugs.webkit.org/show_bug.cgi?id=45197

        Add a GIO-based WebSocket implementation. This does not yet support
        SSL sockets or proxies, but these should be possible to add as support
        arrives in GLib/GIO for them.

        * platform/network/soup/SocketStreamHandle.h:
        * platform/network/soup/SocketStreamHandleSoup.cpp: Add a GIO-based WebSocket implementation.
        (WebCore::isActiveHandle): Added.
        (WebCore::deactivateHandle): Added.
        (WebCore::SocketStreamHandle::SocketStreamHandle): Filled out stub.
        (WebCore::SocketStreamHandle::~SocketStreamHandle): Ditto.
        (WebCore::SocketStreamHandle::connected): Added.
        (WebCore::SocketStreamHandle::readBytes): Added.
        (WebCore::SocketStreamHandle::writeReady): Added.
        (WebCore::SocketStreamHandle::platformSend): Filled out stub.
        (WebCore::SocketStreamHandle::platformClose): Filled out stub.
        (WebCore::SocketStreamHandle::beginWaitingForSocketWritability): Added.
        (WebCore::SocketStreamHandle::stopWaitingForSocketWritability):
        (WebCore::connectedCallback): Added.
        (WebCore::readReadyCallback): Added.
        (WebCore::writeReadyCallback): Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@66986 268f45cc-cd09-0410-ab3c-d52691b4dbfc

ChangeLog
JavaScriptCore/ChangeLog
JavaScriptCore/wtf/gobject/GRefPtr.cpp
JavaScriptCore/wtf/gobject/GRefPtr.h
JavaScriptCore/wtf/gobject/GTypedefs.h
LayoutTests/ChangeLog
LayoutTests/platform/gtk/Skipped
WebCore/ChangeLog
WebCore/platform/network/soup/SocketStreamHandle.h
WebCore/platform/network/soup/SocketStreamHandleSoup.cpp
configure.ac

index fe273ac..f262075 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2010-09-08  Martin Robinson  <mrobinson@igalia.com>
+
+        Reviewed by Xan Lopez.
+
+        [GTK] Need a WebSocket implementation
+        https://bugs.webkit.org/show_bug.cgi?id=45197
+
+        * configure.ac: Enable WebSocket by default.
+
 2010-09-08  Gyuyoung Kim  <gyuyoung.kim@samsung.com>
 
         Reviewed by Kenneth Rohde Christiansen.
index 0340a1c..9ca5b8c 100644 (file)
@@ -1,3 +1,18 @@
+2010-09-08  Martin Robinson  <mrobinson@igalia.com>
+
+        Reviewed by Xan Lopez.
+
+        [GTK] Need a WebSocket implementation
+        https://bugs.webkit.org/show_bug.cgi?id=45197
+
+        Add a GIO-based WebSocket implementation.
+
+        * wtf/gobject/GRefPtr.cpp: Added PlatformRefPtr support for GSource.
+        (WTF::refPlatformPtr):
+        (WTF::derefPlatformPtr):
+        * wtf/gobject/GRefPtr.h: Added new template specialization declarations.
+        * wtf/gobject/GTypedefs.h: Add some more GLib/GIO forward declarations.
+
 2010-08-30  Maciej Stachowiak  <mjs@apple.com>
 
         Reviewed by Darin Adler.
index c16024c..14f7cf4 100644 (file)
@@ -66,4 +66,17 @@ template <> void derefPlatformPtr(GVariant* ptr)
 
 #endif
 
+template <> GSource* refPlatformPtr(GSource* ptr)
+{
+    if (ptr)
+        g_source_ref(ptr);
+    return ptr;
+}
+
+template <> void derefPlatformPtr(GSource* ptr)
+{
+    if (ptr)
+        g_source_unref(ptr);
+}
+
 } // namespace WTF
index 1ca55ce..ede0a7a 100644 (file)
@@ -36,6 +36,8 @@ template <> GHashTable* refPlatformPtr(GHashTable* ptr);
 template <> void derefPlatformPtr(GHashTable* ptr);
 template <> GVariant* refPlatformPtr(GVariant* ptr);
 template <> void derefPlatformPtr(GVariant* ptr);
+template <> GSource* refPlatformPtr(GSource* ptr);
+template <> void derefPlatformPtr(GSource* ptr);
 
 template <typename T> inline T* refPlatformPtr(T* ptr)
 {
index ff9283e..e79ba33 100644 (file)
@@ -36,6 +36,8 @@ typedef unsigned long gulong;
 typedef unsigned short gushort;
 typedef void* gpointer;
 
+typedef struct _GAsyncResult GAsyncResult;
+typedef struct _GCancellable GCancellable;
 typedef struct _GCond GCond;
 typedef struct _GDir GDir;
 typedef struct _GdkAtom* GdkAtom;
@@ -47,9 +49,14 @@ typedef struct _GdkPixbuf GdkPixbuf;
 typedef struct _GError GError;
 typedef struct _GFile GFile;
 typedef struct _GHashTable GHashTable;
+typedef struct _GInputStream GInputStream;
 typedef struct _GList GList;
 typedef struct _GMutex GMutex;
+typedef struct _GOutputStream GOutputStream;
 typedef struct _GPatternSpec GPatternSpec;
+typedef struct _GSocketClient GSocketClient;
+typedef struct _GSocketConnection GSocketConnection;
+typedef struct _GSource GSource;
 typedef struct _GVariant GVariant;
 typedef union _GdkEvent GdkEvent;
 
index 43a2f18..bbfbbe0 100644 (file)
@@ -1,3 +1,12 @@
+2010-09-08  Martin Robinson  <mrobinson@igalia.com>
+
+        Reviewed by Xan Lopez.
+
+        [GTK] Need a WebSocket implementation
+        https://bugs.webkit.org/show_bug.cgi?id=45197
+
+        * platform/gtk/Skipped: Unskip all WebSocket tests, as they are passing.
+
 2010-09-08  Sergio Villar Senin  <svillar@igalia.com>
 
         Reviewed by Adam Barth.
index dd8405b..a3ee333 100644 (file)
@@ -5181,9 +5181,6 @@ fast/ruby/rubyDOM-remove-rt2.html
 fast/ruby/rubyDOM-remove-text1.html
 fast/ruby/rubyDOM-remove-text2.html
 
-# Missing SocketStreamHandle implementation
-websocket/tests
-
 # New color correction tests
 fast/css/color-correction-backgrounds-and-text.html
 fast/css/color-correction-on-backgrounds.html
index dd47ff7..2661247 100644 (file)
@@ -1,3 +1,31 @@
+2010-09-08  Martin Robinson  <mrobinson@igalia.com>
+
+        Reviewed by Xan Lopez.
+
+        [GTK] Need a WebSocket implementation
+        https://bugs.webkit.org/show_bug.cgi?id=45197
+
+        Add a GIO-based WebSocket implementation. This does not yet support
+        SSL sockets or proxies, but these should be possible to add as support
+        arrives in GLib/GIO for them.
+
+        * platform/network/soup/SocketStreamHandle.h:
+        * platform/network/soup/SocketStreamHandleSoup.cpp: Add a GIO-based WebSocket implementation.
+        (WebCore::isActiveHandle): Added.
+        (WebCore::deactivateHandle): Added.
+        (WebCore::SocketStreamHandle::SocketStreamHandle): Filled out stub.
+        (WebCore::SocketStreamHandle::~SocketStreamHandle): Ditto.
+        (WebCore::SocketStreamHandle::connected): Added.
+        (WebCore::SocketStreamHandle::readBytes): Added.
+        (WebCore::SocketStreamHandle::writeReady): Added.
+        (WebCore::SocketStreamHandle::platformSend): Filled out stub.
+        (WebCore::SocketStreamHandle::platformClose): Filled out stub.
+        (WebCore::SocketStreamHandle::beginWaitingForSocketWritability): Added.
+        (WebCore::SocketStreamHandle::stopWaitingForSocketWritability):
+        (WebCore::connectedCallback): Added.
+        (WebCore::readReadyCallback): Added.
+        (WebCore::writeReadyCallback): Added.
+
 2010-09-07  Martin Robinson  <mrobinson@igalia.com>
 
         Reviewed by Dirk Schulze.
index 64139e5..2ba4504 100644 (file)
@@ -32,8 +32,8 @@
 #ifndef SocketStreamHandle_h
 #define SocketStreamHandle_h
 
+#include "GRefPtr.h"
 #include "SocketStreamHandleBase.h"
-
 #include <wtf/PassRefPtr.h>
 #include <wtf/RefCounted.h>
 
@@ -48,12 +48,21 @@ namespace WebCore {
         static PassRefPtr<SocketStreamHandle> create(const KURL& url, SocketStreamHandleClient* client) { return adoptRef(new SocketStreamHandle(url, client)); }
 
         virtual ~SocketStreamHandle();
+        void connected(GSocketConnection*, GError*);
+        void readBytes(signed long, GError*);
+        void writeReady();
 
     protected:
         virtual int platformSend(const char* data, int length);
         virtual void platformClose();
 
     private:
+        PlatformRefPtr<GSocketConnection> m_socketConnection;
+        PlatformRefPtr<GInputStream> m_inputStream;
+        PlatformRefPtr<GOutputStream> m_outputStream;
+        PlatformRefPtr<GSource> m_writeReadySource;
+        char* m_readBuffer;
+
         SocketStreamHandle(const KURL&, SocketStreamHandleClient*);
 
         // No authentication for streams per se, but proxy may ask for credentials.
@@ -61,6 +70,8 @@ namespace WebCore {
         void receivedCredential(const AuthenticationChallenge&, const Credential&);
         void receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&);
         void receivedCancellation(const AuthenticationChallenge&);
+        void beginWaitingForSocketWritability();
+        void stopWaitingForSocketWritability();
     };
 
 }  // namespace WebCore
index 6aa33fc..d73b499 100644 (file)
 #include "config.h"
 #include "SocketStreamHandle.h"
 
+#include "CString.h"
+#include "GOwnPtr.h"
 #include "KURL.h"
 #include "Logging.h"
+#include "NotFound.h"
 #include "NotImplemented.h"
+#include "SocketStreamError.h"
 #include "SocketStreamHandleClient.h"
+#include "Vector.h"
+#include <gio/gio.h>
+#include <glib.h>
+
+#define READ_BUFFER_SIZE 1024
 
 namespace WebCore {
 
+// These functions immediately call the similarly named SocketStreamHandle methods.
+static void connectedCallback(GSocketClient*, GAsyncResult*, SocketStreamHandle*);
+static void readReadyCallback(GInputStream*, GAsyncResult*, SocketStreamHandle*);
+static gboolean writeReadyCallback(GSocket*, GIOCondition, SocketStreamHandle*);
+
+// Having a list of active handles means that we do not have to worry about WebCore
+// reference counting in GLib callbacks. Once the handle is off the active handles list
+// we just ignore it in the callback. We avoid a lot of extra checks and tricky
+// situations this way.
+static Vector<SocketStreamHandle*> gActiveHandles;
+bool isActiveHandle(SocketStreamHandle* handle)
+{
+    return gActiveHandles.find(handle) != notFound;
+}
+
+void deactivateHandle(SocketStreamHandle* handle)
+{
+    size_t handleIndex = gActiveHandles.find(handle);
+    if (handleIndex != notFound)
+        gActiveHandles.remove(handleIndex);
+}
+
 SocketStreamHandle::SocketStreamHandle(const KURL& url, SocketStreamHandleClient* client)
     : SocketStreamHandleBase(url, client)
+    , m_readBuffer(0)
 {
-    LOG(Network, "SocketStreamHandle %p new client %p", this, m_client);
-    notImplemented();
+    // No support for SSL sockets yet.
+    if (url.protocolIs("wss"))
+        return;
+    unsigned int port = url.hasPort() ? url.port() : 80;
+
+    gActiveHandles.append(this);
+    PlatformRefPtr<GSocketClient> socketClient = adoptPlatformRef(g_socket_client_new());
+    g_socket_client_connect_to_host_async(socketClient.get(), url.host().utf8().data(), port, 0,
+        reinterpret_cast<GAsyncReadyCallback>(connectedCallback), this);
 }
 
 SocketStreamHandle::~SocketStreamHandle()
 {
-    LOG(Network, "SocketStreamHandle %p delete", this);
+    // If for some reason we were destroyed without closing, ensure that we are deactivated.
+    deactivateHandle(this);
     setClient(0);
-    notImplemented();
 }
 
-int SocketStreamHandle::platformSend(const char*, int)
+void SocketStreamHandle::connected(GSocketConnection* socketConnection, GError* error)
 {
-    LOG(Network, "SocketStreamHandle %p platformSend", this);
-    notImplemented();
-    return 0;
+    if (error) {
+        m_client->didFail(this, SocketStreamError(error->code));
+        return;
+    }
+
+    m_socketConnection = adoptPlatformRef(socketConnection);
+    m_outputStream = g_io_stream_get_output_stream(G_IO_STREAM(m_socketConnection.get()));
+    m_inputStream = g_io_stream_get_input_stream(G_IO_STREAM(m_socketConnection.get()));
+
+    m_readBuffer = new char[READ_BUFFER_SIZE];
+    g_input_stream_read_async(m_inputStream.get(), m_readBuffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, 0,
+        reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), this);
+
+    // The client can close the handle, potentially removing the last reference.
+    RefPtr<SocketStreamHandle> protect(this); 
+    m_state = Open;
+    m_client->didOpen(this);
+    if (!m_socketConnection) // Client closed the connection.
+        return;
+}
+
+void SocketStreamHandle::readBytes(signed long bytesRead, GError* error)
+{
+    if (error) {
+        m_client->didFail(this, SocketStreamError(error->code));
+        return;
+    }
+
+    if (!bytesRead) {
+        close();
+        return;
+    }
+
+    // The client can close the handle, potentially removing the last reference.
+    RefPtr<SocketStreamHandle> protect(this); 
+    m_client->didReceiveData(this, m_readBuffer, bytesRead);
+    if (m_inputStream) // The client may have closed the connection.
+        g_input_stream_read_async(m_inputStream.get(), m_readBuffer, READ_BUFFER_SIZE, G_PRIORITY_DEFAULT, 0,
+            reinterpret_cast<GAsyncReadyCallback>(readReadyCallback), this);
+}
+
+void SocketStreamHandle::writeReady()
+{
+    // We no longer have buffered data, so stop waiting for the socket to be writable.
+    if (!bufferedAmount()) {
+        stopWaitingForSocketWritability();
+        return;
+    }
+
+    sendPendingData();
+}
+
+int SocketStreamHandle::platformSend(const char* data, int length)
+{
+    if (!g_socket_condition_check(g_socket_connection_get_socket(m_socketConnection.get()), G_IO_OUT)) {
+        beginWaitingForSocketWritability();
+        return 0;
+    }
+
+    GOwnPtr<GError> error;
+    gssize written = g_output_stream_write(m_outputStream.get(), data, length, 0, &error.outPtr());
+    if (error) {
+        m_client->didFail(this, SocketStreamError(error->code)); // FIXME: Provide a sensible error.
+        return 0;
+    }
+
+    // If we did not send all the bytes we were given, we know that
+    // SocketStreamHandleBase will need to send more in the future.
+    if (written < length)
+        beginWaitingForSocketWritability();
+
+    return written;
 }
 
 void SocketStreamHandle::platformClose()
 {
-    LOG(Network, "SocketStreamHandle %p platformClose", this);
-    notImplemented();
+    // We remove this handle from the active handles list first, to disable all callbacks.
+    deactivateHandle(this);
+    stopWaitingForSocketWritability();
+
+    if (m_socketConnection) {
+        GOwnPtr<GError> error;
+        g_io_stream_close(G_IO_STREAM(m_socketConnection.get()), 0, &error.outPtr());
+        if (error)
+            m_client->didFail(this, SocketStreamError(error->code)); // FIXME: Provide a sensible error.
+        m_socketConnection = 0;
+    }
+
+    m_outputStream = 0;
+    m_inputStream = 0;
+    delete m_readBuffer;
+
+    m_client->didClose(this);
 }
 
 void SocketStreamHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&)
@@ -85,4 +208,70 @@ void SocketStreamHandle::receivedCancellation(const AuthenticationChallenge&)
     notImplemented();
 }
 
+void SocketStreamHandle::beginWaitingForSocketWritability()
+{
+    if (m_writeReadySource) // Already waiting.
+        return;
+
+    m_writeReadySource = adoptPlatformRef(g_socket_create_source(
+        g_socket_connection_get_socket(m_socketConnection.get()), static_cast<GIOCondition>(G_IO_OUT), 0));
+    g_source_set_callback(m_writeReadySource.get(), reinterpret_cast<GSourceFunc>(writeReadyCallback), this, 0);
+    g_source_attach(m_writeReadySource.get(), 0);
+}
+
+void SocketStreamHandle::stopWaitingForSocketWritability()
+{
+    if (!m_writeReadySource) // Not waiting.
+        return;
+
+    g_source_remove(g_source_get_id(m_writeReadySource.get()));
+    m_writeReadySource = 0;
+}
+
+static void connectedCallback(GSocketClient* client, GAsyncResult* result, SocketStreamHandle* handle)
+{
+    // Always finish the connection, even if this SocketStreamHandle was deactivated earlier.
+    GOwnPtr<GError> error;
+    GSocketConnection* socketConnection = g_socket_client_connect_to_host_finish(client, result, &error.outPtr());
+
+    // The SocketStreamHandle has been deactivated, so just close the connection, ignoring errors.
+    if (!isActiveHandle(handle)) {
+        g_io_stream_close(G_IO_STREAM(socketConnection), 0, &error.outPtr());
+        return;
+    }
+
+    handle->connected(socketConnection, error.get());
+}
+
+static void readReadyCallback(GInputStream* stream, GAsyncResult* result, SocketStreamHandle* handle)
+{
+    // Always finish the read, even if this SocketStreamHandle was deactivated earlier.
+    GOwnPtr<GError> error;
+    gssize bytesRead = g_input_stream_read_finish(stream, result, &error.outPtr());
+
+    if (!isActiveHandle(handle))
+        return;
+    handle->readBytes(bytesRead, error.get());
+}
+
+static gboolean writeReadyCallback(GSocket*, GIOCondition condition, SocketStreamHandle* handle)
+{
+    if (!isActiveHandle(handle))
+        return FALSE;
+
+    // G_IO_HUP and G_IO_ERR are are always active. See:
+    // http://library.gnome.org/devel/gio/stable/GSocket.html#g-socket-create-source
+    if (condition & G_IO_HUP) {
+        handle->close();
+        return FALSE;
+    }
+    if (condition & G_IO_ERR) {
+        handle->client()->didFail(handle, SocketStreamError(0)); // FIXME: Provide a sensible error.
+        return FALSE;
+    }
+    if (condition & G_IO_OUT)
+        handle->writeReady();
+    return TRUE;
+}
+
 }  // namespace WebCore
index 64908a2..2e93cd3 100644 (file)
@@ -628,8 +628,8 @@ fi
 AC_MSG_CHECKING([whether to enable Web Sockets support])
 AC_ARG_ENABLE(web_sockets,
               AC_HELP_STRING([--enable-web-sockets],
-                             [enable support for Web Sockets [default=no]]),
-              [],[enable_web_sockets="no"])
+                             [enable support for Web Sockets [default=yes]]),
+              [],[enable_web_sockets="yes"])
 AC_MSG_RESULT([$enable_web_sockets])
 
 # check whether to enable Web Timing support