1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_dom_Geolocation_h
8 #define mozilla_dom_Geolocation_h
9 
10 // Microsoft's API Name hackery sucks
11 #undef CreateEvent
12 
13 #include "mozilla/StaticPtr.h"
14 #include "nsCOMPtr.h"
15 #include "nsTArray.h"
16 #include "nsITimer.h"
17 #include "nsIObserver.h"
18 #include "nsIWeakReferenceUtils.h"
19 #include "nsWrapperCache.h"
20 
21 #include "nsCycleCollectionParticipant.h"
22 
23 #include "GeolocationPosition.h"
24 #include "GeolocationCoordinates.h"
25 #include "nsIDOMGeoPosition.h"
26 #include "nsIDOMGeoPositionCallback.h"
27 #include "nsIDOMGeoPositionErrorCallback.h"
28 #include "mozilla/dom/BindingDeclarations.h"
29 #include "mozilla/dom/GeolocationBinding.h"
30 #include "mozilla/dom/CallbackObject.h"
31 
32 #include "nsIGeolocationProvider.h"
33 #include "mozilla/Attributes.h"
34 
35 class nsGeolocationService;
36 class nsGeolocationRequest;
37 
38 namespace mozilla {
39 namespace dom {
40 class Geolocation;
41 using GeoPositionCallback =
42     CallbackObjectHolder<PositionCallback, nsIDOMGeoPositionCallback>;
43 using GeoPositionErrorCallback =
44     CallbackObjectHolder<PositionErrorCallback, nsIDOMGeoPositionErrorCallback>;
45 }  // namespace dom
46 }  // namespace mozilla
47 
48 struct CachedPositionAndAccuracy {
49   nsCOMPtr<nsIDOMGeoPosition> position;
50   bool isHighAccuracy;
51 };
52 
53 /**
54  * Singleton that manages the geolocation provider
55  */
56 class nsGeolocationService final : public nsIGeolocationUpdate,
57                                    public nsIObserver {
58  public:
59   static already_AddRefed<nsGeolocationService> GetGeolocationService();
60   static mozilla::StaticRefPtr<nsGeolocationService> sService;
61 
62   NS_DECL_THREADSAFE_ISUPPORTS
63   NS_DECL_NSIGEOLOCATIONUPDATE
64   NS_DECL_NSIOBSERVER
65 
nsGeolocationService()66   nsGeolocationService() { mHigherAccuracy = false; }
67 
68   nsresult Init();
69 
70   // Management of the Geolocation objects
71   void AddLocator(mozilla::dom::Geolocation* locator);
72   void RemoveLocator(mozilla::dom::Geolocation* locator);
73 
74   void SetCachedPosition(nsIDOMGeoPosition* aPosition);
75   CachedPositionAndAccuracy GetCachedPosition();
76 
77   // Find and startup a geolocation device (gps, nmea, etc.)
78   MOZ_CAN_RUN_SCRIPT
79   nsresult StartDevice(nsIPrincipal* aPrincipal);
80 
81   // Stop the started geolocation device (gps, nmea, etc.)
82   void StopDevice();
83 
84   // create, or reinitalize the callback timer
85   void SetDisconnectTimer();
86 
87   // Update the accuracy and notify the provider if changed
88   void UpdateAccuracy(bool aForceHigh = false);
89   bool HighAccuracyRequested();
90 
91  private:
92   ~nsGeolocationService();
93 
94   // Disconnect timer.  When this timer expires, it clears all pending callbacks
95   // and closes down the provider, unless we are watching a point, and in that
96   // case, we disable the disconnect timer.
97   nsCOMPtr<nsITimer> mDisconnectTimer;
98 
99   // The object providing geo location information to us.
100   nsCOMPtr<nsIGeolocationProvider> mProvider;
101 
102   // mGeolocators are not owned here.  Their constructor
103   // adds them to this list, and their destructor removes
104   // them from this list.
105   nsTArray<mozilla::dom::Geolocation*> mGeolocators;
106 
107   // This is the last geo position that we have seen.
108   CachedPositionAndAccuracy mLastPosition;
109 
110   // Current state of requests for higher accuracy
111   bool mHigherAccuracy;
112 };
113 
114 namespace mozilla {
115 namespace dom {
116 
117 /**
118  * Can return a geolocation info
119  */
120 class Geolocation final : public nsIGeolocationUpdate, public nsWrapperCache {
121  public:
122   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
123   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Geolocation)
124 
125   NS_DECL_NSIGEOLOCATIONUPDATE
126 
127   Geolocation();
128 
129   nsresult Init(nsPIDOMWindowInner* aContentDom = nullptr);
130 
131   nsPIDOMWindowInner* GetParentObject() const;
132   virtual JSObject* WrapObject(JSContext* aCtx,
133                                JS::Handle<JSObject*> aGivenProto) override;
134 
135   MOZ_CAN_RUN_SCRIPT
136   int32_t WatchPosition(PositionCallback& aCallback,
137                         PositionErrorCallback* aErrorCallback,
138                         const PositionOptions& aOptions, CallerType aCallerType,
139                         ErrorResult& aRv);
140 
141   MOZ_CAN_RUN_SCRIPT
142   void GetCurrentPosition(PositionCallback& aCallback,
143                           PositionErrorCallback* aErrorCallback,
144                           const PositionOptions& aOptions,
145                           CallerType aCallerType, ErrorResult& aRv);
146   void ClearWatch(int32_t aWatchId);
147 
148   // A WatchPosition for C++ use. Returns 0 if we failed to actually watch.
149   MOZ_CAN_RUN_SCRIPT
150   int32_t WatchPosition(nsIDOMGeoPositionCallback* aCallback,
151                         nsIDOMGeoPositionErrorCallback* aErrorCallback,
152                         UniquePtr<PositionOptions>&& aOptions);
153 
154   // Returns true if any of the callbacks are repeating
155   bool HasActiveCallbacks();
156 
157   // Register an allowed request
158   void NotifyAllowedRequest(nsGeolocationRequest* aRequest);
159 
160   // Remove request from all callbacks arrays
161   void RemoveRequest(nsGeolocationRequest* request);
162 
163   // Check if there is already ClearWatch called for current
164   // request & clear if yes
165   bool ClearPendingRequest(nsGeolocationRequest* aRequest);
166 
167   // Shutting down.
168   void Shutdown();
169 
170   // Getter for the principal that this Geolocation was loaded from
GetPrincipal()171   nsIPrincipal* GetPrincipal() { return mPrincipal; }
172 
173   // Getter for the window that this Geolocation is owned by
GetOwner()174   nsIWeakReference* GetOwner() { return mOwner; }
175 
176   // Check to see if the window still exists
177   bool WindowOwnerStillExists();
178 
179   // Check to see if any active request requires high accuracy
180   bool HighAccuracyRequested();
181 
182   // Get the singleton non-window Geolocation instance.  This never returns
183   // null.
184   static already_AddRefed<Geolocation> NonWindowSingleton();
185 
186  private:
187   ~Geolocation();
188 
189   MOZ_CAN_RUN_SCRIPT
190   nsresult GetCurrentPosition(GeoPositionCallback aCallback,
191                               GeoPositionErrorCallback aErrorCallback,
192                               UniquePtr<PositionOptions>&& aOptions,
193                               CallerType aCallerType);
194 
195   MOZ_CAN_RUN_SCRIPT
196   int32_t WatchPosition(GeoPositionCallback aCallback,
197                         GeoPositionErrorCallback aErrorCallback,
198                         UniquePtr<PositionOptions>&& aOptions,
199                         CallerType aCallerType, ErrorResult& aRv);
200 
201   bool RegisterRequestWithPrompt(nsGeolocationRequest* request);
202 
203   // Check if clearWatch is already called
204   bool IsAlreadyCleared(nsGeolocationRequest* aRequest);
205 
206   // Returns whether the Geolocation object should block requests
207   // within a context that is not secure.
208   bool ShouldBlockInsecureRequests() const;
209 
210   // Checks if the request is in a content window that is fully active, or the
211   // request is coming from a chrome window.
212   bool IsFullyActiveOrChrome();
213 
214   // Two callback arrays.  The first |mPendingCallbacks| holds objects for only
215   // one callback and then they are released/removed from the array.  The second
216   // |mWatchingCallbacks| holds objects until the object is explictly removed or
217   // there is a page change. All requests held by either array are active, that
218   // is, they have been allowed and expect to be fulfilled.
219 
220   nsTArray<RefPtr<nsGeolocationRequest> > mPendingCallbacks;
221   nsTArray<RefPtr<nsGeolocationRequest> > mWatchingCallbacks;
222 
223   // window that this was created for.  Weak reference.
224   nsWeakPtr mOwner;
225 
226   // where the content was loaded from
227   nsCOMPtr<nsIPrincipal> mPrincipal;
228 
229   // the protocols we want to measure
230   enum class ProtocolType : uint8_t { OTHER, HTTP, HTTPS };
231 
232   // the protocol used to load the content
233   ProtocolType mProtocolType;
234 
235   // owning back pointer.
236   RefPtr<nsGeolocationService> mService;
237 
238   // Watch ID
239   uint32_t mLastWatchId;
240 
241   // Pending requests are used when the service is not ready
242   nsTArray<RefPtr<nsGeolocationRequest> > mPendingRequests;
243 
244   // Array containing already cleared watch IDs
245   nsTArray<int32_t> mClearedWatchIDs;
246 
247   // Our cached non-window singleton.
248   static mozilla::StaticRefPtr<Geolocation> sNonWindowSingleton;
249 };
250 
251 }  // namespace dom
252 }  // namespace mozilla
253 
254 #endif /* mozilla_dom_Geolocation_h */
255