Chromium Code Reviews| Index: third_party/WebKit/Source/core/page/EventSource.cpp |
| diff --git a/third_party/WebKit/Source/core/page/EventSource.cpp b/third_party/WebKit/Source/core/page/EventSource.cpp |
| index 8b2231cb80c159fc92eafd520e9dc7df15411340..1995457e14725c796850ca482097a332f0a27b16 100644 |
| --- a/third_party/WebKit/Source/core/page/EventSource.cpp |
| +++ b/third_party/WebKit/Source/core/page/EventSource.cpp |
| @@ -44,7 +44,6 @@ |
| #include "core/frame/LocalDOMWindow.h" |
| #include "core/frame/LocalFrame.h" |
| #include "core/frame/csp/ContentSecurityPolicy.h" |
| -#include "core/html/parser/TextResourceDecoder.h" |
| #include "core/inspector/ConsoleMessage.h" |
| #include "core/inspector/InspectorInstrumentation.h" |
| #include "core/loader/ThreadableLoader.h" |
| @@ -55,7 +54,6 @@ |
| #include "platform/network/ResourceResponse.h" |
| #include "platform/weborigin/SecurityOrigin.h" |
| #include "public/platform/WebURLRequest.h" |
| -#include "wtf/ASCIICType.h" |
| #include "wtf/text/StringBuilder.h" |
| namespace blink { |
| @@ -67,9 +65,7 @@ inline EventSource::EventSource(ExecutionContext* context, const KURL& url, cons |
| , m_url(url) |
| , m_withCredentials(eventSourceInit.withCredentials()) |
| , m_state(CONNECTING) |
| - , m_decoder(TextResourceDecoder::create("text/plain", "UTF-8")) |
| , m_connectTimer(this, &EventSource::connectTimerFired) |
| - , m_discardTrailingNewline(false) |
| , m_requestInFlight(false) |
| , m_reconnectDelay(defaultReconnectDelay) |
| { |
| @@ -128,10 +124,10 @@ void EventSource::connect() |
| request.setHTTPHeaderField(HTTPNames::Accept, "text/event-stream"); |
| request.setHTTPHeaderField(HTTPNames::Cache_Control, "no-cache"); |
| request.setRequestContext(WebURLRequest::RequestContextEventSource); |
| - if (!m_lastEventId.isEmpty()) { |
| + if (m_parser && !m_parser->lastEventId().isEmpty()) { |
| // HTTP headers are Latin-1 byte strings, but the Last-Event-ID header is encoded as UTF-8. |
| // TODO(davidben): This should be captured in the type of setHTTPHeaderField's arguments. |
| - CString lastEventIdUtf8 = m_lastEventId.utf8(); |
| + CString lastEventIdUtf8 = m_parser->lastEventId().utf8(); |
| request.setHTTPHeaderField(HTTPNames::Last_Event_ID, AtomicString(reinterpret_cast<const LChar*>(lastEventIdUtf8.data()), lastEventIdUtf8.length())); |
|
Tom Sepez
2016/02/12 17:14:30
So if this is untrusted, do we need to verfiy that
yhirano
2016/02/12 21:33:27
It cannot contain CR or LF, but it can contain oth
|
| } |
| @@ -202,6 +198,8 @@ void EventSource::close() |
| ASSERT(!m_requestInFlight); |
| return; |
| } |
| + if (m_parser) |
| + m_parser->stop(); |
| // Stop trying to reconnect if EventSource was explicitly closed or if ActiveDOMObject::stop() was called. |
| if (m_connectTimer.isActive()) { |
| @@ -260,6 +258,12 @@ void EventSource::didReceiveResponse(unsigned long, const ResourceResponse& resp |
| if (responseIsValid) { |
| m_state = OPEN; |
| + AtomicString lastEventId; |
| + if (m_parser) { |
| + // The new parser takes over the event ID. |
| + lastEventId = m_parser->lastEventId(); |
| + } |
| + m_parser = new EventSourceParser(lastEventId, this); |
| dispatchEvent(Event::create(EventTypeNames::open)); |
| } else { |
| m_loader->cancel(); |
| @@ -271,9 +275,9 @@ void EventSource::didReceiveData(const char* data, unsigned length) |
| { |
| ASSERT(m_state == OPEN); |
| ASSERT(m_requestInFlight); |
| + ASSERT(m_parser); |
| - append(m_receiveBuf, m_decoder->decode(data, length)); |
| - parseEventStream(); |
| + m_parser->addBytes(data, length); |
| } |
| void EventSource::didFinishLoading(unsigned long, double) |
| @@ -281,15 +285,6 @@ void EventSource::didFinishLoading(unsigned long, double) |
| ASSERT(m_state == OPEN); |
| ASSERT(m_requestInFlight); |
| - if (m_receiveBuf.size() > 0 || m_data.size() > 0) { |
| - parseEventStream(); |
| - |
| - // Discard everything that has not been dispatched by now. |
| - m_receiveBuf.clear(); |
| - m_data.clear(); |
| - m_eventName = emptyAtom; |
| - m_currentlyParsedEventId = nullAtom; |
| - } |
| networkRequestEnded(); |
| } |
| @@ -316,6 +311,20 @@ void EventSource::didFailRedirectCheck() |
| abortConnectionAttempt(); |
| } |
| +void EventSource::onMessageEvent(const AtomicString& eventType, const String& data, const AtomicString& lastEventId) |
| +{ |
| + RefPtrWillBeRawPtr<MessageEvent> e = MessageEvent::create(); |
| + e->initMessageEvent(eventType, false, false, SerializedScriptValueFactory::instance().create(data), m_eventStreamOrigin, lastEventId, 0, nullptr); |
| + |
| + InspectorInstrumentation::willDispatchEventSourceEvent(executionContext(), this, eventType, lastEventId, data); |
| + dispatchEvent(e); |
| +} |
| + |
| +void EventSource::onReconnectionTimeSet(unsigned long long reconnectionTime) |
| +{ |
| + m_reconnectDelay = reconnectionTime; |
| +} |
| + |
| void EventSource::abortConnectionAttempt() |
| { |
| ASSERT(m_state == CONNECTING); |
| @@ -327,105 +336,6 @@ void EventSource::abortConnectionAttempt() |
| dispatchEvent(Event::create(EventTypeNames::error)); |
| } |
| -void EventSource::parseEventStream() |
| -{ |
| - unsigned bufPos = 0; |
| - unsigned bufSize = m_receiveBuf.size(); |
| - while (bufPos < bufSize) { |
| - if (m_discardTrailingNewline) { |
| - if (m_receiveBuf[bufPos] == '\n') |
| - bufPos++; |
| - m_discardTrailingNewline = false; |
| - } |
| - |
| - int lineLength = -1; |
| - int fieldLength = -1; |
| - for (unsigned i = bufPos; lineLength < 0 && i < bufSize; i++) { |
| - switch (m_receiveBuf[i]) { |
| - case ':': |
| - if (fieldLength < 0) |
| - fieldLength = i - bufPos; |
| - break; |
| - case '\r': |
| - m_discardTrailingNewline = true; |
| - case '\n': |
| - lineLength = i - bufPos; |
| - break; |
| - } |
| - } |
| - |
| - if (lineLength < 0) |
| - break; |
| - |
| - parseEventStreamLine(bufPos, fieldLength, lineLength); |
| - bufPos += lineLength + 1; |
| - |
| - // EventSource.close() might've been called by one of the message event handlers. |
| - // Per spec, no further messages should be fired after that. |
| - if (m_state == CLOSED) |
| - break; |
| - } |
| - |
| - if (bufPos == bufSize) |
| - m_receiveBuf.clear(); |
| - else if (bufPos) |
| - m_receiveBuf.remove(0, bufPos); |
| -} |
| - |
| -void EventSource::parseEventStreamLine(unsigned bufPos, int fieldLength, int lineLength) |
| -{ |
| - if (!lineLength) { |
| - if (!m_data.isEmpty()) { |
| - m_data.removeLast(); |
| - if (!m_currentlyParsedEventId.isNull()) { |
| - m_lastEventId = m_currentlyParsedEventId; |
| - m_currentlyParsedEventId = nullAtom; |
| - } |
| - InspectorInstrumentation::willDispachEventSourceEvent(executionContext(), this, m_eventName.isEmpty() ? EventTypeNames::message : m_eventName, m_lastEventId, m_data); |
| - dispatchEvent(createMessageEvent()); |
| - } |
| - if (!m_eventName.isEmpty()) |
| - m_eventName = emptyAtom; |
| - } else if (fieldLength) { |
| - bool noValue = fieldLength < 0; |
| - |
| - 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 (field == "data") { |
| - if (valueLength) |
| - m_data.append(&m_receiveBuf[bufPos], valueLength); |
| - m_data.append('\n'); |
| - } else if (field == "event") { |
| - m_eventName = valueLength ? AtomicString(&m_receiveBuf[bufPos], valueLength) : ""; |
| - } else if (field == "id") { |
| - m_currentlyParsedEventId = valueLength ? AtomicString(&m_receiveBuf[bufPos], valueLength) : ""; |
| - } else if (field == "retry") { |
| - bool hasOnlyDigits = true; |
| - for (int i = 0; i < valueLength && hasOnlyDigits; ++i) { |
| - hasOnlyDigits = isASCIIDigit(m_receiveBuf[bufPos + i]); |
| - } |
| - if (!valueLength) { |
| - m_reconnectDelay = defaultReconnectDelay; |
| - } else if (hasOnlyDigits) { |
| - String value(&m_receiveBuf[bufPos], valueLength); |
| - bool ok; |
| - unsigned long long retry = value.toUInt64(&ok); |
| - if (ok) |
| - m_reconnectDelay = retry; |
| - } |
| - } |
| - } |
| -} |
| - |
| void EventSource::stop() |
| { |
| close(); |
| @@ -443,18 +353,12 @@ bool EventSource::hasPendingActivity() const |
| return m_state != CLOSED; |
| } |
| -PassRefPtrWillBeRawPtr<MessageEvent> EventSource::createMessageEvent() |
| -{ |
| - RefPtrWillBeRawPtr<MessageEvent> event = MessageEvent::create(); |
| - event->initMessageEvent(m_eventName.isEmpty() ? EventTypeNames::message : m_eventName, false, false, SerializedScriptValueFactory::instance().create(String(m_data)), m_eventStreamOrigin, m_lastEventId, 0, nullptr); |
| - m_data.clear(); |
| - return event.release(); |
| -} |
| - |
| DEFINE_TRACE(EventSource) |
| { |
| + visitor->trace(m_parser); |
| RefCountedGarbageCollectedEventTargetWithInlineData::trace(visitor); |
| ActiveDOMObject::trace(visitor); |
| + EventSourceParser::Client::trace(visitor); |
| } |
| } // namespace blink |