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