| 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 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 63 const unsigned long long EventSource::defaultReconnectDelay = 3000; | 63 const unsigned long long EventSource::defaultReconnectDelay = 3000; |
| 64 | 64 |
| 65 inline EventSource::EventSource(ExecutionContext* context, const KURL& url, cons
t EventSourceInit& eventSourceInit) | 65 inline EventSource::EventSource(ExecutionContext* context, const KURL& url, cons
t EventSourceInit& eventSourceInit) |
| 66 : ActiveDOMObject(context) | 66 : ActiveDOMObject(context) |
| 67 , m_url(url) | 67 , m_url(url) |
| 68 , m_withCredentials(eventSourceInit.withCredentials()) | 68 , m_withCredentials(eventSourceInit.withCredentials()) |
| 69 , m_state(CONNECTING) | 69 , m_state(CONNECTING) |
| 70 , m_decoder(TextResourceDecoder::create("text/plain", "UTF-8")) | 70 , m_decoder(TextResourceDecoder::create("text/plain", "UTF-8")) |
| 71 , m_connectTimer(this, &EventSource::connectTimerFired) | 71 , m_connectTimer(this, &EventSource::connectTimerFired) |
| 72 , m_discardTrailingNewline(false) | 72 , m_discardTrailingNewline(false) |
| 73 , m_requestInFlight(false) | |
| 74 , m_reconnectDelay(defaultReconnectDelay) | 73 , m_reconnectDelay(defaultReconnectDelay) |
| 75 { | 74 { |
| 76 } | 75 } |
| 77 | 76 |
| 78 EventSource* EventSource::create(ExecutionContext* context, const String& url, c
onst EventSourceInit& eventSourceInit, ExceptionState& exceptionState) | 77 EventSource* EventSource::create(ExecutionContext* context, const String& url, c
onst EventSourceInit& eventSourceInit, ExceptionState& exceptionState) |
| 79 { | 78 { |
| 80 if (url.isEmpty()) { | 79 if (url.isEmpty()) { |
| 81 exceptionState.throwDOMException(SyntaxError, "Cannot open an EventSourc
e to an empty URL."); | 80 exceptionState.throwDOMException(SyntaxError, "Cannot open an EventSourc
e to an empty URL."); |
| 82 return nullptr; | 81 return nullptr; |
| 83 } | 82 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 98 EventSource* source = new EventSource(context, fullURL, eventSourceInit); | 97 EventSource* source = new EventSource(context, fullURL, eventSourceInit); |
| 99 | 98 |
| 100 source->scheduleInitialConnect(); | 99 source->scheduleInitialConnect(); |
| 101 source->suspendIfNeeded(); | 100 source->suspendIfNeeded(); |
| 102 return source; | 101 return source; |
| 103 } | 102 } |
| 104 | 103 |
| 105 EventSource::~EventSource() | 104 EventSource::~EventSource() |
| 106 { | 105 { |
| 107 ASSERT(m_state == CLOSED); | 106 ASSERT(m_state == CLOSED); |
| 108 ASSERT(!m_requestInFlight); | 107 ASSERT(!m_loader); |
| 109 } | 108 } |
| 110 | 109 |
| 111 void EventSource::scheduleInitialConnect() | 110 void EventSource::scheduleInitialConnect() |
| 112 { | 111 { |
| 113 ASSERT(m_state == CONNECTING); | 112 ASSERT(m_state == CONNECTING); |
| 114 ASSERT(!m_requestInFlight); | 113 ASSERT(!m_loader); |
| 115 | 114 |
| 116 m_connectTimer.startOneShot(0, BLINK_FROM_HERE); | 115 m_connectTimer.startOneShot(0, BLINK_FROM_HERE); |
| 117 } | 116 } |
| 118 | 117 |
| 119 void EventSource::connect() | 118 void EventSource::connect() |
| 120 { | 119 { |
| 121 ASSERT(m_state == CONNECTING); | 120 ASSERT(m_state == CONNECTING); |
| 122 ASSERT(!m_requestInFlight); | 121 ASSERT(!m_loader); |
| 123 ASSERT(executionContext()); | 122 ASSERT(executionContext()); |
| 124 | 123 |
| 125 ExecutionContext& executionContext = *this->executionContext(); | 124 ExecutionContext& executionContext = *this->executionContext(); |
| 126 ResourceRequest request(m_url); | 125 ResourceRequest request(m_url); |
| 127 request.setHTTPMethod(HTTPNames::GET); | 126 request.setHTTPMethod(HTTPNames::GET); |
| 128 request.setHTTPHeaderField(HTTPNames::Accept, "text/event-stream"); | 127 request.setHTTPHeaderField(HTTPNames::Accept, "text/event-stream"); |
| 129 request.setHTTPHeaderField(HTTPNames::Cache_Control, "no-cache"); | 128 request.setHTTPHeaderField(HTTPNames::Cache_Control, "no-cache"); |
| 130 request.setRequestContext(WebURLRequest::RequestContextEventSource); | 129 request.setRequestContext(WebURLRequest::RequestContextEventSource); |
| 131 if (!m_lastEventId.isEmpty()) { | 130 if (!m_lastEventId.isEmpty()) { |
| 132 // 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 10 matching lines...) Expand all Loading... |
| 143 options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypa
ssMainWorld(&executionContext) ? DoNotEnforceContentSecurityPolicy : EnforceConn
ectSrcDirective; | 142 options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypa
ssMainWorld(&executionContext) ? DoNotEnforceContentSecurityPolicy : EnforceConn
ectSrcDirective; |
| 144 | 143 |
| 145 ResourceLoaderOptions resourceLoaderOptions; | 144 ResourceLoaderOptions resourceLoaderOptions; |
| 146 resourceLoaderOptions.allowCredentials = (origin->canRequestNoSuborigin(m_ur
l) || m_withCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials; | 145 resourceLoaderOptions.allowCredentials = (origin->canRequestNoSuborigin(m_ur
l) || m_withCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials; |
| 147 resourceLoaderOptions.credentialsRequested = m_withCredentials ? ClientReque
stedCredentials : ClientDidNotRequestCredentials; | 146 resourceLoaderOptions.credentialsRequested = m_withCredentials ? ClientReque
stedCredentials : ClientDidNotRequestCredentials; |
| 148 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; | 147 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; |
| 149 resourceLoaderOptions.securityOrigin = origin; | 148 resourceLoaderOptions.securityOrigin = origin; |
| 150 | 149 |
| 151 InspectorInstrumentation::willSendEventSourceRequest(&executionContext, this
); | 150 InspectorInstrumentation::willSendEventSourceRequest(&executionContext, this
); |
| 152 // InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient
will be called synchronously. | 151 // InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient
will be called synchronously. |
| 153 m_loader = ThreadableLoader::create(executionContext, this, request, options
, resourceLoaderOptions); | 152 m_loader = ThreadableLoader::create(executionContext, this, options, resourc
eLoaderOptions); |
| 154 | 153 m_loader->start(request); |
| 155 if (m_loader) | |
| 156 m_requestInFlight = true; | |
| 157 } | 154 } |
| 158 | 155 |
| 159 void EventSource::networkRequestEnded() | 156 void EventSource::networkRequestEnded() |
| 160 { | 157 { |
| 161 if (!m_requestInFlight) | |
| 162 return; | |
| 163 | |
| 164 InspectorInstrumentation::didFinishEventSourceRequest(executionContext(), th
is); | 158 InspectorInstrumentation::didFinishEventSourceRequest(executionContext(), th
is); |
| 165 | 159 |
| 166 m_requestInFlight = false; | 160 m_loader = nullptr; |
| 167 | 161 |
| 168 if (m_state != CLOSED) | 162 if (m_state != CLOSED) |
| 169 scheduleReconnect(); | 163 scheduleReconnect(); |
| 170 } | 164 } |
| 171 | 165 |
| 172 void EventSource::scheduleReconnect() | 166 void EventSource::scheduleReconnect() |
| 173 { | 167 { |
| 174 m_state = CONNECTING; | 168 m_state = CONNECTING; |
| 175 m_connectTimer.startOneShot(m_reconnectDelay / 1000.0, BLINK_FROM_HERE); | 169 m_connectTimer.startOneShot(m_reconnectDelay / 1000.0, BLINK_FROM_HERE); |
| 176 dispatchEvent(Event::create(EventTypeNames::error)); | 170 dispatchEvent(Event::create(EventTypeNames::error)); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 192 } | 186 } |
| 193 | 187 |
| 194 EventSource::State EventSource::readyState() const | 188 EventSource::State EventSource::readyState() const |
| 195 { | 189 { |
| 196 return m_state; | 190 return m_state; |
| 197 } | 191 } |
| 198 | 192 |
| 199 void EventSource::close() | 193 void EventSource::close() |
| 200 { | 194 { |
| 201 if (m_state == CLOSED) { | 195 if (m_state == CLOSED) { |
| 202 ASSERT(!m_requestInFlight); | 196 ASSERT(!m_loader); |
| 203 return; | 197 return; |
| 204 } | 198 } |
| 205 | 199 |
| 206 // Stop trying to reconnect if EventSource was explicitly closed or if Activ
eDOMObject::stop() was called. | 200 // Stop trying to reconnect if EventSource was explicitly closed or if Activ
eDOMObject::stop() was called. |
| 207 if (m_connectTimer.isActive()) { | 201 if (m_connectTimer.isActive()) { |
| 208 m_connectTimer.stop(); | 202 m_connectTimer.stop(); |
| 209 } | 203 } |
| 210 | 204 |
| 211 if (m_requestInFlight) | 205 if (m_loader) { |
| 212 m_loader->cancel(); | 206 m_loader->cancel(); |
| 207 m_loader = nullptr; |
| 208 } |
| 213 | 209 |
| 214 m_state = CLOSED; | 210 m_state = CLOSED; |
| 215 } | 211 } |
| 216 | 212 |
| 217 const AtomicString& EventSource::interfaceName() const | 213 const AtomicString& EventSource::interfaceName() const |
| 218 { | 214 { |
| 219 return EventTargetNames::EventSource; | 215 return EventTargetNames::EventSource; |
| 220 } | 216 } |
| 221 | 217 |
| 222 ExecutionContext* EventSource::executionContext() const | 218 ExecutionContext* EventSource::executionContext() const |
| 223 { | 219 { |
| 224 return ActiveDOMObject::executionContext(); | 220 return ActiveDOMObject::executionContext(); |
| 225 } | 221 } |
| 226 | 222 |
| 227 void EventSource::didReceiveResponse(unsigned long, const ResourceResponse& resp
onse, PassOwnPtr<WebDataConsumerHandle> handle) | 223 void EventSource::didReceiveResponse(unsigned long, const ResourceResponse& resp
onse, PassOwnPtr<WebDataConsumerHandle> handle) |
| 228 { | 224 { |
| 229 ASSERT_UNUSED(handle, !handle); | 225 ASSERT_UNUSED(handle, !handle); |
| 230 ASSERT(m_state == CONNECTING); | 226 ASSERT(m_state == CONNECTING); |
| 231 ASSERT(m_requestInFlight); | 227 ASSERT(m_loader); |
| 232 | 228 |
| 233 m_eventStreamOrigin = SecurityOrigin::create(response.url())->toString(); | 229 m_eventStreamOrigin = SecurityOrigin::create(response.url())->toString(); |
| 234 int statusCode = response.httpStatusCode(); | 230 int statusCode = response.httpStatusCode(); |
| 235 bool mimeTypeIsValid = response.mimeType() == "text/event-stream"; | 231 bool mimeTypeIsValid = response.mimeType() == "text/event-stream"; |
| 236 bool responseIsValid = statusCode == 200 && mimeTypeIsValid; | 232 bool responseIsValid = statusCode == 200 && mimeTypeIsValid; |
| 237 if (responseIsValid) { | 233 if (responseIsValid) { |
| 238 const String& charset = response.textEncodingName(); | 234 const String& charset = response.textEncodingName(); |
| 239 // If we have a charset, the only allowed value is UTF-8 (case-insensiti
ve). | 235 // If we have a charset, the only allowed value is UTF-8 (case-insensiti
ve). |
| 240 responseIsValid = charset.isEmpty() || equalIgnoringCase(charset, "UTF-8
"); | 236 responseIsValid = charset.isEmpty() || equalIgnoringCase(charset, "UTF-8
"); |
| 241 if (!responseIsValid) { | 237 if (!responseIsValid) { |
| (...skipping 21 matching lines...) Expand all Loading... |
| 263 dispatchEvent(Event::create(EventTypeNames::open)); | 259 dispatchEvent(Event::create(EventTypeNames::open)); |
| 264 } else { | 260 } else { |
| 265 m_loader->cancel(); | 261 m_loader->cancel(); |
| 266 dispatchEvent(Event::create(EventTypeNames::error)); | 262 dispatchEvent(Event::create(EventTypeNames::error)); |
| 267 } | 263 } |
| 268 } | 264 } |
| 269 | 265 |
| 270 void EventSource::didReceiveData(const char* data, unsigned length) | 266 void EventSource::didReceiveData(const char* data, unsigned length) |
| 271 { | 267 { |
| 272 ASSERT(m_state == OPEN); | 268 ASSERT(m_state == OPEN); |
| 273 ASSERT(m_requestInFlight); | 269 ASSERT(m_loader); |
| 274 | 270 |
| 275 append(m_receiveBuf, m_decoder->decode(data, length)); | 271 append(m_receiveBuf, m_decoder->decode(data, length)); |
| 276 parseEventStream(); | 272 parseEventStream(); |
| 277 } | 273 } |
| 278 | 274 |
| 279 void EventSource::didFinishLoading(unsigned long, double) | 275 void EventSource::didFinishLoading(unsigned long, double) |
| 280 { | 276 { |
| 281 ASSERT(m_state == OPEN); | 277 ASSERT(m_state == OPEN); |
| 282 ASSERT(m_requestInFlight); | 278 ASSERT(m_loader); |
| 283 | 279 |
| 284 if (m_receiveBuf.size() > 0 || m_data.size() > 0) { | 280 if (m_receiveBuf.size() > 0 || m_data.size() > 0) { |
| 285 parseEventStream(); | 281 parseEventStream(); |
| 286 | 282 |
| 287 // Discard everything that has not been dispatched by now. | 283 // Discard everything that has not been dispatched by now. |
| 288 m_receiveBuf.clear(); | 284 m_receiveBuf.clear(); |
| 289 m_data.clear(); | 285 m_data.clear(); |
| 290 m_eventName = emptyAtom; | 286 m_eventName = emptyAtom; |
| 291 m_currentlyParsedEventId = nullAtom; | 287 m_currentlyParsedEventId = nullAtom; |
| 292 } | 288 } |
| 293 networkRequestEnded(); | 289 networkRequestEnded(); |
| 294 } | 290 } |
| 295 | 291 |
| 296 void EventSource::didFail(const ResourceError& error) | 292 void EventSource::didFail(const ResourceError& error) |
| 297 { | 293 { |
| 298 ASSERT(m_state != CLOSED); | 294 ASSERT(m_state != CLOSED); |
| 299 ASSERT(m_requestInFlight); | 295 ASSERT(m_loader); |
| 300 | 296 |
| 301 if (error.isCancellation()) | 297 if (error.isCancellation()) |
| 302 m_state = CLOSED; | 298 m_state = CLOSED; |
| 303 networkRequestEnded(); | 299 networkRequestEnded(); |
| 304 } | 300 } |
| 305 | 301 |
| 306 void EventSource::didFailAccessControlCheck(const ResourceError& error) | 302 void EventSource::didFailAccessControlCheck(const ResourceError& error) |
| 307 { | 303 { |
| 304 ASSERT(m_loader); |
| 305 |
| 308 String message = "EventSource cannot load " + error.failingURL() + ". " + er
ror.localizedDescription(); | 306 String message = "EventSource cannot load " + error.failingURL() + ". " + er
ror.localizedDescription(); |
| 309 executionContext()->addConsoleMessage(ConsoleMessage::create(JSMessageSource
, ErrorMessageLevel, message)); | 307 executionContext()->addConsoleMessage(ConsoleMessage::create(JSMessageSource
, ErrorMessageLevel, message)); |
| 310 | 308 |
| 311 abortConnectionAttempt(); | 309 abortConnectionAttempt(); |
| 312 } | 310 } |
| 313 | 311 |
| 314 void EventSource::didFailRedirectCheck() | 312 void EventSource::didFailRedirectCheck() |
| 315 { | 313 { |
| 314 ASSERT(m_loader); |
| 315 |
| 316 abortConnectionAttempt(); | 316 abortConnectionAttempt(); |
| 317 } | 317 } |
| 318 | 318 |
| 319 void EventSource::abortConnectionAttempt() | 319 void EventSource::abortConnectionAttempt() |
| 320 { | 320 { |
| 321 ASSERT(m_state == CONNECTING); | 321 ASSERT(m_state == CONNECTING); |
| 322 | 322 |
| 323 m_loader = nullptr; | 323 m_loader = nullptr; |
| 324 m_state = CLOSED; | 324 m_state = CLOSED; |
| 325 networkRequestEnded(); | 325 networkRequestEnded(); |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 422 if (ok) | 422 if (ok) |
| 423 m_reconnectDelay = retry; | 423 m_reconnectDelay = retry; |
| 424 } | 424 } |
| 425 } | 425 } |
| 426 } | 426 } |
| 427 } | 427 } |
| 428 | 428 |
| 429 void EventSource::stop() | 429 void EventSource::stop() |
| 430 { | 430 { |
| 431 close(); | 431 close(); |
| 432 | |
| 433 // (Non)Oilpan: In order to make Worker shutdowns clean, | |
| 434 // deref the loader. This will in turn deref its | |
| 435 // RefPtr<WorkerGlobalScope>. | |
| 436 // | |
| 437 // Worth doing regardless, it is no longer of use. | |
| 438 m_loader = nullptr; | |
| 439 } | 432 } |
| 440 | 433 |
| 441 bool EventSource::hasPendingActivity() const | 434 bool EventSource::hasPendingActivity() const |
| 442 { | 435 { |
| 443 return m_state != CLOSED; | 436 return m_state != CLOSED; |
| 444 } | 437 } |
| 445 | 438 |
| 446 PassRefPtrWillBeRawPtr<MessageEvent> EventSource::createMessageEvent() | 439 PassRefPtrWillBeRawPtr<MessageEvent> EventSource::createMessageEvent() |
| 447 { | 440 { |
| 448 RefPtrWillBeRawPtr<MessageEvent> event = MessageEvent::create(); | 441 RefPtrWillBeRawPtr<MessageEvent> event = MessageEvent::create(); |
| 449 event->initMessageEvent(m_eventName.isEmpty() ? EventTypeNames::message : m_
eventName, false, false, SerializedScriptValueFactory::instance().create(String(
m_data)), m_eventStreamOrigin, m_lastEventId, 0, nullptr); | 442 event->initMessageEvent(m_eventName.isEmpty() ? EventTypeNames::message : m_
eventName, false, false, SerializedScriptValueFactory::instance().create(String(
m_data)), m_eventStreamOrigin, m_lastEventId, 0, nullptr); |
| 450 m_data.clear(); | 443 m_data.clear(); |
| 451 return event.release(); | 444 return event.release(); |
| 452 } | 445 } |
| 453 | 446 |
| 454 DEFINE_TRACE(EventSource) | 447 DEFINE_TRACE(EventSource) |
| 455 { | 448 { |
| 456 RefCountedGarbageCollectedEventTargetWithInlineData::trace(visitor); | 449 RefCountedGarbageCollectedEventTargetWithInlineData::trace(visitor); |
| 457 ActiveDOMObject::trace(visitor); | 450 ActiveDOMObject::trace(visitor); |
| 458 } | 451 } |
| 459 | 452 |
| 460 } // namespace blink | 453 } // namespace blink |
| OLD | NEW |