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