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;
+};