1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 ;*; */
2 /* vim: set sw=2 ts=8 et 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 #include "nsAutoPtr.h"
8 #include "nsIObserverService.h"
9 #include "nsIUUIDGenerator.h"
10 #include "nsServiceManagerUtils.h"
11 #include "nsThreadUtils.h"
12 #include "RequestContextService.h"
13 
14 #include "mozilla/Atomics.h"
15 #include "mozilla/Services.h"
16 
17 #include "mozilla/net/PSpdyPush.h"
18 
19 namespace mozilla {
20 namespace net {
21 
22 // nsIRequestContext
23 class RequestContext final : public nsIRequestContext
24 {
25 public:
26   NS_DECL_THREADSAFE_ISUPPORTS
27   NS_DECL_NSIREQUESTCONTEXT
28 
29   explicit RequestContext(const nsID& id);
30 private:
31   virtual ~RequestContext();
32 
33   nsID mID;
34   char mCID[NSID_LENGTH];
35   Atomic<uint32_t>       mBlockingTransactionCount;
36   nsAutoPtr<SpdyPushCache> mSpdyCache;
37   nsCString mUserAgentOverride;
38 };
39 
NS_IMPL_ISUPPORTS(RequestContext,nsIRequestContext)40 NS_IMPL_ISUPPORTS(RequestContext, nsIRequestContext)
41 
42 RequestContext::RequestContext(const nsID& aID)
43   : mBlockingTransactionCount(0)
44 {
45   mID = aID;
46   mID.ToProvidedString(mCID);
47 }
48 
~RequestContext()49 RequestContext::~RequestContext()
50 {
51 }
52 
53 NS_IMETHODIMP
GetBlockingTransactionCount(uint32_t * aBlockingTransactionCount)54 RequestContext::GetBlockingTransactionCount(uint32_t *aBlockingTransactionCount)
55 {
56   NS_ENSURE_ARG_POINTER(aBlockingTransactionCount);
57   *aBlockingTransactionCount = mBlockingTransactionCount;
58   return NS_OK;
59 }
60 
61 NS_IMETHODIMP
AddBlockingTransaction()62 RequestContext::AddBlockingTransaction()
63 {
64   mBlockingTransactionCount++;
65   return NS_OK;
66 }
67 
68 NS_IMETHODIMP
RemoveBlockingTransaction(uint32_t * outval)69 RequestContext::RemoveBlockingTransaction(uint32_t *outval)
70 {
71   NS_ENSURE_ARG_POINTER(outval);
72   mBlockingTransactionCount--;
73   *outval = mBlockingTransactionCount;
74   return NS_OK;
75 }
76 
77 NS_IMETHODIMP
GetSpdyPushCache(mozilla::net::SpdyPushCache ** aSpdyPushCache)78 RequestContext::GetSpdyPushCache(mozilla::net::SpdyPushCache **aSpdyPushCache)
79 {
80   *aSpdyPushCache = mSpdyCache.get();
81   return NS_OK;
82 }
83 
84 NS_IMETHODIMP
SetSpdyPushCache(mozilla::net::SpdyPushCache * aSpdyPushCache)85 RequestContext::SetSpdyPushCache(mozilla::net::SpdyPushCache *aSpdyPushCache)
86 {
87   mSpdyCache = aSpdyPushCache;
88   return NS_OK;
89 }
90 
91 NS_IMETHODIMP
GetID(nsID * outval)92 RequestContext::GetID(nsID *outval)
93 {
94   NS_ENSURE_ARG_POINTER(outval);
95   *outval = mID;
96   return NS_OK;
97 }
98 
99 NS_IMETHODIMP
GetUserAgentOverride(nsACString & aUserAgentOverride)100 RequestContext::GetUserAgentOverride(nsACString& aUserAgentOverride)
101 {
102   aUserAgentOverride = mUserAgentOverride;
103   return NS_OK;
104 }
105 
106 NS_IMETHODIMP
SetUserAgentOverride(const nsACString & aUserAgentOverride)107 RequestContext::SetUserAgentOverride(const nsACString& aUserAgentOverride)
108 {
109   mUserAgentOverride = aUserAgentOverride;
110   return NS_OK;
111 }
112 
113 
114 //nsIRequestContextService
115 RequestContextService *RequestContextService::sSelf = nullptr;
116 
NS_IMPL_ISUPPORTS(RequestContextService,nsIRequestContextService,nsIObserver)117 NS_IMPL_ISUPPORTS(RequestContextService, nsIRequestContextService, nsIObserver)
118 
119 RequestContextService::RequestContextService()
120 {
121   MOZ_ASSERT(!sSelf, "multiple rcs instances!");
122   MOZ_ASSERT(NS_IsMainThread());
123   sSelf = this;
124 }
125 
~RequestContextService()126 RequestContextService::~RequestContextService()
127 {
128   MOZ_ASSERT(NS_IsMainThread());
129   Shutdown();
130   sSelf = nullptr;
131 }
132 
133 nsresult
Init()134 RequestContextService::Init()
135 {
136   MOZ_ASSERT(NS_IsMainThread());
137   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
138   if (!obs) {
139     return NS_ERROR_NOT_AVAILABLE;
140   }
141 
142   return obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
143 }
144 
145 void
Shutdown()146 RequestContextService::Shutdown()
147 {
148   MOZ_ASSERT(NS_IsMainThread());
149   mTable.Clear();
150 }
151 
152 /* static */ nsresult
Create(nsISupports * aOuter,const nsIID & aIID,void ** aResult)153 RequestContextService::Create(nsISupports *aOuter, const nsIID& aIID, void **aResult)
154 {
155   MOZ_ASSERT(NS_IsMainThread());
156   if (aOuter != nullptr) {
157     return NS_ERROR_NO_AGGREGATION;
158   }
159 
160   RefPtr<RequestContextService> svc = new RequestContextService();
161   nsresult rv = svc->Init();
162   NS_ENSURE_SUCCESS(rv, rv);
163 
164   return svc->QueryInterface(aIID, aResult);
165 }
166 
167 NS_IMETHODIMP
GetRequestContext(const nsID & rcID,nsIRequestContext ** rc)168 RequestContextService::GetRequestContext(const nsID& rcID, nsIRequestContext **rc)
169 {
170   MOZ_ASSERT(NS_IsMainThread());
171   NS_ENSURE_ARG_POINTER(rc);
172   *rc = nullptr;
173 
174   if (!mTable.Get(rcID, rc)) {
175     nsCOMPtr<nsIRequestContext> newSC = new RequestContext(rcID);
176     mTable.Put(rcID, newSC);
177     newSC.swap(*rc);
178   }
179 
180   return NS_OK;
181 }
182 
183 NS_IMETHODIMP
NewRequestContextID(nsID * rcID)184 RequestContextService::NewRequestContextID(nsID *rcID)
185 {
186   MOZ_ASSERT(NS_IsMainThread());
187   if (!mUUIDGen) {
188     nsresult rv;
189     mUUIDGen = do_GetService("@mozilla.org/uuid-generator;1", &rv);
190     NS_ENSURE_SUCCESS(rv, rv);
191   }
192 
193   return mUUIDGen->GenerateUUIDInPlace(rcID);
194 }
195 
196 NS_IMETHODIMP
RemoveRequestContext(const nsID & rcID)197 RequestContextService::RemoveRequestContext(const nsID& rcID)
198 {
199   MOZ_ASSERT(NS_IsMainThread());
200   mTable.Remove(rcID);
201   return NS_OK;
202 }
203 
204 NS_IMETHODIMP
Observe(nsISupports * subject,const char * topic,const char16_t * data_unicode)205 RequestContextService::Observe(nsISupports *subject, const char *topic,
206                                   const char16_t *data_unicode)
207 {
208   MOZ_ASSERT(NS_IsMainThread());
209   if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, topic)) {
210     Shutdown();
211   }
212 
213   return NS_OK;
214 }
215 
216 } // ::mozilla::net
217 } // ::mozilla
218