Changeset 94399 in webkit


Ignore:
Timestamp:
Sep 2, 2011, 3:36:43 AM (14 years ago)
Author:
yutak@chromium.org
Message:

WebSocket: Send Blob as WebSocket binary message
https://bugs.webkit.org/show_bug.cgi?id=67465

Reviewed by Kent Tamura.

Source/WebCore:

Tests: http/tests/websocket/tests/hixie76/send-empty.html

http/tests/websocket/tests/hixie76/send-object.html
http/tests/websocket/tests/hybi/send-blob.html
http/tests/websocket/tests/hybi/send-empty.html
http/tests/websocket/tests/hybi/send-file-blob-fail.html
http/tests/websocket/tests/hybi/send-file-blob.html
http/tests/websocket/tests/hybi/workers/send-blob.html
http/tests/websocket/tests/hybi/bufferedAmount-after-close.html (updated)

  • bindings/js/JSWebSocketCustom.cpp:

(WebCore::JSWebSocket::send):

  • bindings/v8/custom/V8WebSocketCustom.cpp:

(WebCore::V8WebSocket::sendCallback):

  • websockets/ThreadableWebSocketChannel.h:
  • websockets/WebSocket.cpp:

(WebCore::WebSocket::send):

  • websockets/WebSocket.h:
  • websockets/WebSocket.idl:

Fixing code generator did not sound easy, because there are some classes depending on
broken behavior of current code generator (one such example is CanvasRenderingContext2D).
As a temporary workaround, new custom handlers for send() are added.

  • websockets/WebSocketChannel.cpp:

(WebCore::WebSocketChannel::send):

  • websockets/WebSocketChannel.h:
  • websockets/WorkerThreadableWebSocketChannel.cpp:

(WebCore::WorkerThreadableWebSocketChannel::send):
(WebCore::WorkerThreadableWebSocketChannel::Peer::send):
(WebCore::WorkerThreadableWebSocketChannel::mainThreadSendBlob):
A Blob can be deserialized from url, type and size.
(WebCore::WorkerThreadableWebSocketChannel::Bridge::send):
KURL, String and long long (corresponding to url, type and size, respectively) can be passed
safely across threads.

  • websockets/WorkerThreadableWebSocketChannel.h:

LayoutTests:

  • http/tests/websocket/tests/hixie76/send-empty-expected.txt: Added.
  • http/tests/websocket/tests/hixie76/send-empty.html: Added.
  • http/tests/websocket/tests/hixie76/send-object-expected.txt: Added.
  • http/tests/websocket/tests/hixie76/send-object.html: Added.
  • http/tests/websocket/tests/hybi/bufferedAmount-after-close-expected.txt:
  • http/tests/websocket/tests/hybi/bufferedAmount-after-close.html:

Updated. Added tests to send Blobs.

  • http/tests/websocket/tests/hybi/send-blob-expected.txt: Added.
  • http/tests/websocket/tests/hybi/send-blob.html:

Added. Send three Blobs each of which contains a small binary message.

  • http/tests/websocket/tests/hybi/send-blob_wsh.py:

Added. receive_message() returns a unicode value if the received message was text, or
a str value if the message was binary.

  • http/tests/websocket/tests/hybi/send-empty-expected.txt: Added.
  • http/tests/websocket/tests/hybi/send-empty.html: Added.
  • http/tests/websocket/tests/hybi/send-file-blob-expected.txt: Added.
  • http/tests/websocket/tests/hybi/send-file-blob-fail-expected.txt: Added.
  • http/tests/websocket/tests/hybi/send-file-blob-fail.html:

Added. If we delete a file before reading it, FileReaderLoader reliably fails.

  • http/tests/websocket/tests/hybi/send-file-blob.html:

Added. Create a File and try to send it as a Blob.

  • http/tests/websocket/tests/hybi/send-file-blob_wsh.py: Added.
  • http/tests/websocket/tests/hybi/workers/resources/send-blob.js:

Added. Same as send-blob.html above.

  • http/tests/websocket/tests/hybi/workers/resources/send-blob_wsh.py:

Added. Same as send-blob_wsh.py above.

  • http/tests/websocket/tests/hybi/workers/send-blob-expected.txt: Added.
  • http/tests/websocket/tests/hybi/workers/send-blob.html: Added.
  • platform/gtk/Skipped:

send-file-blob.html and send-file-blob-fail.html depend on availability of File API.

  • platform/mac/Skipped: Ditto.
  • platform/qt/Skipped: Ditto.
  • platform/win/Skipped: Ditto.
Location:
trunk
Files:
18 added
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r94395 r94399  
     12011-09-02  Yuta Kitamura  <yutak@chromium.org>
     2
     3        WebSocket: Send Blob as WebSocket binary message
     4        https://bugs.webkit.org/show_bug.cgi?id=67465
     5
     6        Reviewed by Kent Tamura.
     7
     8        * http/tests/websocket/tests/hixie76/send-empty-expected.txt: Added.
     9        * http/tests/websocket/tests/hixie76/send-empty.html: Added.
     10        * http/tests/websocket/tests/hixie76/send-object-expected.txt: Added.
     11        * http/tests/websocket/tests/hixie76/send-object.html: Added.
     12        * http/tests/websocket/tests/hybi/bufferedAmount-after-close-expected.txt:
     13        * http/tests/websocket/tests/hybi/bufferedAmount-after-close.html:
     14        Updated. Added tests to send Blobs.
     15        * http/tests/websocket/tests/hybi/send-blob-expected.txt: Added.
     16        * http/tests/websocket/tests/hybi/send-blob.html:
     17        Added. Send three Blobs each of which contains a small binary message.
     18        * http/tests/websocket/tests/hybi/send-blob_wsh.py:
     19        Added. receive_message() returns a unicode value if the received message was text, or
     20        a str value if the message was binary.
     21        * http/tests/websocket/tests/hybi/send-empty-expected.txt: Added.
     22        * http/tests/websocket/tests/hybi/send-empty.html: Added.
     23        * http/tests/websocket/tests/hybi/send-file-blob-expected.txt: Added.
     24        * http/tests/websocket/tests/hybi/send-file-blob-fail-expected.txt: Added.
     25        * http/tests/websocket/tests/hybi/send-file-blob-fail.html:
     26        Added. If we delete a file before reading it, FileReaderLoader reliably fails.
     27        * http/tests/websocket/tests/hybi/send-file-blob.html:
     28        Added. Create a File and try to send it as a Blob.
     29        * http/tests/websocket/tests/hybi/send-file-blob_wsh.py: Added.
     30        * http/tests/websocket/tests/hybi/workers/resources/send-blob.js:
     31        Added. Same as send-blob.html above.
     32        * http/tests/websocket/tests/hybi/workers/resources/send-blob_wsh.py:
     33        Added. Same as send-blob_wsh.py above.
     34        * http/tests/websocket/tests/hybi/workers/send-blob-expected.txt: Added.
     35        * http/tests/websocket/tests/hybi/workers/send-blob.html: Added.
     36        * platform/gtk/Skipped:
     37        send-file-blob.html and send-file-blob-fail.html depend on availability of File API.
     38        * platform/mac/Skipped: Ditto.
     39        * platform/qt/Skipped: Ditto.
     40        * platform/win/Skipped: Ditto.
     41
    1422011-09-02  Philippe Normand  <pnormand@igalia.com>
    243
  • trunk/LayoutTests/http/tests/websocket/tests/hybi/bufferedAmount-after-close-expected.txt

    r94282 r94399  
    77PASS ws.readyState is 3
    88PASS ws.bufferedAmount is 0
     9Testing send(string)...
    910PASS ws.send(messageToSend) is false
    1011PASS bufferedAmountDifference is 27
     12PASS ws.send(messageToSend) is false
     13PASS bufferedAmountDifference is 6
     14PASS ws.send(messageToSend) is false
     15PASS bufferedAmountDifference is 7
     16PASS ws.send(messageToSend) is false
     17PASS bufferedAmountDifference is 131
     18PASS ws.send(messageToSend) is false
     19PASS bufferedAmountDifference is 134
     20PASS ws.send(messageToSend) is false
     21PASS bufferedAmountDifference is 65543
     22PASS ws.send(messageToSend) is false
     23PASS bufferedAmountDifference is 65550
     24Testing send(Blob)...
    1125PASS ws.send(messageToSend) is false
    1226PASS bufferedAmountDifference is 6
  • trunk/LayoutTests/http/tests/websocket/tests/hybi/bufferedAmount-after-close.html

    r94282 r94399  
    2323}
    2424
     25function createBlobWithLength(length)
     26{
     27    var builder = new WebKitBlobBuilder();
     28    builder.append(new ArrayBuffer(length));
     29    return builder.getBlob();
     30}
     31
    2532var ws = new WebSocket("ws://localhost:8880/websocket/tests/hybi/simple");
    2633
     
    3845
    3946    var baseOverhead = 2 + 4; // Base header size and masking key size.
     47    debug("Testing send(string)...");
    4048    testBufferedAmount('send to closed socket', 21 + baseOverhead);
    4149    testBufferedAmount('', baseOverhead);
     
    4553    testBufferedAmount(createStringWithLength(0xFFFF), 0xFFFF + baseOverhead + 2);
    4654    testBufferedAmount(createStringWithLength(0x10000), 0x10000 + baseOverhead + 8); // With 64-bit extended payload length field.
     55
     56    debug("Testing send(Blob)...");
     57    testBufferedAmount(createBlobWithLength(0), baseOverhead);
     58    testBufferedAmount(createBlobWithLength(1), 1 + baseOverhead);
     59    testBufferedAmount(createBlobWithLength(125), 125 + baseOverhead);
     60    testBufferedAmount(createBlobWithLength(126), 126 + baseOverhead + 2);
     61    testBufferedAmount(createBlobWithLength(0xFFFF), 0xFFFF + baseOverhead + 2);
     62    testBufferedAmount(createBlobWithLength(0x10000), 0x10000 + baseOverhead + 8);
    4763
    4864    finishJSTest();
  • trunk/LayoutTests/platform/gtk/Skipped

    r94300 r94399  
    367367http/tests/local/fileapi
    368368http/tests/security/filesystem-iframe-from-remote.html
     369http/tests/websocket/tests/hybi/send-file-blob.html
     370http/tests/websocket/tests/hybi/send-file-blob-fail.html
    369371
    370372# Requires WebP support.
  • trunk/LayoutTests/platform/mac/Skipped

    r94280 r94399  
    278278http/tests/filesystem
    279279http/tests/security/filesystem-iframe-from-remote.html
     280http/tests/websocket/tests/hybi/send-file-blob.html
     281http/tests/websocket/tests/hybi/send-file-blob-fail.html
    280282
    281283# https://bugs.webkit.org/show_bug.cgi?id=46223
  • trunk/LayoutTests/platform/qt/Skipped

    r94283 r94399  
    100100http/tests/filesystem
    101101http/tests/security/filesystem-iframe-from-remote.html
     102http/tests/websocket/tests/hybi/send-file-blob.html
     103http/tests/websocket/tests/hybi/send-file-blob-fail.html
    102104
    103105# ENABLE(QUOTA) is disabled.
  • trunk/LayoutTests/platform/win/Skipped

    r94121 r94399  
    12031203http/tests/filesystem
    12041204http/tests/security/filesystem-iframe-from-remote.html
     1205http/tests/websocket/tests/hybi/send-file-blob.html
     1206http/tests/websocket/tests/hybi/send-file-blob-fail.html
    12051207
    12061208# LayoutTestController::nodesFromRect is not supported.
  • trunk/Source/WebCore/ChangeLog

    r94397 r94399  
     12011-09-02  Yuta Kitamura  <yutak@chromium.org>
     2
     3        WebSocket: Send Blob as WebSocket binary message
     4        https://bugs.webkit.org/show_bug.cgi?id=67465
     5
     6        Reviewed by Kent Tamura.
     7
     8        Tests: http/tests/websocket/tests/hixie76/send-empty.html
     9               http/tests/websocket/tests/hixie76/send-object.html
     10               http/tests/websocket/tests/hybi/send-blob.html
     11               http/tests/websocket/tests/hybi/send-empty.html
     12               http/tests/websocket/tests/hybi/send-file-blob-fail.html
     13               http/tests/websocket/tests/hybi/send-file-blob.html
     14               http/tests/websocket/tests/hybi/workers/send-blob.html
     15               http/tests/websocket/tests/hybi/bufferedAmount-after-close.html (updated)
     16
     17        * bindings/js/JSWebSocketCustom.cpp:
     18        (WebCore::JSWebSocket::send):
     19        * bindings/v8/custom/V8WebSocketCustom.cpp:
     20        (WebCore::V8WebSocket::sendCallback):
     21        * websockets/ThreadableWebSocketChannel.h:
     22        * websockets/WebSocket.cpp:
     23        (WebCore::WebSocket::send):
     24        * websockets/WebSocket.h:
     25        * websockets/WebSocket.idl:
     26        Fixing code generator did not sound easy, because there are some classes depending on
     27        broken behavior of current code generator (one such example is CanvasRenderingContext2D).
     28        As a temporary workaround, new custom handlers for send() are added.
     29        * websockets/WebSocketChannel.cpp:
     30        (WebCore::WebSocketChannel::send):
     31        * websockets/WebSocketChannel.h:
     32        * websockets/WorkerThreadableWebSocketChannel.cpp:
     33        (WebCore::WorkerThreadableWebSocketChannel::send):
     34        (WebCore::WorkerThreadableWebSocketChannel::Peer::send):
     35        (WebCore::WorkerThreadableWebSocketChannel::mainThreadSendBlob):
     36        A Blob can be deserialized from url, type and size.
     37        (WebCore::WorkerThreadableWebSocketChannel::Bridge::send):
     38        KURL, String and long long (corresponding to url, type and size, respectively) can be passed
     39        safely across threads.
     40        * websockets/WorkerThreadableWebSocketChannel.h:
     41
    1422011-09-02  Philippe Normand  <pnormand@igalia.com>
    243
  • trunk/Source/WebCore/bindings/js/JSWebSocketCustom.cpp

    r94387 r94399  
    3737
    3838#include "ExceptionCode.h"
     39#include "JSBlob.h"
     40#include "JSEventListener.h"
    3941#include "KURL.h"
    40 #include "JSEventListener.h"
    4142#include "WebSocket.h"
    4243#include "WebSocketChannel.h"
     
    8990}
    9091
     92JSValue JSWebSocket::send(ExecState* exec)
     93{
     94    if (!exec->argumentCount())
     95        return throwError(exec, createSyntaxError(exec, "Not enough arguments"));
     96
     97    JSValue message = exec->argument(0);
     98    ExceptionCode ec = 0;
     99    bool result;
     100    if (message.inherits(&JSBlob::s_info))
     101        result = impl()->send(toBlob(message), ec);
     102    else {
     103        String stringMessage = ustringToString(message.toString(exec));
     104        if (exec->hadException())
     105            return jsUndefined();
     106        result = impl()->send(stringMessage, ec);
     107    }
     108    if (ec) {
     109        setDOMException(exec, ec);
     110        return jsUndefined();
     111    }
     112
     113    return jsBoolean(result);
     114}
     115
    91116JSValue JSWebSocket::close(ExecState* exec)
    92117{
  • trunk/Source/WebCore/bindings/v8/custom/V8WebSocketCustom.cpp

    r94387 r94399  
    3939#include "Settings.h"
    4040#include "V8Binding.h"
     41#include "V8Blob.h"
    4142#include "V8Proxy.h"
    4243#include "V8Utilities.h"
     
    112113}
    113114
     115v8::Handle<v8::Value> V8WebSocket::sendCallback(const v8::Arguments& args)
     116{
     117    INC_STATS("DOM.WebSocket.send()");
     118
     119    if (!args.Length())
     120        return throwError("Not enough arguments", V8Proxy::SyntaxError);
     121
     122    WebSocket* webSocket = V8WebSocket::toNative(args.Holder());
     123    v8::Handle<v8::Value> message = args[0];
     124    ExceptionCode ec = 0;
     125    bool result;
     126    if (V8Blob::HasInstance(message)) {
     127        Blob* blob = V8Blob::toNative(v8::Handle<v8::Object>::Cast(message));
     128        ASSERT(blob);
     129        result = webSocket->send(blob, ec);
     130    } else {
     131        v8::TryCatch tryCatch;
     132        v8::Handle<v8::String> stringMessage = message->ToString();
     133        if (tryCatch.HasCaught())
     134            return throwError(tryCatch.Exception());
     135        result = webSocket->send(toWebCoreString(message), ec);
     136    }
     137    if (ec)
     138        return throwError(ec);
     139
     140    return v8Boolean(result);
     141}
     142
    114143v8::Handle<v8::Value> V8WebSocket::closeCallback(const v8::Arguments& args)
    115144{
  • trunk/Source/WebCore/websockets/ThreadableWebSocketChannel.h

    r94387 r94399  
    4040namespace WebCore {
    4141
     42class Blob;
    4243class KURL;
    4344class ScriptExecutionContext;
     
    5455    virtual String subprotocol() = 0; // Will be available after didConnect() callback is invoked.
    5556    virtual bool send(const String& message) = 0;
     57    virtual bool send(const Blob&) = 0;
    5658    virtual unsigned long bufferedAmount() const = 0;
    5759    virtual void close(int code, const String& reason) = 0;
  • trunk/Source/WebCore/websockets/WebSocket.cpp

    r94387 r94399  
    266266}
    267267
     268bool WebSocket::send(Blob* binaryData, ExceptionCode& ec)
     269{
     270    LOG(Network, "WebSocket %p send blob %s", this, binaryData->url().string().utf8().data());
     271    ASSERT(binaryData);
     272    if (m_useHixie76Protocol)
     273        return send("[object Blob]", ec);
     274    if (m_state == CONNECTING) {
     275        ec = INVALID_STATE_ERR;
     276        return false;
     277    }
     278    if (m_state == CLOSING || m_state == CLOSED) {
     279        m_bufferedAmountAfterClose += binaryData->size() + getFramingOverhead(binaryData->size());
     280        return false;
     281    }
     282    ASSERT(m_channel);
     283    return m_channel->send(*binaryData);
     284}
     285
    268286void WebSocket::close(int code, const String& reason, ExceptionCode& ec)
    269287{
  • trunk/Source/WebCore/websockets/WebSocket.h

    r94387 r94399  
    4747namespace WebCore {
    4848
     49class Blob;
    4950class ThreadableWebSocketChannel;
    5051
     
    6869
    6970    bool send(const String& message, ExceptionCode&);
     71    bool send(Blob*, ExceptionCode&);
    7072
    7173    void close(int code, const String& reason, ExceptionCode&);
  • trunk/Source/WebCore/websockets/WebSocket.idl

    r94387 r94399  
    6464            setter raises(DOMException);
    6565
    66         [RequiresAllArguments] boolean send(in DOMString data) raises(DOMException);
     66        // FIXME: Use overloading provided by our IDL code generator.
     67        // According to Web IDL specification, overloaded function with DOMString argument
     68        // should accept anything that can be converted to a string (including numbers,
     69        // booleans, null, undefined and objects except Blob). Current code generator does
     70        // not handle this rule correctly.
     71        // [RequiresAllArguments] boolean send(in Blob data) raises(DOMException);
     72        // [RequiresAllArguments] boolean send(in DOMString data) raises(DOMException);
     73        [Custom] boolean send(in DOMString data) raises(DOMException);
     74
    6775        // FIXME: Implement and apply [Clamp] attribute instead of [Custom].
    6876        [Custom] void close(in [Optional] unsigned short code, in [Optional] DOMString reason) raises(DOMException);
  • trunk/Source/WebCore/websockets/WebSocketChannel.cpp

    r94387 r94399  
    171171}
    172172
     173bool WebSocketChannel::send(const Blob& binaryData)
     174{
     175    LOG(Network, "WebSocketChannel %p send blob %s", this, binaryData.url().string().utf8().data());
     176    ASSERT(!m_useHixie76Protocol);
     177    enqueueBlobFrame(OpCodeBinary, binaryData);
     178    return true;
     179}
     180
    173181unsigned long WebSocketChannel::bufferedAmount() const
    174182{
  • trunk/Source/WebCore/websockets/WebSocketChannel.h

    r94387 r94399  
    6767    virtual String subprotocol();
    6868    virtual bool send(const String& message);
     69    virtual bool send(const Blob&);
    6970    virtual unsigned long bufferedAmount() const;
    7071    virtual void close(int code, const String& reason); // Start closing handshake.
  • trunk/Source/WebCore/websockets/WorkerThreadableWebSocketChannel.cpp

    r94387 r94399  
    3535#include "WorkerThreadableWebSocketChannel.h"
    3636
     37#include "Blob.h"
    3738#include "CrossThreadTask.h"
    3839#include "PlatformString.h"
     
    8889}
    8990
     91bool WorkerThreadableWebSocketChannel::send(const Blob& binaryData)
     92{
     93    if (!m_bridge)
     94        return false;
     95    return m_bridge->send(binaryData);
     96}
     97
    9098unsigned long WorkerThreadableWebSocketChannel::bufferedAmount() const
    9199{
     
    170178        return;
    171179    bool sent = m_mainWebSocketChannel->send(message);
     180    m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidSend, m_workerClientWrapper, sent), m_taskMode);
     181}
     182
     183void WorkerThreadableWebSocketChannel::Peer::send(const Blob& binaryData)
     184{
     185    ASSERT(isMainThread());
     186    if (!m_mainWebSocketChannel || !m_workerClientWrapper)
     187        return;
     188    bool sent = m_mainWebSocketChannel->send(binaryData);
    172189    m_loaderProxy.postTaskForModeToWorkerContext(createCallbackTask(&workerContextDidSend, m_workerClientWrapper, sent), m_taskMode);
    173190}
     
    359376}
    360377
     378void WorkerThreadableWebSocketChannel::mainThreadSendBlob(ScriptExecutionContext* context, Peer* peer, const KURL& url, const String& type, long long size)
     379{
     380    ASSERT(isMainThread());
     381    ASSERT_UNUSED(context, context->isDocument());
     382    ASSERT(peer);
     383
     384    RefPtr<Blob> blob = Blob::create(url, type, size);
     385    peer->send(*blob);
     386}
     387
    361388bool WorkerThreadableWebSocketChannel::Bridge::send(const String& message)
    362389{
     
    366393    setMethodNotCompleted();
    367394    m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadSend, AllowCrossThreadAccess(m_peer), message));
     395    RefPtr<Bridge> protect(this);
     396    waitForMethodCompletion();
     397    ThreadableWebSocketChannelClientWrapper* clientWrapper = m_workerClientWrapper.get();
     398    return clientWrapper && clientWrapper->sent();
     399}
     400
     401bool WorkerThreadableWebSocketChannel::Bridge::send(const Blob& binaryData)
     402{
     403    if (!m_workerClientWrapper)
     404        return false;
     405    ASSERT(m_peer);
     406    setMethodNotCompleted();
     407    m_loaderProxy.postTaskToLoader(createCallbackTask(&WorkerThreadableWebSocketChannel::mainThreadSendBlob, AllowCrossThreadAccess(m_peer), binaryData.url(), binaryData.type(), binaryData.size()));
    368408    RefPtr<Bridge> protect(this);
    369409    waitForMethodCompletion();
  • trunk/Source/WebCore/websockets/WorkerThreadableWebSocketChannel.h

    r94387 r94399  
    6565    virtual String subprotocol();
    6666    virtual bool send(const String& message);
     67    virtual bool send(const Blob&);
    6768    virtual unsigned long bufferedAmount() const;
    6869    virtual void close(int code, const String& reason);
     
    9495        void connect(const KURL&, const String& protocol);
    9596        void send(const String& message);
     97        void send(const Blob&);
    9698        void bufferedAmount();
    9799        void close(int code, const String& reason);
     
    126128        void connect(const KURL&, const String& protocol);
    127129        bool send(const String& message);
     130        bool send(const Blob&);
    128131        unsigned long bufferedAmount();
    129132        void close(int code, const String& reason);
     
    161164    static void mainThreadConnect(ScriptExecutionContext*, Peer*, const KURL&, const String& protocol);
    162165    static void mainThreadSend(ScriptExecutionContext*, Peer*, const String& message);
     166    static void mainThreadSendBlob(ScriptExecutionContext*, Peer*, const KURL&, const String& type, long long size);
    163167    static void mainThreadBufferedAmount(ScriptExecutionContext*, Peer*);
    164168    static void mainThreadClose(ScriptExecutionContext*, Peer*, int code, const String& reason);
Note: See TracChangeset for help on using the changeset viewer.