1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/base/src/EventSource.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,272 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * This implementation has support only for http requests. It is because the 1.11 + * spec has defined event streams only for http. HTTP is required because 1.12 + * this implementation uses some http headers: "Last-Event-ID", "Cache-Control" 1.13 + * and "Accept". 1.14 + */ 1.15 + 1.16 +#ifndef mozilla_dom_EventSource_h 1.17 +#define mozilla_dom_EventSource_h 1.18 + 1.19 +#include "mozilla/Attributes.h" 1.20 +#include "mozilla/DOMEventTargetHelper.h" 1.21 +#include "nsIObserver.h" 1.22 +#include "nsIStreamListener.h" 1.23 +#include "nsIChannelEventSink.h" 1.24 +#include "nsIInterfaceRequestor.h" 1.25 +#include "nsITimer.h" 1.26 +#include "nsIHttpChannel.h" 1.27 +#include "nsWeakReference.h" 1.28 +#include "nsDeque.h" 1.29 +#include "nsIUnicodeDecoder.h" 1.30 + 1.31 +class nsPIDOMWindow; 1.32 + 1.33 +namespace mozilla { 1.34 + 1.35 +class ErrorResult; 1.36 + 1.37 +namespace dom { 1.38 + 1.39 +class AsyncVerifyRedirectCallbackFwr; 1.40 +struct EventSourceInit; 1.41 + 1.42 +class EventSource : public DOMEventTargetHelper 1.43 + , public nsIObserver 1.44 + , public nsIStreamListener 1.45 + , public nsIChannelEventSink 1.46 + , public nsIInterfaceRequestor 1.47 + , public nsSupportsWeakReference 1.48 +{ 1.49 +friend class AsyncVerifyRedirectCallbackFwr; 1.50 + 1.51 +public: 1.52 + EventSource(nsPIDOMWindow* aOwnerWindow); 1.53 + virtual ~EventSource(); 1.54 + NS_DECL_ISUPPORTS_INHERITED 1.55 + NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS_INHERITED( 1.56 + EventSource, DOMEventTargetHelper) 1.57 + 1.58 + NS_DECL_NSIOBSERVER 1.59 + NS_DECL_NSISTREAMLISTENER 1.60 + NS_DECL_NSIREQUESTOBSERVER 1.61 + NS_DECL_NSICHANNELEVENTSINK 1.62 + NS_DECL_NSIINTERFACEREQUESTOR 1.63 + 1.64 + // nsWrapperCache 1.65 + virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; 1.66 + 1.67 + // WebIDL 1.68 + nsPIDOMWindow* 1.69 + GetParentObject() const 1.70 + { 1.71 + return GetOwner(); 1.72 + } 1.73 + static already_AddRefed<EventSource> 1.74 + Constructor(const GlobalObject& aGlobal, const nsAString& aURL, 1.75 + const EventSourceInit& aEventSourceInitDict, 1.76 + ErrorResult& aRv); 1.77 + 1.78 + void GetUrl(nsAString& aURL) const 1.79 + { 1.80 + aURL = mOriginalURL; 1.81 + } 1.82 + bool WithCredentials() const 1.83 + { 1.84 + return mWithCredentials; 1.85 + } 1.86 + 1.87 + enum { 1.88 + CONNECTING = 0U, 1.89 + OPEN = 1U, 1.90 + CLOSED = 2U 1.91 + }; 1.92 + uint16_t ReadyState() const 1.93 + { 1.94 + return mReadyState; 1.95 + } 1.96 + 1.97 + IMPL_EVENT_HANDLER(open) 1.98 + IMPL_EVENT_HANDLER(message) 1.99 + IMPL_EVENT_HANDLER(error) 1.100 + void Close(); 1.101 + 1.102 + // Determine if preferences allow EventSource 1.103 + static bool PrefEnabled(JSContext* aCx = nullptr, JSObject* aGlobal = nullptr); 1.104 + 1.105 + virtual void DisconnectFromOwner() MOZ_OVERRIDE; 1.106 + 1.107 +protected: 1.108 + nsresult Init(nsISupports* aOwner, 1.109 + const nsAString& aURL, 1.110 + bool aWithCredentials); 1.111 + 1.112 + nsresult GetBaseURI(nsIURI **aBaseURI); 1.113 + 1.114 + nsresult SetupHttpChannel(); 1.115 + nsresult InitChannelAndRequestEventSource(); 1.116 + nsresult ResetConnection(); 1.117 + nsresult DispatchFailConnection(); 1.118 + nsresult SetReconnectionTimeout(); 1.119 + 1.120 + void AnnounceConnection(); 1.121 + void DispatchAllMessageEvents(); 1.122 + void ReestablishConnection(); 1.123 + void FailConnection(); 1.124 + 1.125 + nsresult Thaw(); 1.126 + nsresult Freeze(); 1.127 + 1.128 + static void TimerCallback(nsITimer *aTimer, void *aClosure); 1.129 + 1.130 + nsresult PrintErrorOnConsole(const char *aBundleURI, 1.131 + const char16_t *aError, 1.132 + const char16_t **aFormatStrings, 1.133 + uint32_t aFormatStringsLen); 1.134 + nsresult ConsoleError(); 1.135 + 1.136 + static NS_METHOD StreamReaderFunc(nsIInputStream *aInputStream, 1.137 + void *aClosure, 1.138 + const char *aFromRawSegment, 1.139 + uint32_t aToOffset, 1.140 + uint32_t aCount, 1.141 + uint32_t *aWriteCount); 1.142 + nsresult SetFieldAndClear(); 1.143 + nsresult ClearFields(); 1.144 + nsresult ResetEvent(); 1.145 + nsresult DispatchCurrentMessageEvent(); 1.146 + nsresult ParseCharacter(char16_t aChr); 1.147 + bool CheckCanRequestSrc(nsIURI* aSrc = nullptr); // if null, it tests mSrc 1.148 + nsresult CheckHealthOfRequestCallback(nsIRequest *aRequestCallback); 1.149 + nsresult OnRedirectVerifyCallback(nsresult result); 1.150 + 1.151 + nsCOMPtr<nsIURI> mSrc; 1.152 + 1.153 + nsString mLastEventID; 1.154 + uint32_t mReconnectionTime; // in ms 1.155 + 1.156 + struct Message { 1.157 + nsString mEventName; 1.158 + nsString mLastEventID; 1.159 + nsString mData; 1.160 + }; 1.161 + nsDeque mMessagesToDispatch; 1.162 + Message mCurrentMessage; 1.163 + 1.164 + /** 1.165 + * A simple state machine used to manage the event-source's line buffer 1.166 + * 1.167 + * PARSE_STATE_OFF -> PARSE_STATE_BEGIN_OF_STREAM 1.168 + * 1.169 + * PARSE_STATE_BEGIN_OF_STREAM -> PARSE_STATE_BOM_WAS_READ | 1.170 + * PARSE_STATE_CR_CHAR | 1.171 + * PARSE_STATE_BEGIN_OF_LINE | 1.172 + * PARSE_STATE_COMMENT | 1.173 + * PARSE_STATE_FIELD_NAME 1.174 + * 1.175 + * PARSE_STATE_BOM_WAS_READ -> PARSE_STATE_CR_CHAR | 1.176 + * PARSE_STATE_BEGIN_OF_LINE | 1.177 + * PARSE_STATE_COMMENT | 1.178 + * PARSE_STATE_FIELD_NAME 1.179 + * 1.180 + * PARSE_STATE_CR_CHAR -> PARSE_STATE_CR_CHAR | 1.181 + * PARSE_STATE_COMMENT | 1.182 + * PARSE_STATE_FIELD_NAME | 1.183 + * PARSE_STATE_BEGIN_OF_LINE 1.184 + * 1.185 + * PARSE_STATE_COMMENT -> PARSE_STATE_CR_CHAR | 1.186 + * PARSE_STATE_BEGIN_OF_LINE 1.187 + * 1.188 + * PARSE_STATE_FIELD_NAME -> PARSE_STATE_CR_CHAR | 1.189 + * PARSE_STATE_BEGIN_OF_LINE | 1.190 + * PARSE_STATE_FIRST_CHAR_OF_FIELD_VALUE 1.191 + * 1.192 + * PARSE_STATE_FIRST_CHAR_OF_FIELD_VALUE -> PARSE_STATE_FIELD_VALUE | 1.193 + * PARSE_STATE_CR_CHAR | 1.194 + * PARSE_STATE_BEGIN_OF_LINE 1.195 + * 1.196 + * PARSE_STATE_FIELD_VALUE -> PARSE_STATE_CR_CHAR | 1.197 + * PARSE_STATE_BEGIN_OF_LINE 1.198 + * 1.199 + * PARSE_STATE_BEGIN_OF_LINE -> PARSE_STATE_CR_CHAR | 1.200 + * PARSE_STATE_COMMENT | 1.201 + * PARSE_STATE_FIELD_NAME | 1.202 + * PARSE_STATE_BEGIN_OF_LINE 1.203 + * 1.204 + * Whenever the parser find an empty line or the end-of-file 1.205 + * it dispatches the stacked event. 1.206 + * 1.207 + */ 1.208 + enum ParserStatus { 1.209 + PARSE_STATE_OFF, 1.210 + PARSE_STATE_BEGIN_OF_STREAM, 1.211 + PARSE_STATE_BOM_WAS_READ, 1.212 + PARSE_STATE_CR_CHAR, 1.213 + PARSE_STATE_COMMENT, 1.214 + PARSE_STATE_FIELD_NAME, 1.215 + PARSE_STATE_FIRST_CHAR_OF_FIELD_VALUE, 1.216 + PARSE_STATE_FIELD_VALUE, 1.217 + PARSE_STATE_BEGIN_OF_LINE 1.218 + }; 1.219 + ParserStatus mStatus; 1.220 + 1.221 + bool mFrozen; 1.222 + bool mErrorLoadOnRedirect; 1.223 + bool mGoingToDispatchAllMessages; 1.224 + bool mWithCredentials; 1.225 + bool mWaitingForOnStopRequest; 1.226 + bool mInterrupted; 1.227 + 1.228 + // used while reading the input streams 1.229 + nsCOMPtr<nsIUnicodeDecoder> mUnicodeDecoder; 1.230 + nsresult mLastConvertionResult; 1.231 + nsString mLastFieldName; 1.232 + nsString mLastFieldValue; 1.233 + 1.234 + nsCOMPtr<nsILoadGroup> mLoadGroup; 1.235 + 1.236 + /** 1.237 + * The notification callbacks the channel had initially. 1.238 + * We want to forward things here as needed. 1.239 + */ 1.240 + nsCOMPtr<nsIInterfaceRequestor> mNotificationCallbacks; 1.241 + nsCOMPtr<nsIChannelEventSink> mChannelEventSink; 1.242 + 1.243 + nsCOMPtr<nsIHttpChannel> mHttpChannel; 1.244 + 1.245 + nsCOMPtr<nsITimer> mTimer; 1.246 + 1.247 + uint16_t mReadyState; 1.248 + nsString mOriginalURL; 1.249 + 1.250 + nsCOMPtr<nsIPrincipal> mPrincipal; 1.251 + nsString mOrigin; 1.252 + 1.253 + uint32_t mRedirectFlags; 1.254 + nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback; 1.255 + nsCOMPtr<nsIChannel> mNewRedirectChannel; 1.256 + 1.257 + // Event Source owner information: 1.258 + // - the script file name 1.259 + // - source code line number where the Event Source object was constructed. 1.260 + // - the ID of the inner window where the script lives. Note that this may not 1.261 + // be the same as the Event Source owner window. 1.262 + // These attributes are used for error reporting. 1.263 + nsString mScriptFile; 1.264 + uint32_t mScriptLine; 1.265 + uint64_t mInnerWindowID; 1.266 + 1.267 +private: 1.268 + EventSource(const EventSource& x); // prevent bad usage 1.269 + EventSource& operator=(const EventSource& x); 1.270 +}; 1.271 + 1.272 +} // namespace dom 1.273 +} // namespace mozilla 1.274 + 1.275 +#endif // mozilla_dom_EventSource_h