Title: [200558] trunk/Source
Revision
200558
Author
[email protected]
Date
2016-05-08 11:46:53 -0700 (Sun, 08 May 2016)

Log Message

Change EventSource constructor to take an IDL dictionary instead of a WebCore::Dictionary
https://bugs.webkit.org/show_bug.cgi?id=157459

Reviewed by Chris Dumez.

Source/WebCore:

Patch also includes some updating of EventSource class to modern idioms.

* page/EventSource.cpp:
(WebCore::EventSource::EventSource): Initialize based on Init.
(WebCore::EventSource::create): Take/pass Init instead of Dictionary.

* bindings/js/SerializedScriptValue.cpp:
(WebCore::CloneSerializer::serialize): Take a StringView instead of a string
so callers don't have to allocate a String just to use this.
(WebCore::SerializedScriptValue::create): Ditto.
* bindings/js/SerializedScriptValue.h: Ditto.

* page/EventSource.cpp: Changed defaultReconnectDelay to be a uint64_t
instead of an unsigned long long.
(WebCore::EventSource::EventSource): Changed constructor to take a struct
instead of a Dictionary for eventSourceInit. Also moved initialization of
data members to the header and used ASCIILiteral.
(WebCore::EventSource::create): Changed type to Init and streamlined code
a little bit using auto.
(WebCore::EventSource::connect): Used a reference instead of a pointer.
Also added a FIXME since I noticed that m_requestInFlight is probably not
needed, since it's basically the same thing as "is m_loader null".
(WebCore::EventSource::url): Moved to the header and made it inline.
(WebCore::EventSource::networkRequestEnded): Removed unneeded check that
is already done by all callers and turned it into an assertion.
(WebCore::EventSource::withCredentials): Ditto.
(WebCore::EventSource::readyState): Ditto.
(WebCore::EventSource::responseIsValid): Added. Helper function to make
the logic in didReceiveResponse easier to read. Fixed logic to compare
MIME type ignoring ASCII case, since that's how MIME types work.
(WebCore::EventSource::didReceiveResponse): Use the helper above, and also
move the m_eventStreamOrigin set up code into the valid response case,
since there is no point doing it if the response is not valid. Also use
the early return idiom.
(WebCore::EventSource::didReceiveData): Removed the unneeded explicit
conversion to StringView here. Also removed a FIXME that I fixed.
(WebCore::EventSource::didFinishLoading): Added code to flush the decoder
as mentioned in didReceiveData. Added FIXME about peculiar clearing code
that exists only here. Removed check for empty receive buffer and data
that is not needed since parseEventStream does sufficient checking.
(WebCore::EventSource::didFail): Added FIXME because of things that
didFinishLoading does that seem equally valuable here.
(WebCore::EventSource::parseEventStream): Tweaked types and names of local
variables, and changed to use Optional instead of magic number -1. Also
added a FIXME about how the buffer type is probably not right since we
keep moving the characters in the buffer as we consume the start of it.
(WebCore::EventSource::parseEventStreamLine): Refactor and reorganize so
this doesn't do so much string allocation and is easier to read
(WebCore::EventSource::canSuspendForDocumentSuspension): Tweaked comment.
(WebCore::EventSource::dispatchMessageEvent): Renamed this from
createMessageEvent, and moved more code in here. We now don't have to
allocate a temporary string just to pass it to SerializedScriptValue.

* page/EventSource.h: Updated for changes above. Use pragma once.
Define and use EventSource::Init struct. Other small cleanup.

* page/EventSource.idl: Define EventSourceInit dictionary and use it.
Other small cleanup.

* page/EventSource.idl: U

Source/WTF:

* wtf/text/WTFString.h: Export a symbol now used in WebCore.

Modified Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (200557 => 200558)


--- trunk/Source/WTF/ChangeLog	2016-05-08 18:35:23 UTC (rev 200557)
+++ trunk/Source/WTF/ChangeLog	2016-05-08 18:46:53 UTC (rev 200558)
@@ -1,3 +1,12 @@
+2016-05-08  Darin Adler  <[email protected]>
+
+        Change EventSource constructor to take an IDL dictionary instead of a WebCore::Dictionary
+        https://bugs.webkit.org/show_bug.cgi?id=157459
+
+        Reviewed by Chris Dumez.
+
+        * wtf/text/WTFString.h: Export a symbol now used in WebCore.
+
 2016-05-02  Sam Weinig  <[email protected]>
 
         On platforms that support it, use a SecTrustRef as the basis of CertificateInfo instead of a chain of SecCertificateRefs.

Modified: trunk/Source/WTF/wtf/text/WTFString.h (200557 => 200558)


--- trunk/Source/WTF/wtf/text/WTFString.h	2016-05-08 18:35:23 UTC (rev 200557)
+++ trunk/Source/WTF/wtf/text/WTFString.h	2016-05-08 18:46:53 UTC (rev 200558)
@@ -34,6 +34,8 @@
 
 namespace WTF {
 
+class ASCIILiteral;
+
 // Declarations of string operations
 
 WTF_EXPORT_STRING_API int charactersToIntStrict(const LChar*, size_t, bool* ok = 0, int base = 10);
@@ -54,7 +56,7 @@
 int64_t charactersToInt64(const LChar*, size_t, bool* ok = 0); // ignores trailing garbage
 int64_t charactersToInt64(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage
 uint64_t charactersToUInt64(const LChar*, size_t, bool* ok = 0); // ignores trailing garbage
-uint64_t charactersToUInt64(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage
+WTF_EXPORT_STRING_API uint64_t charactersToUInt64(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage
 intptr_t charactersToIntPtr(const LChar*, size_t, bool* ok = 0); // ignores trailing garbage
 intptr_t charactersToIntPtr(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage
 
@@ -68,16 +70,10 @@
 WTF_EXPORT_STRING_API float charactersToFloat(const LChar*, size_t, size_t& parsedLength);
 WTF_EXPORT_STRING_API float charactersToFloat(const UChar*, size_t, size_t& parsedLength);
 
-class ASCIILiteral;
+template<bool isSpecialCharacter(UChar), typename CharacterType> bool isAllSpecialCharacters(const CharacterType*, size_t);
 
-enum TrailingZerosTruncatingPolicy {
-    KeepTrailingZeros,
-    TruncateTrailingZeros
-};
+enum TrailingZerosTruncatingPolicy { KeepTrailingZeros, TruncateTrailingZeros };
 
-template<bool isSpecialCharacter(UChar), typename CharacterType>
-bool isAllSpecialCharacters(const CharacterType*, size_t);
-
 class String {
 public:
     // Construct a null string, distinguishable from an empty string.

Modified: trunk/Source/WebCore/ChangeLog (200557 => 200558)


--- trunk/Source/WebCore/ChangeLog	2016-05-08 18:35:23 UTC (rev 200557)
+++ trunk/Source/WebCore/ChangeLog	2016-05-08 18:46:53 UTC (rev 200558)
@@ -1,3 +1,71 @@
+2016-05-08  Darin Adler  <[email protected]>
+
+        Change EventSource constructor to take an IDL dictionary instead of a WebCore::Dictionary
+        https://bugs.webkit.org/show_bug.cgi?id=157459
+
+        Reviewed by Chris Dumez.
+
+        Patch also includes some updating of EventSource class to modern idioms.
+
+        * page/EventSource.cpp:
+        (WebCore::EventSource::EventSource): Initialize based on Init.
+        (WebCore::EventSource::create): Take/pass Init instead of Dictionary.
+
+        * bindings/js/SerializedScriptValue.cpp:
+        (WebCore::CloneSerializer::serialize): Take a StringView instead of a string
+        so callers don't have to allocate a String just to use this.
+        (WebCore::SerializedScriptValue::create): Ditto.
+        * bindings/js/SerializedScriptValue.h: Ditto.
+
+        * page/EventSource.cpp: Changed defaultReconnectDelay to be a uint64_t
+        instead of an unsigned long long.
+        (WebCore::EventSource::EventSource): Changed constructor to take a struct
+        instead of a Dictionary for eventSourceInit. Also moved initialization of
+        data members to the header and used ASCIILiteral.
+        (WebCore::EventSource::create): Changed type to Init and streamlined code
+        a little bit using auto.
+        (WebCore::EventSource::connect): Used a reference instead of a pointer.
+        Also added a FIXME since I noticed that m_requestInFlight is probably not
+        needed, since it's basically the same thing as "is m_loader null".
+        (WebCore::EventSource::url): Moved to the header and made it inline.
+        (WebCore::EventSource::networkRequestEnded): Removed unneeded check that
+        is already done by all callers and turned it into an assertion.
+        (WebCore::EventSource::withCredentials): Ditto.
+        (WebCore::EventSource::readyState): Ditto.
+        (WebCore::EventSource::responseIsValid): Added. Helper function to make
+        the logic in didReceiveResponse easier to read. Fixed logic to compare
+        MIME type ignoring ASCII case, since that's how MIME types work.
+        (WebCore::EventSource::didReceiveResponse): Use the helper above, and also
+        move the m_eventStreamOrigin set up code into the valid response case,
+        since there is no point doing it if the response is not valid. Also use
+        the early return idiom.
+        (WebCore::EventSource::didReceiveData): Removed the unneeded explicit
+        conversion to StringView here. Also removed a FIXME that I fixed.
+        (WebCore::EventSource::didFinishLoading): Added code to flush the decoder
+        as mentioned in didReceiveData. Added FIXME about peculiar clearing code
+        that exists only here. Removed check for empty receive buffer and data
+        that is not needed since parseEventStream does sufficient checking.
+        (WebCore::EventSource::didFail): Added FIXME because of things that
+        didFinishLoading does that seem equally valuable here.
+        (WebCore::EventSource::parseEventStream): Tweaked types and names of local
+        variables, and changed to use Optional instead of magic number -1. Also
+        added a FIXME about how the buffer type is probably not right since we
+        keep moving the characters in the buffer as we consume the start of it.
+        (WebCore::EventSource::parseEventStreamLine): Refactor and reorganize so
+        this doesn't do so much string allocation and is easier to read
+        (WebCore::EventSource::canSuspendForDocumentSuspension): Tweaked comment.
+        (WebCore::EventSource::dispatchMessageEvent): Renamed this from
+        createMessageEvent, and moved more code in here. We now don't have to
+        allocate a temporary string just to pass it to SerializedScriptValue.
+
+        * page/EventSource.h: Updated for changes above. Use pragma once.
+        Define and use EventSource::Init struct. Other small cleanup.
+
+        * page/EventSource.idl: Define EventSourceInit dictionary and use it.
+        Other small cleanup.
+
+        * page/EventSource.idl: U
+
 2016-05-07  Darin Adler  <[email protected]>
 
         Change HTMLSlotElement::assignedNodes to take a IDL dictionary instead of a WebCore::Dictionary

Modified: trunk/Source/WebCore/bindings/js/SerializedScriptValue.cpp (200557 => 200558)


--- trunk/Source/WebCore/bindings/js/SerializedScriptValue.cpp	2016-05-08 18:35:23 UTC (rev 200557)
+++ trunk/Source/WebCore/bindings/js/SerializedScriptValue.cpp	2016-05-08 18:46:53 UTC (rev 200558)
@@ -478,20 +478,20 @@
         return serializer.serialize(value);
     }
 
-    static bool serialize(const String& s, Vector<uint8_t>& out)
+    static bool serialize(StringView string, Vector<uint8_t>& out)
     {
         writeLittleEndian(out, CurrentVersion);
-        if (s.isEmpty()) {
+        if (string.isEmpty()) {
             writeLittleEndian<uint8_t>(out, EmptyStringTag);
             return true;
         }
         writeLittleEndian<uint8_t>(out, StringTag);
-        if (s.is8Bit()) {
-            writeLittleEndian(out, s.length() | StringDataIs8BitFlag);
-            return writeLittleEndian(out, s.characters8(), s.length());
+        if (string.is8Bit()) {
+            writeLittleEndian(out, string.length() | StringDataIs8BitFlag);
+            return writeLittleEndian(out, string.characters8(), string.length());
         }
-        writeLittleEndian(out, s.length());
-        return writeLittleEndian(out, s.characters16(), s.length());
+        writeLittleEndian(out, string.length());
+        return writeLittleEndian(out, string.characters16(), string.length());
     }
 
     static void serializeUndefined(Vector<uint8_t>& out)
@@ -2687,7 +2687,7 @@
     return adoptRef(*new SerializedScriptValue(WTFMove(buffer), blobURLs, WTFMove(arrayBufferContentsArray)));
 }
 
-RefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& string)
+RefPtr<SerializedScriptValue> SerializedScriptValue::create(StringView string)
 {
     Vector<uint8_t> buffer;
     if (!CloneSerializer::serialize(string, buffer))

Modified: trunk/Source/WebCore/bindings/js/SerializedScriptValue.h (200557 => 200558)


--- trunk/Source/WebCore/bindings/js/SerializedScriptValue.h	2016-05-08 18:35:23 UTC (rev 200557)
+++ trunk/Source/WebCore/bindings/js/SerializedScriptValue.h	2016-05-08 18:46:53 UTC (rev 200558)
@@ -62,7 +62,7 @@
 public:
     WEBCORE_EXPORT static RefPtr<SerializedScriptValue> create(JSC::ExecState*, JSC::JSValue, MessagePortArray*, ArrayBufferArray*, SerializationErrorMode = Throwing);
 
-    WEBCORE_EXPORT static RefPtr<SerializedScriptValue> create(const String&);
+    WEBCORE_EXPORT static RefPtr<SerializedScriptValue> create(StringView);
     static Ref<SerializedScriptValue> adopt(Vector<uint8_t>&& buffer)
     {
         return adoptRef(*new SerializedScriptValue(WTFMove(buffer)));

Modified: trunk/Source/WebCore/page/EventSource.cpp (200557 => 200558)


--- trunk/Source/WebCore/page/EventSource.cpp	2016-05-08 18:35:23 UTC (rev 200557)
+++ trunk/Source/WebCore/page/EventSource.cpp	2016-05-08 18:46:53 UTC (rev 200558)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2009, 2012 Ericsson AB. All rights reserved.
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2016 Apple Inc. All rights reserved.
  * Copyright (C) 2011, Code Aurora Forum. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -34,44 +34,29 @@
 #include "EventSource.h"
 
 #include "ContentSecurityPolicy.h"
-#include "DOMWindow.h"
-#include "Dictionary.h"
-#include "Document.h"
-#include "Event.h"
 #include "ExceptionCode.h"
-#include "Frame.h"
-#include "HTTPHeaderNames.h"
-#include "MemoryCache.h"
 #include "MessageEvent.h"
 #include "ResourceError.h"
-#include "ResourceRequest.h"
 #include "ResourceResponse.h"
-#include "ScriptController.h"
 #include "ScriptExecutionContext.h"
 #include "SecurityOrigin.h"
-#include "SerializedScriptValue.h"
 #include "TextResourceDecoder.h"
 #include "ThreadableLoader.h"
 
 namespace WebCore {
 
-const unsigned long long EventSource::defaultReconnectDelay = 3000;
+const uint64_t EventSource::defaultReconnectDelay = 3000;
 
-inline EventSource::EventSource(ScriptExecutionContext& context, const URL& url, const Dictionary& eventSourceInit)
+inline EventSource::EventSource(ScriptExecutionContext& context, const URL& url, const Init& eventSourceInit)
     : ActiveDOMObject(&context)
     , m_url(url)
-    , m_withCredentials(false)
-    , m_state(CONNECTING)
-    , m_decoder(TextResourceDecoder::create("text/plain", "UTF-8"))
+    , m_withCredentials(eventSourceInit.withCredentials)
+    , m_decoder(TextResourceDecoder::create(ASCIILiteral("text/plain"), "UTF-8"))
     , m_connectTimer(*this, &EventSource::connect)
-    , m_discardTrailingNewline(false)
-    , m_requestInFlight(false)
-    , m_reconnectDelay(defaultReconnectDelay)
 {
-    eventSourceInit.get("withCredentials", m_withCredentials);
 }
 
-RefPtr<EventSource> EventSource::create(ScriptExecutionContext& context, const String& url, const Dictionary& eventSourceInit, ExceptionCode& ec)
+RefPtr<EventSource> EventSource::create(ScriptExecutionContext& context, const String& url, const Init& eventSourceInit, ExceptionCode& ec)
 {
     if (url.isEmpty()) {
         ec = SYNTAX_ERR;
@@ -91,13 +76,11 @@
         return nullptr;
     }
 
-    RefPtr<EventSource> source = adoptRef(new EventSource(context, fullURL, eventSourceInit));
-
-    source->setPendingActivity(source.get());
+    auto source = adoptRef(*new EventSource(context, fullURL, eventSourceInit));
+    source->setPendingActivity(source.ptr());
     source->scheduleInitialConnect();
     source->suspendIfNeeded();
-
-    return source.release();
+    return WTFMove(source);
 }
 
 EventSource::~EventSource()
@@ -111,36 +94,36 @@
     ASSERT(m_state == CONNECTING);
     ASSERT(!m_requestInFlight);
 
-    ResourceRequest request(m_url);
+    ResourceRequest request { m_url };
     request.setHTTPMethod("GET");
     request.setHTTPHeaderField(HTTPHeaderName::Accept, "text/event-stream");
     request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "no-cache");
     if (!m_lastEventId.isEmpty())
         request.setHTTPHeaderField(HTTPHeaderName::LastEventID, m_lastEventId);
 
-    SecurityOrigin* origin = scriptExecutionContext()->securityOrigin();
+    SecurityOrigin& origin = *scriptExecutionContext()->securityOrigin();
 
     ThreadableLoaderOptions options;
     options.setSendLoadCallbacks(SendCallbacks);
     options.setSniffContent(DoNotSniffContent);
-    options.setAllowCredentials((origin->canRequest(m_url) || m_withCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials);
+    options.setAllowCredentials((origin.canRequest(m_url) || m_withCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials);
     options.setCredentialRequest(m_withCredentials ? ClientRequestedCredentials : ClientDidNotRequestCredentials);
     options.preflightPolicy = PreventPreflight;
     options.crossOriginRequestPolicy = UseAccessControl;
     options.setDataBufferingPolicy(DoNotBufferData);
-    options.securityOrigin = origin;
+    options.securityOrigin = &origin;
     options.contentSecurityPolicyEnforcement = scriptExecutionContext()->shouldBypassMainWorldContentSecurityPolicy() ? ContentSecurityPolicyEnforcement::DoNotEnforce : ContentSecurityPolicyEnforcement::EnforceConnectSrcDirective;
 
     m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options);
 
+    // FIXME: Can we just use m_loader for this, null it out when it's no longer in flight, and eliminate the m_requestInFlight member?
     if (m_loader)
         m_requestInFlight = true;
 }
 
 void EventSource::networkRequestEnded()
 {
-    if (!m_requestInFlight)
-        return;
+    ASSERT(m_requestInFlight);
 
     m_requestInFlight = false;
 
@@ -165,21 +148,6 @@
     dispatchEvent(Event::create(eventNames().errorEvent, false, false));
 }
 
-String EventSource::url() const
-{
-    return m_url.string();
-}
-
-bool EventSource::withCredentials() const
-{
-    return m_withCredentials;
-}
-
-EventSource::State EventSource::readyState() const
-{
-    return m_state;
-}
-
 void EventSource::close()
 {
     if (m_state == CLOSED) {
@@ -199,40 +167,47 @@
     }
 }
 
+bool EventSource::responseIsValid(const ResourceResponse& response) const
+{
+    // Logs to the console as a side effect.
+
+    // To keep the signal-to-noise ratio low, we don't log anything if the status code is not 200.
+    if (response.httpStatusCode() != 200)
+        return false;
+
+    if (!equalLettersIgnoringASCIICase(response.mimeType(), "text/event-stream")) {
+        auto message = makeString("EventSource's response has a MIME type (\"", response.mimeType(), "\") that is not \"text/event-stream\". Aborting the connection.");
+        // FIXME: Console message would be better with a source code location; where would we get that?
+        scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, WTFMove(message));
+        return false;
+    }
+
+    // If we have a charset, the only allowed value is UTF-8 (case-insensitive).
+    auto& charset = response.textEncodingName();
+    if (!charset.isEmpty() && !equalLettersIgnoringASCIICase(charset, "utf-8")) {
+        auto message = makeString("EventSource's response has a charset (\"", charset, "\") that is not UTF-8. Aborting the connection.");
+        // FIXME: Console message would be better with a source code location; where would we get that?
+        scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, WTFMove(message));
+        return false;
+    }
+
+    return true;
+}
+
 void EventSource::didReceiveResponse(unsigned long, const ResourceResponse& response)
 {
     ASSERT(m_state == CONNECTING);
     ASSERT(m_requestInFlight);
 
-    m_eventStreamOrigin = SecurityOrigin::create(response.url())->toString();
-    int statusCode = response.httpStatusCode();
-    bool mimeTypeIsValid = response.mimeType() == "text/event-stream";
-    bool responseIsValid = statusCode == 200 && mimeTypeIsValid;
-    if (responseIsValid) {
-        const String& charset = response.textEncodingName();
-        // If we have a charset, the only allowed value is UTF-8 (case-insensitive).
-        responseIsValid = charset.isEmpty() || equalLettersIgnoringASCIICase(charset, "utf-8");
-        if (!responseIsValid) {
-            String message = makeString("EventSource's response has a charset (\"", charset, "\") that is not UTF-8. Aborting the connection.");
-            // FIXME: We are missing the source line.
-            scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, message);
-        }
-    } else {
-        // To keep the signal-to-noise ratio low, we only log 200-response with an invalid MIME type.
-        if (statusCode == 200 && !mimeTypeIsValid) {
-            String message = makeString("EventSource's response has a MIME type (\"", response.mimeType(), "\") that is not \"text/event-stream\". Aborting the connection.");
-            // FIXME: We are missing the source line.
-            scriptExecutionContext()->addConsoleMessage(MessageSource::JS, MessageLevel::Error, message);
-        }
-    }
-
-    if (responseIsValid) {
-        m_state = OPEN;
-        dispatchEvent(Event::create(eventNames().openEvent, false, false));
-    } else {
+    if (!responseIsValid(response)) {
         m_loader->cancel();
         dispatchEvent(Event::create(eventNames().errorEvent, false, false));
+        return;
     }
+
+    m_eventStreamOrigin = SecurityOrigin::create(response.url())->toString();
+    m_state = OPEN;
+    dispatchEvent(Event::create(eventNames().openEvent, false, false));
 }
 
 void EventSource::didReceiveData(const char* data, int length)
@@ -240,8 +215,7 @@
     ASSERT(m_state == OPEN);
     ASSERT(m_requestInFlight);
 
-    // FIXME: Need to call flush at some point.
-    append(m_receiveBuf, StringView(m_decoder->decode(data, length)));
+    append(m_receiveBuffer, m_decoder->decode(data, length));
     parseEventStream();
 }
 
@@ -250,15 +224,17 @@
     ASSERT(m_state == OPEN);
     ASSERT(m_requestInFlight);
 
-    if (m_receiveBuf.size() > 0 || m_data.size() > 0) {
-        parseEventStream();
+    append(m_receiveBuffer, m_decoder->flush());
+    parseEventStream();
 
-        // Discard everything that has not been dispatched by now.
-        m_receiveBuf.clear();
-        m_data.clear();
-        m_eventName = "";
-        m_currentlyParsedEventId = String();
-    }
+    // Discard everything that has not been dispatched by now.
+    // FIXME: Why does this need to be done?
+    // If this is important, why isn't it important to clear other data members: m_decoder, m_lastEventId, m_loader?
+    m_receiveBuffer.clear();
+    m_data.clear();
+    m_eventName = { };
+    m_currentlyParsedEventId = { };
+
     networkRequestEnded();
 }
 
@@ -269,6 +245,9 @@
 
     if (error.isCancellation())
         m_state = CLOSED;
+
+    // FIXME: Why don't we need to clear data members here as in didFinishLoading?
+
     networkRequestEnded();
 }
 
@@ -302,37 +281,37 @@
 
 void EventSource::parseEventStream()
 {
-    unsigned int bufPos = 0;
-    unsigned int bufSize = m_receiveBuf.size();
-    while (bufPos < bufSize) {
+    unsigned position = 0;
+    unsigned size = m_receiveBuffer.size();
+    while (position < size) {
         if (m_discardTrailingNewline) {
-            if (m_receiveBuf[bufPos] == '\n')
-                bufPos++;
+            if (m_receiveBuffer[position] == '\n')
+                position++;
             m_discardTrailingNewline = false;
         }
 
-        int lineLength = -1;
-        int fieldLength = -1;
-        for (unsigned int i = bufPos; lineLength < 0 && i < bufSize; i++) {
-            switch (m_receiveBuf[i]) {
+        Optional<unsigned> lineLength;
+        Optional<unsigned> fieldLength;
+        for (unsigned i = position; !lineLength && i < size; i++) {
+            switch (m_receiveBuffer[i]) {
             case ':':
-                if (fieldLength < 0)
-                    fieldLength = i - bufPos;
+                if (!fieldLength)
+                    fieldLength = i - position;
                 break;
             case '\r':
                 m_discardTrailingNewline = true;
                 FALLTHROUGH;
             case '\n':
-                lineLength = i - bufPos;
+                lineLength = i - position;
                 break;
             }
         }
 
-        if (lineLength < 0)
+        if (!lineLength)
             break;
 
-        parseEventStreamLine(bufPos, fieldLength, lineLength);
-        bufPos += lineLength + 1;
+        parseEventStreamLine(position, fieldLength, lineLength.value());
+        position += lineLength.value() + 1;
 
         // EventSource.close() might've been called by one of the message event handlers.
         // Per spec, no further messages should be fired after that.
@@ -340,57 +319,55 @@
             break;
     }
 
-    if (bufPos == bufSize)
-        m_receiveBuf.clear();
-    else if (bufPos)
-        m_receiveBuf.remove(0, bufPos);
+    // FIXME: The following operation makes it clear that m_receiveBuffer should be some other type,
+    // perhaps a Deque or a circular buffer of some sort.
+    if (position == size)
+        m_receiveBuffer.clear();
+    else if (position)
+        m_receiveBuffer.remove(0, position);
 }
 
-void EventSource::parseEventStreamLine(unsigned bufPos, int fieldLength, int lineLength)
+void EventSource::parseEventStreamLine(unsigned position, Optional<unsigned> fieldLength, unsigned lineLength)
 {
     if (!lineLength) {
-        if (!m_data.isEmpty()) {
-            m_data.removeLast();
-            if (!m_currentlyParsedEventId.isNull()) {
-                m_lastEventId.swap(m_currentlyParsedEventId);
-                m_currentlyParsedEventId = String();
-            }
-            dispatchEvent(createMessageEvent());
-        }
-        if (!m_eventName.isEmpty())
-            m_eventName = "";
-    } else if (fieldLength) {
-        bool noValue = fieldLength < 0;
+        if (!m_data.isEmpty())
+            dispatchMessageEvent();
+        m_eventName = { };
+        return;
+    }
 
-        String field(&m_receiveBuf[bufPos], noValue ? lineLength : fieldLength);
-        int step;
-        if (noValue)
-            step = lineLength;
-        else if (m_receiveBuf[bufPos + fieldLength + 1] != ' ')
-            step = fieldLength + 1;
-        else
-            step = fieldLength + 2;
-        bufPos += step;
-        int valueLength = lineLength - step;
+    if (fieldLength && !fieldLength.value())
+        return;
 
-        if (field == "data") {
-            if (valueLength)
-                m_data.append(&m_receiveBuf[bufPos], valueLength);
-            m_data.append('\n');
-        } else if (field == "event")
-            m_eventName = valueLength ? String(&m_receiveBuf[bufPos], valueLength) : "";
-        else if (field == "id")
-            m_currentlyParsedEventId = valueLength ? String(&m_receiveBuf[bufPos], valueLength) : "";
-        else if (field == "retry") {
-            if (!valueLength)
-                m_reconnectDelay = defaultReconnectDelay;
-            else {
-                String value(&m_receiveBuf[bufPos], valueLength);
-                bool ok;
-                unsigned long long retry = value.toUInt64(&ok);
-                if (ok)
-                    m_reconnectDelay = retry;
-            }
+    StringView field { &m_receiveBuffer[position], fieldLength ? fieldLength.value() : lineLength };
+
+    unsigned step;
+    if (!fieldLength)
+        step = lineLength;
+    else if (m_receiveBuffer[position + fieldLength.value() + 1] != ' ')
+        step = fieldLength.value() + 1;
+    else
+        step = fieldLength.value() + 2;
+    position += step;
+    unsigned valueLength = lineLength - step;
+
+    if (field == "data") {
+        m_data.append(&m_receiveBuffer[position], valueLength);
+        m_data.append('\n');
+    } else if (field == "event")
+        m_eventName = { &m_receiveBuffer[position], valueLength };
+    else if (field == "id")
+        m_currentlyParsedEventId = { &m_receiveBuffer[position], valueLength };
+    else if (field == "retry") {
+        if (!valueLength)
+            m_reconnectDelay = defaultReconnectDelay;
+        else {
+            // FIXME: Do we really want to ignore trailing garbage here? Should we be using the strict version instead?
+            // FIXME: If we can't parse the value, should we leave m_reconnectDelay alone or set it to defaultReconnectDelay?
+            bool ok;
+            auto reconnectDelay = charactersToUInt64(&m_receiveBuffer[position], valueLength, &ok);
+            if (ok)
+                m_reconnectDelay = reconnectDelay;
         }
     }
 }
@@ -407,13 +384,24 @@
 
 bool EventSource::canSuspendForDocumentSuspension() const
 {
-    // FIXME: We should try and do better here.
+    // FIXME: We should return true here when we can because this object is not actually currently active.
     return false;
 }
 
-Ref<MessageEvent> EventSource::createMessageEvent()
+void EventSource::dispatchMessageEvent()
 {
-    return MessageEvent::create(m_eventName.isEmpty() ? eventNames().messageEvent : AtomicString(m_eventName), SerializedScriptValue::create(String::adopt(m_data)), m_eventStreamOrigin, m_lastEventId);
+    if (!m_currentlyParsedEventId.isNull())
+        m_lastEventId = WTFMove(m_currentlyParsedEventId);
+
+    auto& name = m_eventName.isEmpty() ? eventNames().messageEvent : m_eventName;
+
+    // Omit the trailing "\n" character.
+    ASSERT(!m_data.isEmpty());
+    unsigned size = m_data.size() - 1;
+    auto data = "" { m_data.data(), size });
+    m_data = { };
+
+    dispatchEvent(MessageEvent::create(name, WTFMove(data), m_eventStreamOrigin, m_lastEventId));
 }
 
 } // namespace WebCore

Modified: trunk/Source/WebCore/page/EventSource.h (200557 => 200558)


--- trunk/Source/WebCore/page/EventSource.h	2016-05-08 18:35:23 UTC (rev 200557)
+++ trunk/Source/WebCore/page/EventSource.h	2016-05-08 18:46:53 UTC (rev 200558)
@@ -29,34 +29,31 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef EventSource_h
-#define EventSource_h
+#pragma once
 
 #include "ActiveDOMObject.h"
 #include "EventTarget.h"
 #include "URL.h"
 #include "ThreadableLoaderClient.h"
 #include "Timer.h"
-#include <wtf/RefPtr.h>
 #include <wtf/Vector.h>
 
 namespace WebCore {
 
-class Dictionary;
 class MessageEvent;
-class ResourceResponse;
 class TextResourceDecoder;
 class ThreadableLoader;
 
 class EventSource final : public RefCounted<EventSource>, public EventTargetWithInlineData, private ThreadableLoaderClient, public ActiveDOMObject {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    static RefPtr<EventSource> create(ScriptExecutionContext&, const String& url, const Dictionary&, ExceptionCode&);
+    struct Init {
+        bool withCredentials;
+    };
+    static RefPtr<EventSource> create(ScriptExecutionContext&, const String& url, const Init&, ExceptionCode&);
     virtual ~EventSource();
 
-    static const unsigned long long defaultReconnectDelay;
-
-    String url() const;
+    const String& url() const;
     bool withCredentials() const;
 
     typedef short State;
@@ -68,58 +65,74 @@
 
     void close();
 
-    using RefCounted<EventSource>::ref;
-    using RefCounted<EventSource>::deref;
+    using RefCounted::ref;
+    using RefCounted::deref;
 
-    EventTargetInterface eventTargetInterface() const override { return EventSourceEventTargetInterfaceType; }
-    ScriptExecutionContext* scriptExecutionContext() const override { return ActiveDOMObject::scriptExecutionContext(); }
-
 private:
-    EventSource(ScriptExecutionContext&, const URL&, const Dictionary&);
+    EventSource(ScriptExecutionContext&, const URL&, const Init&);
 
-    void refEventTarget() override { ref(); }
-    void derefEventTarget() override { deref(); }
+    EventTargetInterface eventTargetInterface() const final { return EventSourceEventTargetInterfaceType; }
+    ScriptExecutionContext* scriptExecutionContext() const final { return ActiveDOMObject::scriptExecutionContext(); }
 
-    void didReceiveResponse(unsigned long, const ResourceResponse&) override;
-    void didReceiveData(const char*, int) override;
-    void didFinishLoading(unsigned long, double) override;
-    void didFail(const ResourceError&) override;
-    void didFailAccessControlCheck(const ResourceError&) override;
-    void didFailRedirectCheck() override;
+    void refEventTarget() final { ref(); }
+    void derefEventTarget() final { deref(); }
 
-    // ActiveDOMObject API.
-    void stop() override;
-    const char* activeDOMObjectName() const override;
-    bool canSuspendForDocumentSuspension() const override;
+    void didReceiveResponse(unsigned long, const ResourceResponse&) final;
+    void didReceiveData(const char*, int) final;
+    void didFinishLoading(unsigned long, double) final;
+    void didFail(const ResourceError&) final;
+    void didFailAccessControlCheck(const ResourceError&) final;
+    void didFailRedirectCheck() final;
 
+    void stop() final;
+    const char* activeDOMObjectName() const final;
+    bool canSuspendForDocumentSuspension() const final;
+
     void connect();
     void networkRequestEnded();
     void scheduleInitialConnect();
     void scheduleReconnect();
     void abortConnectionAttempt();
     void parseEventStream();
-    void parseEventStreamLine(unsigned pos, int fieldLength, int lineLength);
-    Ref<MessageEvent> createMessageEvent();
+    void parseEventStreamLine(unsigned position, Optional<unsigned> fieldLength, unsigned lineLength);
+    void dispatchMessageEvent();
 
+    bool responseIsValid(const ResourceResponse&) const;
+
+    static const uint64_t defaultReconnectDelay;
+
     URL m_url;
     bool m_withCredentials;
-    State m_state;
+    State m_state { CONNECTING };
 
-    RefPtr<TextResourceDecoder> m_decoder;
+    Ref<TextResourceDecoder> m_decoder;
     RefPtr<ThreadableLoader> m_loader;
     Timer m_connectTimer;
-    Vector<UChar> m_receiveBuf;
-    bool m_discardTrailingNewline;
-    bool m_requestInFlight;
+    Vector<UChar> m_receiveBuffer;
+    bool m_discardTrailingNewline { false };
+    bool m_requestInFlight { false };
 
-    String m_eventName;
+    AtomicString m_eventName;
     Vector<UChar> m_data;
     String m_currentlyParsedEventId;
     String m_lastEventId;
-    unsigned long long m_reconnectDelay;
+    uint64_t m_reconnectDelay { defaultReconnectDelay };
     String m_eventStreamOrigin;
 };
 
+inline const String& EventSource::url() const
+{
+    return m_url.string();
+}
+
+inline bool EventSource::withCredentials() const
+{
+    return m_withCredentials;
+}
+
+inline EventSource::State EventSource::readyState() const
+{
+    return m_state;
+}
+
 } // namespace WebCore
-
-#endif // EventSource_h

Modified: trunk/Source/WebCore/page/EventSource.idl (200557 => 200558)


--- trunk/Source/WebCore/page/EventSource.idl	2016-05-08 18:35:23 UTC (rev 200557)
+++ trunk/Source/WebCore/page/EventSource.idl	2016-05-08 18:46:53 UTC (rev 200558)
@@ -32,11 +32,10 @@
 [
     Exposed=(Window,Worker),
     ActiveDOMObject,
-    Constructor(DOMString url, optional Dictionary eventSourceInit),
+    Constructor(DOMString url, optional EventSourceInit eventSourceInitDict),
     ConstructorCallWith=ScriptExecutionContext,
     ConstructorRaisesException,
 ] interface EventSource : EventTarget {
-
     readonly attribute DOMString URL; // Lowercased .url is the one in the spec, but leaving .URL for compatibility reasons.
     readonly attribute DOMString url;
     readonly attribute boolean withCredentials;
@@ -53,3 +52,7 @@
     attribute EventHandler onerror;
     void close();
 };
+
+dictionary EventSourceInit {
+    boolean withCredentials = false;
+};
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to