| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2009, 2012 Ericsson AB. All rights reserved. | 2 * Copyright (C) 2009, 2012 Ericsson AB. All rights reserved. |
| 3 * Copyright (C) 2010 Apple Inc. All rights reserved. | 3 * Copyright (C) 2010 Apple Inc. All rights reserved. |
| 4 * Copyright (C) 2011, Code Aurora Forum. All rights reserved. | 4 * Copyright (C) 2011, Code Aurora Forum. All rights reserved. |
| 5 * | 5 * |
| 6 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
| 7 * modification, are permitted provided that the following conditions | 7 * modification, are permitted provided that the following conditions |
| 8 * are met: | 8 * are met: |
| 9 * | 9 * |
| 10 * 1. Redistributions of source code must retain the above copyright | 10 * 1. Redistributions of source code must retain the above copyright |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 60 namespace blink { | 60 namespace blink { |
| 61 | 61 |
| 62 const unsigned long long EventSource::defaultReconnectDelay = 3000; | 62 const unsigned long long EventSource::defaultReconnectDelay = 3000; |
| 63 | 63 |
| 64 inline EventSource::EventSource(ExecutionContext* context, const KURL& url, cons
t EventSourceInit& eventSourceInit) | 64 inline EventSource::EventSource(ExecutionContext* context, const KURL& url, cons
t EventSourceInit& eventSourceInit) |
| 65 : ActiveScriptWrappable(this) | 65 : ActiveScriptWrappable(this) |
| 66 , ActiveDOMObject(context) | 66 , ActiveDOMObject(context) |
| 67 , m_url(url) | 67 , m_url(url) |
| 68 , m_currentURL(url) | 68 , m_currentURL(url) |
| 69 , m_withCredentials(eventSourceInit.withCredentials()) | 69 , m_withCredentials(eventSourceInit.withCredentials()) |
| 70 , m_state(CONNECTING) | 70 , m_state(kConnecting) |
| 71 , m_connectTimer(this, &EventSource::connectTimerFired) | 71 , m_connectTimer(this, &EventSource::connectTimerFired) |
| 72 , m_reconnectDelay(defaultReconnectDelay) | 72 , m_reconnectDelay(defaultReconnectDelay) |
| 73 { | 73 { |
| 74 } | 74 } |
| 75 | 75 |
| 76 EventSource* EventSource::create(ExecutionContext* context, const String& url, c
onst EventSourceInit& eventSourceInit, ExceptionState& exceptionState) | 76 EventSource* EventSource::create(ExecutionContext* context, const String& url, c
onst EventSourceInit& eventSourceInit, ExceptionState& exceptionState) |
| 77 { | 77 { |
| 78 if (url.isEmpty()) { | 78 if (url.isEmpty()) { |
| 79 exceptionState.throwDOMException(SyntaxError, "Cannot open an EventSourc
e to an empty URL."); | 79 exceptionState.throwDOMException(SyntaxError, "Cannot open an EventSourc
e to an empty URL."); |
| 80 return nullptr; | 80 return nullptr; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 95 | 95 |
| 96 EventSource* source = new EventSource(context, fullURL, eventSourceInit); | 96 EventSource* source = new EventSource(context, fullURL, eventSourceInit); |
| 97 | 97 |
| 98 source->scheduleInitialConnect(); | 98 source->scheduleInitialConnect(); |
| 99 source->suspendIfNeeded(); | 99 source->suspendIfNeeded(); |
| 100 return source; | 100 return source; |
| 101 } | 101 } |
| 102 | 102 |
| 103 EventSource::~EventSource() | 103 EventSource::~EventSource() |
| 104 { | 104 { |
| 105 ASSERT(m_state == CLOSED); | 105 DCHECK_EQ(kClosed, m_state); |
| 106 ASSERT(!m_loader); | 106 DCHECK(!m_loader); |
| 107 } | 107 } |
| 108 | 108 |
| 109 void EventSource::scheduleInitialConnect() | 109 void EventSource::scheduleInitialConnect() |
| 110 { | 110 { |
| 111 ASSERT(m_state == CONNECTING); | 111 DCHECK_EQ(kConnecting, m_state); |
| 112 ASSERT(!m_loader); | 112 DCHECK(!m_loader); |
| 113 | 113 |
| 114 m_connectTimer.startOneShot(0, BLINK_FROM_HERE); | 114 m_connectTimer.startOneShot(0, BLINK_FROM_HERE); |
| 115 } | 115 } |
| 116 | 116 |
| 117 void EventSource::connect() | 117 void EventSource::connect() |
| 118 { | 118 { |
| 119 ASSERT(m_state == CONNECTING); | 119 DCHECK_EQ(kConnecting, m_state); |
| 120 ASSERT(!m_loader); | 120 DCHECK(!m_loader); |
| 121 ASSERT(getExecutionContext()); | 121 DCHECK(getExecutionContext()); |
| 122 | 122 |
| 123 ExecutionContext& executionContext = *this->getExecutionContext(); | 123 ExecutionContext& executionContext = *this->getExecutionContext(); |
| 124 ResourceRequest request(m_currentURL); | 124 ResourceRequest request(m_currentURL); |
| 125 request.setHTTPMethod(HTTPNames::GET); | 125 request.setHTTPMethod(HTTPNames::GET); |
| 126 request.setHTTPHeaderField(HTTPNames::Accept, "text/event-stream"); | 126 request.setHTTPHeaderField(HTTPNames::Accept, "text/event-stream"); |
| 127 request.setHTTPHeaderField(HTTPNames::Cache_Control, "no-cache"); | 127 request.setHTTPHeaderField(HTTPNames::Cache_Control, "no-cache"); |
| 128 request.setRequestContext(WebURLRequest::RequestContextEventSource); | 128 request.setRequestContext(WebURLRequest::RequestContextEventSource); |
| 129 request.setExternalRequestStateFromRequestorAddressSpace(executionContext.se
curityContext().addressSpace()); | 129 request.setExternalRequestStateFromRequestorAddressSpace(executionContext.se
curityContext().addressSpace()); |
| 130 if (m_parser && !m_parser->lastEventId().isEmpty()) { | 130 if (m_parser && !m_parser->lastEventId().isEmpty()) { |
| 131 // HTTP headers are Latin-1 byte strings, but the Last-Event-ID header i
s encoded as UTF-8. | 131 // HTTP headers are Latin-1 byte strings, but the Last-Event-ID header i
s encoded as UTF-8. |
| (...skipping 20 matching lines...) Expand all Loading... |
| 152 m_loader = ThreadableLoader::create(executionContext, this, options, resourc
eLoaderOptions); | 152 m_loader = ThreadableLoader::create(executionContext, this, options, resourc
eLoaderOptions); |
| 153 m_loader->start(request); | 153 m_loader->start(request); |
| 154 } | 154 } |
| 155 | 155 |
| 156 void EventSource::networkRequestEnded() | 156 void EventSource::networkRequestEnded() |
| 157 { | 157 { |
| 158 InspectorInstrumentation::didFinishEventSourceRequest(getExecutionContext(),
this); | 158 InspectorInstrumentation::didFinishEventSourceRequest(getExecutionContext(),
this); |
| 159 | 159 |
| 160 m_loader = nullptr; | 160 m_loader = nullptr; |
| 161 | 161 |
| 162 if (m_state != CLOSED) | 162 if (m_state != kClosed) |
| 163 scheduleReconnect(); | 163 scheduleReconnect(); |
| 164 } | 164 } |
| 165 | 165 |
| 166 void EventSource::scheduleReconnect() | 166 void EventSource::scheduleReconnect() |
| 167 { | 167 { |
| 168 m_state = CONNECTING; | 168 m_state = kConnecting; |
| 169 m_connectTimer.startOneShot(m_reconnectDelay / 1000.0, BLINK_FROM_HERE); | 169 m_connectTimer.startOneShot(m_reconnectDelay / 1000.0, BLINK_FROM_HERE); |
| 170 dispatchEvent(Event::create(EventTypeNames::error)); | 170 dispatchEvent(Event::create(EventTypeNames::error)); |
| 171 } | 171 } |
| 172 | 172 |
| 173 void EventSource::connectTimerFired(Timer<EventSource>*) | 173 void EventSource::connectTimerFired(Timer<EventSource>*) |
| 174 { | 174 { |
| 175 connect(); | 175 connect(); |
| 176 } | 176 } |
| 177 | 177 |
| 178 String EventSource::url() const | 178 String EventSource::url() const |
| 179 { | 179 { |
| 180 return m_url.getString(); | 180 return m_url.getString(); |
| 181 } | 181 } |
| 182 | 182 |
| 183 bool EventSource::withCredentials() const | 183 bool EventSource::withCredentials() const |
| 184 { | 184 { |
| 185 return m_withCredentials; | 185 return m_withCredentials; |
| 186 } | 186 } |
| 187 | 187 |
| 188 EventSource::State EventSource::readyState() const | 188 EventSource::State EventSource::readyState() const |
| 189 { | 189 { |
| 190 return m_state; | 190 return m_state; |
| 191 } | 191 } |
| 192 | 192 |
| 193 void EventSource::close() | 193 void EventSource::close() |
| 194 { | 194 { |
| 195 if (m_state == CLOSED) { | 195 if (m_state == kClosed) { |
| 196 ASSERT(!m_loader); | 196 DCHECK(!m_loader); |
| 197 return; | 197 return; |
| 198 } | 198 } |
| 199 if (m_parser) | 199 if (m_parser) |
| 200 m_parser->stop(); | 200 m_parser->stop(); |
| 201 | 201 |
| 202 // Stop trying to reconnect if EventSource was explicitly closed or if Activ
eDOMObject::stop() was called. | 202 // Stop trying to reconnect if EventSource was explicitly closed or if Activ
eDOMObject::stop() was called. |
| 203 if (m_connectTimer.isActive()) { | 203 if (m_connectTimer.isActive()) { |
| 204 m_connectTimer.stop(); | 204 m_connectTimer.stop(); |
| 205 } | 205 } |
| 206 | 206 |
| 207 if (m_loader) { | 207 if (m_loader) { |
| 208 m_loader->cancel(); | 208 m_loader->cancel(); |
| 209 m_loader = nullptr; | 209 m_loader = nullptr; |
| 210 } | 210 } |
| 211 | 211 |
| 212 m_state = CLOSED; | 212 m_state = kClosed; |
| 213 } | 213 } |
| 214 | 214 |
| 215 const AtomicString& EventSource::interfaceName() const | 215 const AtomicString& EventSource::interfaceName() const |
| 216 { | 216 { |
| 217 return EventTargetNames::EventSource; | 217 return EventTargetNames::EventSource; |
| 218 } | 218 } |
| 219 | 219 |
| 220 ExecutionContext* EventSource::getExecutionContext() const | 220 ExecutionContext* EventSource::getExecutionContext() const |
| 221 { | 221 { |
| 222 return ActiveDOMObject::getExecutionContext(); | 222 return ActiveDOMObject::getExecutionContext(); |
| 223 } | 223 } |
| 224 | 224 |
| 225 void EventSource::didReceiveResponse(unsigned long, const ResourceResponse& resp
onse, std::unique_ptr<WebDataConsumerHandle> handle) | 225 void EventSource::didReceiveResponse(unsigned long, const ResourceResponse& resp
onse, std::unique_ptr<WebDataConsumerHandle> handle) |
| 226 { | 226 { |
| 227 ASSERT_UNUSED(handle, !handle); | 227 ASSERT_UNUSED(handle, !handle); |
| 228 ASSERT(m_state == CONNECTING); | 228 DCHECK_EQ(kConnecting, m_state); |
| 229 ASSERT(m_loader); | 229 DCHECK(m_loader); |
| 230 | 230 |
| 231 m_currentURL = response.url(); | 231 m_currentURL = response.url(); |
| 232 m_eventStreamOrigin = SecurityOrigin::create(response.url())->toString(); | 232 m_eventStreamOrigin = SecurityOrigin::create(response.url())->toString(); |
| 233 int statusCode = response.httpStatusCode(); | 233 int statusCode = response.httpStatusCode(); |
| 234 bool mimeTypeIsValid = response.mimeType() == "text/event-stream"; | 234 bool mimeTypeIsValid = response.mimeType() == "text/event-stream"; |
| 235 bool responseIsValid = statusCode == 200 && mimeTypeIsValid; | 235 bool responseIsValid = statusCode == 200 && mimeTypeIsValid; |
| 236 if (responseIsValid) { | 236 if (responseIsValid) { |
| 237 const String& charset = response.textEncodingName(); | 237 const String& charset = response.textEncodingName(); |
| 238 // If we have a charset, the only allowed value is UTF-8 (case-insensiti
ve). | 238 // If we have a charset, the only allowed value is UTF-8 (case-insensiti
ve). |
| 239 responseIsValid = charset.isEmpty() || equalIgnoringCase(charset, "UTF-8
"); | 239 responseIsValid = charset.isEmpty() || equalIgnoringCase(charset, "UTF-8
"); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 251 StringBuilder message; | 251 StringBuilder message; |
| 252 message.append("EventSource's response has a MIME type (\""); | 252 message.append("EventSource's response has a MIME type (\""); |
| 253 message.append(response.mimeType()); | 253 message.append(response.mimeType()); |
| 254 message.append("\") that is not \"text/event-stream\". Aborting the
connection."); | 254 message.append("\") that is not \"text/event-stream\". Aborting the
connection."); |
| 255 // FIXME: We are missing the source line. | 255 // FIXME: We are missing the source line. |
| 256 getExecutionContext()->addConsoleMessage(ConsoleMessage::create(JSMe
ssageSource, ErrorMessageLevel, message.toString())); | 256 getExecutionContext()->addConsoleMessage(ConsoleMessage::create(JSMe
ssageSource, ErrorMessageLevel, message.toString())); |
| 257 } | 257 } |
| 258 } | 258 } |
| 259 | 259 |
| 260 if (responseIsValid) { | 260 if (responseIsValid) { |
| 261 m_state = OPEN; | 261 m_state = kOpen; |
| 262 AtomicString lastEventId; | 262 AtomicString lastEventId; |
| 263 if (m_parser) { | 263 if (m_parser) { |
| 264 // The new parser takes over the event ID. | 264 // The new parser takes over the event ID. |
| 265 lastEventId = m_parser->lastEventId(); | 265 lastEventId = m_parser->lastEventId(); |
| 266 } | 266 } |
| 267 m_parser = new EventSourceParser(lastEventId, this); | 267 m_parser = new EventSourceParser(lastEventId, this); |
| 268 dispatchEvent(Event::create(EventTypeNames::open)); | 268 dispatchEvent(Event::create(EventTypeNames::open)); |
| 269 } else { | 269 } else { |
| 270 m_loader->cancel(); | 270 m_loader->cancel(); |
| 271 dispatchEvent(Event::create(EventTypeNames::error)); | 271 dispatchEvent(Event::create(EventTypeNames::error)); |
| 272 } | 272 } |
| 273 } | 273 } |
| 274 | 274 |
| 275 void EventSource::didReceiveData(const char* data, unsigned length) | 275 void EventSource::didReceiveData(const char* data, unsigned length) |
| 276 { | 276 { |
| 277 ASSERT(m_state == OPEN); | 277 DCHECK_EQ(kOpen, m_state); |
| 278 ASSERT(m_loader); | 278 DCHECK(m_loader); |
| 279 ASSERT(m_parser); | 279 DCHECK(m_parser); |
| 280 | 280 |
| 281 m_parser->addBytes(data, length); | 281 m_parser->addBytes(data, length); |
| 282 } | 282 } |
| 283 | 283 |
| 284 void EventSource::didFinishLoading(unsigned long, double) | 284 void EventSource::didFinishLoading(unsigned long, double) |
| 285 { | 285 { |
| 286 ASSERT(m_state == OPEN); | 286 DCHECK_EQ(kOpen, m_state); |
| 287 ASSERT(m_loader); | 287 DCHECK(m_loader); |
| 288 | 288 |
| 289 networkRequestEnded(); | 289 networkRequestEnded(); |
| 290 } | 290 } |
| 291 | 291 |
| 292 void EventSource::didFail(const ResourceError& error) | 292 void EventSource::didFail(const ResourceError& error) |
| 293 { | 293 { |
| 294 ASSERT(m_state != CLOSED); | 294 DCHECK_NE(kClosed, m_state); |
| 295 ASSERT(m_loader); | 295 DCHECK(m_loader); |
| 296 | 296 |
| 297 if (error.isCancellation()) | 297 if (error.isCancellation()) |
| 298 m_state = CLOSED; | 298 m_state = kClosed; |
| 299 networkRequestEnded(); | 299 networkRequestEnded(); |
| 300 } | 300 } |
| 301 | 301 |
| 302 void EventSource::didFailAccessControlCheck(const ResourceError& error) | 302 void EventSource::didFailAccessControlCheck(const ResourceError& error) |
| 303 { | 303 { |
| 304 ASSERT(m_loader); | 304 DCHECK(m_loader); |
| 305 | 305 |
| 306 String message = "EventSource cannot load " + error.failingURL() + ". " + er
ror.localizedDescription(); | 306 String message = "EventSource cannot load " + error.failingURL() + ". " + er
ror.localizedDescription(); |
| 307 getExecutionContext()->addConsoleMessage(ConsoleMessage::create(JSMessageSou
rce, ErrorMessageLevel, message)); | 307 getExecutionContext()->addConsoleMessage(ConsoleMessage::create(JSMessageSou
rce, ErrorMessageLevel, message)); |
| 308 | 308 |
| 309 abortConnectionAttempt(); | 309 abortConnectionAttempt(); |
| 310 } | 310 } |
| 311 | 311 |
| 312 void EventSource::didFailRedirectCheck() | 312 void EventSource::didFailRedirectCheck() |
| 313 { | 313 { |
| 314 ASSERT(m_loader); | 314 DCHECK(m_loader); |
| 315 | 315 |
| 316 abortConnectionAttempt(); | 316 abortConnectionAttempt(); |
| 317 } | 317 } |
| 318 | 318 |
| 319 void EventSource::onMessageEvent(const AtomicString& eventType, const String& da
ta, const AtomicString& lastEventId) | 319 void EventSource::onMessageEvent(const AtomicString& eventType, const String& da
ta, const AtomicString& lastEventId) |
| 320 { | 320 { |
| 321 MessageEvent* e = MessageEvent::create(); | 321 MessageEvent* e = MessageEvent::create(); |
| 322 e->initMessageEvent(eventType, false, false, SerializedScriptValue::serializ
e(data), m_eventStreamOrigin, lastEventId, 0, nullptr); | 322 e->initMessageEvent(eventType, false, false, SerializedScriptValue::serializ
e(data), m_eventStreamOrigin, lastEventId, 0, nullptr); |
| 323 | 323 |
| 324 InspectorInstrumentation::willDispatchEventSourceEvent(getExecutionContext()
, this, eventType, lastEventId, data); | 324 InspectorInstrumentation::willDispatchEventSourceEvent(getExecutionContext()
, this, eventType, lastEventId, data); |
| 325 dispatchEvent(e); | 325 dispatchEvent(e); |
| 326 } | 326 } |
| 327 | 327 |
| 328 void EventSource::onReconnectionTimeSet(unsigned long long reconnectionTime) | 328 void EventSource::onReconnectionTimeSet(unsigned long long reconnectionTime) |
| 329 { | 329 { |
| 330 m_reconnectDelay = reconnectionTime; | 330 m_reconnectDelay = reconnectionTime; |
| 331 } | 331 } |
| 332 | 332 |
| 333 void EventSource::abortConnectionAttempt() | 333 void EventSource::abortConnectionAttempt() |
| 334 { | 334 { |
| 335 ASSERT(m_state == CONNECTING); | 335 DCHECK_EQ(kConnecting, m_state); |
| 336 | 336 |
| 337 m_loader = nullptr; | 337 m_loader = nullptr; |
| 338 m_state = CLOSED; | 338 m_state = kClosed; |
| 339 networkRequestEnded(); | 339 networkRequestEnded(); |
| 340 | 340 |
| 341 dispatchEvent(Event::create(EventTypeNames::error)); | 341 dispatchEvent(Event::create(EventTypeNames::error)); |
| 342 } | 342 } |
| 343 | 343 |
| 344 void EventSource::stop() | 344 void EventSource::stop() |
| 345 { | 345 { |
| 346 close(); | 346 close(); |
| 347 } | 347 } |
| 348 | 348 |
| 349 bool EventSource::hasPendingActivity() const | 349 bool EventSource::hasPendingActivity() const |
| 350 { | 350 { |
| 351 return m_state != CLOSED; | 351 return m_state != kClosed; |
| 352 } | 352 } |
| 353 | 353 |
| 354 DEFINE_TRACE(EventSource) | 354 DEFINE_TRACE(EventSource) |
| 355 { | 355 { |
| 356 visitor->trace(m_parser); | 356 visitor->trace(m_parser); |
| 357 EventTargetWithInlineData::trace(visitor); | 357 EventTargetWithInlineData::trace(visitor); |
| 358 ActiveDOMObject::trace(visitor); | 358 ActiveDOMObject::trace(visitor); |
| 359 EventSourceParser::Client::trace(visitor); | 359 EventSourceParser::Client::trace(visitor); |
| 360 } | 360 } |
| 361 | 361 |
| 362 } // namespace blink | 362 } // namespace blink |
| OLD | NEW |