1231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block/* 2231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * Copyright (C) 2009 Ericsson AB 3231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * All rights reserved. 4e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke * Copyright (C) 2010 Apple Inc. All rights reserved. 52daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch * Copyright (C) 2011, Code Aurora Forum. All rights reserved. 6231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 7231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * Redistribution and use in source and binary forms, with or without 8231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * modification, are permitted provided that the following conditions 9231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * are met: 10231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 11231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 1. Redistributions of source code must retain the above copyright 12231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * notice, this list of conditions and the following disclaimer. 13231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 2. Redistributions in binary form must reproduce the above copyright 14231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * notice, this list of conditions and the following disclaimer 15231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * in the documentation and/or other materials provided with the 16231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * distribution. 17231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 3. Neither the name of Ericsson nor the names of its contributors 18231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * may be used to endorse or promote products derived from this 19231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * software without specific prior written permission. 20231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * 21231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block */ 33231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 34231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "config.h" 35231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 36231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#if ENABLE(EVENTSOURCE) 37231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 38231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "EventSource.h" 39231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 4028040489d744e0c5d475a88663056c9040ed5320Teng-Hui Zhu#include "MemoryCache.h" 41231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "DOMWindow.h" 42231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "Event.h" 43231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "EventException.h" 44231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "PlatformString.h" 45231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "MessageEvent.h" 46231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "ResourceError.h" 47231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "ResourceRequest.h" 48231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "ResourceResponse.h" 492daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include "ScriptCallStack.h" 50231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "ScriptExecutionContext.h" 51231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "SerializedScriptValue.h" 52231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "TextResourceDecoder.h" 53231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#include "ThreadableLoader.h" 54231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 55231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blocknamespace WebCore { 56231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 57231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockconst unsigned long long EventSource::defaultReconnectDelay = 3000; 58231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 59e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarkeinline EventSource::EventSource(const KURL& url, ScriptExecutionContext* context) 60231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block : ActiveDOMObject(context, this) 61e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke , m_url(url) 62231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block , m_state(CONNECTING) 63e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke , m_decoder(TextResourceDecoder::create("text/plain", "UTF-8")) 64231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block , m_reconnectTimer(this, &EventSource::reconnectTimerFired) 65d0825bca7fe65beaee391d30da42e937db621564Steve Block , m_discardTrailingNewline(false) 66231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block , m_failSilently(false) 67231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block , m_requestInFlight(false) 68231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block , m_reconnectDelay(defaultReconnectDelay) 69e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke , m_origin(context->securityOrigin()->toString()) 70231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 71e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke} 72e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 73e458d70a0d18538346f41b503114c9ebe6b2ce12Leon ClarkePassRefPtr<EventSource> EventSource::create(const String& url, ScriptExecutionContext* context, ExceptionCode& ec) 74e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke{ 75e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (url.isEmpty()) { 76e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke ec = SYNTAX_ERR; 77e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return 0; 78e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke } 79e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 80e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke KURL fullURL = context->completeURL(url); 81e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (!fullURL.isValid()) { 82231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block ec = SYNTAX_ERR; 83e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return 0; 84231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 85e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 86e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke // FIXME: Should support at least some cross-origin requests. 87e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke if (!context->securityOrigin()->canRequest(fullURL)) { 88231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block ec = SECURITY_ERR; 89e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return 0; 90231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 91231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 92e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke RefPtr<EventSource> source = adoptRef(new EventSource(fullURL, context)); 93e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke 94e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke source->setPendingActivity(source.get()); 95e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke source->connect(); 96231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 97e458d70a0d18538346f41b503114c9ebe6b2ce12Leon Clarke return source.release(); 98231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 99231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 100231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockEventSource::~EventSource() 101231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 102231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 103231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 104231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid EventSource::connect() 105231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 106231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block ResourceRequest request(m_url); 107231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block request.setHTTPMethod("GET"); 108231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block request.setHTTPHeaderField("Accept", "text/event-stream"); 109231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block request.setHTTPHeaderField("Cache-Control", "no-cache"); 110231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (!m_lastEventId.isEmpty()) 111231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block request.setHTTPHeaderField("Last-Event-ID", m_lastEventId); 112231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 113231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block ThreadableLoaderOptions options; 114231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block options.sendLoadCallbacks = true; 115231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block options.sniffContent = false; 116231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block options.allowCredentials = true; 117231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 118231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options); 119231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 120231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_requestInFlight = true; 121231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 122231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 123231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid EventSource::endRequest() 124231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 1254576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang if (!m_requestInFlight) 1264576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang return; 1274576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang 128231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_requestInFlight = false; 129231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 130231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (!m_failSilently) 131231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block dispatchEvent(Event::create(eventNames().errorEvent, false, false)); 132231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 133231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (m_state != CLOSED) 134231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block scheduleReconnect(); 135231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block else 136231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block unsetPendingActivity(this); 137231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 138231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 139231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid EventSource::scheduleReconnect() 140231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 141231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_state = CONNECTING; 142231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_reconnectTimer.startOneShot(m_reconnectDelay / 1000); 143231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 144231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 145231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid EventSource::reconnectTimerFired(Timer<EventSource>*) 146231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 147231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block connect(); 148231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 149231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 150231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockString EventSource::url() const 151231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 152231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return m_url.string(); 153231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 154231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 155231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockEventSource::State EventSource::readyState() const 156231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 157231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return m_state; 158231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 159231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 160231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid EventSource::close() 161231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 162231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (m_state == CLOSED) 163231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return; 164231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 165231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (m_reconnectTimer.isActive()) { 166231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_reconnectTimer.stop(); 167231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block unsetPendingActivity(this); 168231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 169231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 170231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_state = CLOSED; 171231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_failSilently = true; 172231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 173231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (m_requestInFlight) 174231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_loader->cancel(); 175231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 176231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 177231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockScriptExecutionContext* EventSource::scriptExecutionContext() const 178231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 179231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return ActiveDOMObject::scriptExecutionContext(); 180231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 181231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 182231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid EventSource::didReceiveResponse(const ResourceResponse& response) 183231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 184231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block int statusCode = response.httpStatusCode(); 1852daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch bool mimeTypeIsValid = response.mimeType() == "text/event-stream"; 1862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch bool responseIsValid = statusCode == 200 && mimeTypeIsValid; 1872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (responseIsValid) { 1882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch const String& charset = response.textEncodingName(); 1892daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // If we have a charset, the only allowed value is UTF-8 (case-insensitive). This should match 1902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // the updated EventSource standard. 1912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch responseIsValid = charset.isEmpty() || equalIgnoringCase(charset, "UTF-8"); 1922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (!responseIsValid) { 1932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch String message = "EventSource's response has a charset (\""; 1942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch message += charset; 1952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch message += "\") that is not UTF-8. Aborting the connection."; 1962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // FIXME: We are missing the source line. 1972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch scriptExecutionContext()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String(), 0); 1982daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 1992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } else { 2002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // To keep the signal-to-noise ratio low, we only log 200-response with an invalid MIME type. 2012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (statusCode == 200 && !mimeTypeIsValid) { 2022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch String message = "EventSource's response has a MIME type (\""; 2032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch message += response.mimeType(); 2042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch message += "\") that is not \"text/event-stream\". Aborting the connection."; 2052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // FIXME: We are missing the source line. 2062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch scriptExecutionContext()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, message, 1, String(), 0); 2072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 2082daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 2092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 2102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (responseIsValid) { 211231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_state = OPEN; 212231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block dispatchEvent(Event::create(eventNames().openEvent, false, false)); 213231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } else { 214231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (statusCode <= 200 || statusCode > 299) 215231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_state = CLOSED; 216231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_loader->cancel(); 217231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 218231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 219231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 220231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid EventSource::didReceiveData(const char* data, int length) 221231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 222231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block append(m_receiveBuf, m_decoder->decode(data, length)); 223231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block parseEventStream(); 224231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 225231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 22681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid EventSource::didFinishLoading(unsigned long, double) 227231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 228231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (m_receiveBuf.size() > 0 || m_data.size() > 0) { 229231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block append(m_receiveBuf, "\n\n"); 230231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block parseEventStream(); 231231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 232231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_state = CONNECTING; 233231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block endRequest(); 234231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 235231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 236231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid EventSource::didFail(const ResourceError& error) 237231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 238231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block int canceled = error.isCancellation(); 239231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (((m_state == CONNECTING) && !canceled) || ((m_state == OPEN) && canceled)) 240231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_state = CLOSED; 241231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block endRequest(); 242231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 243231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 244231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid EventSource::didFailRedirectCheck() 245231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 246231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_state = CLOSED; 247231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_loader->cancel(); 248231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 249231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 250231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid EventSource::parseEventStream() 251231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 252231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block unsigned int bufPos = 0; 253231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block unsigned int bufSize = m_receiveBuf.size(); 254d0825bca7fe65beaee391d30da42e937db621564Steve Block while (bufPos < bufSize) { 255d0825bca7fe65beaee391d30da42e937db621564Steve Block if (m_discardTrailingNewline) { 256d0825bca7fe65beaee391d30da42e937db621564Steve Block if (m_receiveBuf[bufPos] == '\n') 257d0825bca7fe65beaee391d30da42e937db621564Steve Block bufPos++; 258d0825bca7fe65beaee391d30da42e937db621564Steve Block m_discardTrailingNewline = false; 259d0825bca7fe65beaee391d30da42e937db621564Steve Block } 260d0825bca7fe65beaee391d30da42e937db621564Steve Block 261231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block int lineLength = -1; 262231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block int fieldLength = -1; 263231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block for (unsigned int i = bufPos; lineLength < 0 && i < bufSize; i++) { 264231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block switch (m_receiveBuf[i]) { 265231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block case ':': 266231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (fieldLength < 0) 267231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block fieldLength = i - bufPos; 268231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block break; 269d0825bca7fe65beaee391d30da42e937db621564Steve Block case '\r': 270d0825bca7fe65beaee391d30da42e937db621564Steve Block m_discardTrailingNewline = true; 271231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block case '\n': 272231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block lineLength = i - bufPos; 273231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block break; 274231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 275231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 276231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 277231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (lineLength < 0) 278231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block break; 279231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 280231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block parseEventStreamLine(bufPos, fieldLength, lineLength); 281d0825bca7fe65beaee391d30da42e937db621564Steve Block bufPos += lineLength + 1; 282231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 283231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 284231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (bufPos == bufSize) 285231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_receiveBuf.clear(); 286231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block else if (bufPos) 287231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_receiveBuf.remove(0, bufPos); 288231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 289231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 290231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid EventSource::parseEventStreamLine(unsigned int bufPos, int fieldLength, int lineLength) 291231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 292231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (!lineLength) { 293dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!m_data.isEmpty()) { 294dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block m_data.removeLast(); 295231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block dispatchEvent(createMessageEvent()); 296dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 297231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (!m_eventName.isEmpty()) 298231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_eventName = ""; 299231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } else if (fieldLength) { 300231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block bool noValue = fieldLength < 0; 301231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 302231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block String field(&m_receiveBuf[bufPos], noValue ? lineLength : fieldLength); 303231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block int step; 304231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (noValue) 305231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block step = lineLength; 306231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block else if (m_receiveBuf[bufPos + fieldLength + 1] != ' ') 307231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block step = fieldLength + 1; 308231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block else 309231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block step = fieldLength + 2; 310231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block bufPos += step; 311231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block int valueLength = lineLength - step; 312231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 313231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (field == "data") { 314231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (valueLength) 315231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_data.append(&m_receiveBuf[bufPos], valueLength); 316dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block m_data.append('\n'); 317231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } else if (field == "event") 318231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_eventName = valueLength ? String(&m_receiveBuf[bufPos], valueLength) : ""; 319231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block else if (field == "id") 320231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_lastEventId = valueLength ? String(&m_receiveBuf[bufPos], valueLength) : ""; 321231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block else if (field == "retry") { 322231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (!valueLength) 323231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_reconnectDelay = defaultReconnectDelay; 324231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block else { 325231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block String value(&m_receiveBuf[bufPos], valueLength); 326231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block bool ok; 327231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block unsigned long long retry = value.toUInt64(&ok); 328231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block if (ok) 329231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block m_reconnectDelay = retry; 330231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 331231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 332231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block } 333231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 334231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 335231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockvoid EventSource::stop() 336231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 337231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block close(); 338231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 339231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 340231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockPassRefPtr<MessageEvent> EventSource::createMessageEvent() 341231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 342231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block RefPtr<MessageEvent> event = MessageEvent::create(); 343231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block event->initMessageEvent(m_eventName.isEmpty() ? eventNames().messageEvent : AtomicString(m_eventName), false, false, SerializedScriptValue::create(String::adopt(m_data)), m_origin, m_lastEventId, 0, 0); 344231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return event.release(); 345231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 346231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 347231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockEventTargetData* EventSource::eventTargetData() 348231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 349231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return &m_eventTargetData; 350231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 351231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 352231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockEventTargetData* EventSource::ensureEventTargetData() 353231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{ 354231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return &m_eventTargetData; 355231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} 356231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 357231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block} // namespace WebCore 358231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block 359231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#endif // ENABLE(EVENTSOURCE) 360