netwerk/protocol/app/AppProtocolHandler.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim:set expandtab ts=2 sw=2 sts=2 cin: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "AppProtocolHandler.h"
michael@0 8 #include "nsBaseChannel.h"
michael@0 9 #include "nsJARChannel.h"
michael@0 10 #include "nsNetCID.h"
michael@0 11 #include "nsIAppsService.h"
michael@0 12 #include "nsCxPusher.h"
michael@0 13 #include "nsXULAppAPI.h"
michael@0 14
michael@0 15 /**
michael@0 16 * This dummy channel implementation only provides enough functionality
michael@0 17 * to return a fake 404 error when the caller asks for an app:// URL
michael@0 18 * containing an unknown appId.
michael@0 19 */
michael@0 20 class DummyChannel : public nsIJARChannel
michael@0 21 , nsRunnable
michael@0 22 {
michael@0 23 public:
michael@0 24 NS_DECL_ISUPPORTS
michael@0 25 NS_DECL_NSIREQUEST
michael@0 26 NS_DECL_NSICHANNEL
michael@0 27 NS_DECL_NSIJARCHANNEL
michael@0 28
michael@0 29 DummyChannel();
michael@0 30
michael@0 31 NS_IMETHODIMP Run();
michael@0 32
michael@0 33 private:
michael@0 34 bool mPending;
michael@0 35 uint32_t mSuspendCount;
michael@0 36 nsCOMPtr<nsISupports> mListenerContext;
michael@0 37 nsCOMPtr<nsIStreamListener> mListener;
michael@0 38 nsCOMPtr<nsILoadGroup> mLoadGroup;
michael@0 39 nsLoadFlags mLoadFlags;
michael@0 40 };
michael@0 41
michael@0 42 NS_IMPL_ISUPPORTS(DummyChannel, nsIRequest, nsIChannel, nsIJARChannel)
michael@0 43
michael@0 44 DummyChannel::DummyChannel() : mPending(false)
michael@0 45 , mSuspendCount(0)
michael@0 46 , mLoadFlags(LOAD_NORMAL)
michael@0 47 {
michael@0 48 }
michael@0 49
michael@0 50 NS_IMETHODIMP DummyChannel::GetName(nsACString &result)
michael@0 51 {
michael@0 52 result = "dummy_app_channel";
michael@0 53 return NS_OK;
michael@0 54 }
michael@0 55
michael@0 56 NS_IMETHODIMP DummyChannel::GetStatus(nsresult *aStatus)
michael@0 57 {
michael@0 58 *aStatus = NS_ERROR_FILE_NOT_FOUND;
michael@0 59 return NS_OK;
michael@0 60 }
michael@0 61
michael@0 62 NS_IMETHODIMP DummyChannel::IsPending(bool *aResult)
michael@0 63 {
michael@0 64 *aResult = mPending;
michael@0 65 return NS_OK;
michael@0 66 }
michael@0 67
michael@0 68 NS_IMETHODIMP DummyChannel::Suspend()
michael@0 69 {
michael@0 70 mSuspendCount++;
michael@0 71 return NS_OK;
michael@0 72 }
michael@0 73
michael@0 74 NS_IMETHODIMP DummyChannel::Resume()
michael@0 75 {
michael@0 76 if (mSuspendCount <= 0) {
michael@0 77 return NS_ERROR_UNEXPECTED;
michael@0 78 }
michael@0 79
michael@0 80 if (--mSuspendCount == 0) {
michael@0 81 NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
michael@0 82 }
michael@0 83 return NS_OK;
michael@0 84 }
michael@0 85
michael@0 86 NS_IMETHODIMP DummyChannel::Open(nsIInputStream**)
michael@0 87 {
michael@0 88 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 89 }
michael@0 90
michael@0 91 NS_IMETHODIMP DummyChannel::AsyncOpen(nsIStreamListener* aListener, nsISupports* aContext)
michael@0 92 {
michael@0 93 mListener = aListener;
michael@0 94 mListenerContext = aContext;
michael@0 95 mPending = true;
michael@0 96
michael@0 97 if (mLoadGroup) {
michael@0 98 mLoadGroup->AddRequest(this, aContext);
michael@0 99 }
michael@0 100
michael@0 101 if (mSuspendCount == 0) {
michael@0 102 NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
michael@0 103 }
michael@0 104
michael@0 105 return NS_OK;
michael@0 106 }
michael@0 107
michael@0 108 // nsIJarChannel, needed for XHR to turn NS_ERROR_FILE_NOT_FOUND into
michael@0 109 // a 404 error.
michael@0 110 NS_IMETHODIMP DummyChannel::GetIsUnsafe(bool *aResult)
michael@0 111 {
michael@0 112 *aResult = false;
michael@0 113 return NS_OK;
michael@0 114 }
michael@0 115
michael@0 116 NS_IMETHODIMP DummyChannel::SetAppURI(nsIURI *aURI)
michael@0 117 {
michael@0 118 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 119 }
michael@0 120
michael@0 121 NS_IMETHODIMP DummyChannel::Run()
michael@0 122 {
michael@0 123 nsresult rv = mListener->OnStartRequest(this, mListenerContext);
michael@0 124 NS_ENSURE_SUCCESS(rv, rv);
michael@0 125 mPending = false;
michael@0 126 rv = mListener->OnStopRequest(this, mListenerContext, NS_ERROR_FILE_NOT_FOUND);
michael@0 127 NS_ENSURE_SUCCESS(rv, rv);
michael@0 128 if (mLoadGroup) {
michael@0 129 mLoadGroup->RemoveRequest(this, mListenerContext, NS_ERROR_FILE_NOT_FOUND);
michael@0 130 }
michael@0 131
michael@0 132 mListener = nullptr;
michael@0 133 mListenerContext = nullptr;
michael@0 134 rv = SetNotificationCallbacks(nullptr);
michael@0 135 NS_ENSURE_SUCCESS(rv, rv);
michael@0 136
michael@0 137 return NS_OK;
michael@0 138 }
michael@0 139
michael@0 140 NS_IMETHODIMP DummyChannel::Cancel(nsresult)
michael@0 141 {
michael@0 142 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 143 }
michael@0 144
michael@0 145 NS_IMETHODIMP DummyChannel::GetLoadGroup(nsILoadGroup* *aLoadGroup)
michael@0 146 {
michael@0 147 *aLoadGroup = mLoadGroup;
michael@0 148 NS_IF_ADDREF(*aLoadGroup);
michael@0 149 return NS_OK;
michael@0 150 }
michael@0 151
michael@0 152 NS_IMETHODIMP DummyChannel::SetLoadGroup(nsILoadGroup* aLoadGroup)
michael@0 153 {
michael@0 154 mLoadGroup = aLoadGroup;
michael@0 155 return NS_OK;
michael@0 156 }
michael@0 157
michael@0 158 NS_IMETHODIMP DummyChannel::GetLoadFlags(nsLoadFlags *aLoadFlags)
michael@0 159 {
michael@0 160 *aLoadFlags = mLoadFlags;
michael@0 161 return NS_OK;
michael@0 162 }
michael@0 163
michael@0 164 NS_IMETHODIMP DummyChannel::SetLoadFlags(nsLoadFlags aLoadFlags)
michael@0 165 {
michael@0 166 mLoadFlags = aLoadFlags;
michael@0 167 return NS_OK;
michael@0 168 }
michael@0 169
michael@0 170 NS_IMETHODIMP DummyChannel::GetOriginalURI(nsIURI**)
michael@0 171 {
michael@0 172 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 173 }
michael@0 174
michael@0 175 NS_IMETHODIMP DummyChannel::SetOriginalURI(nsIURI*)
michael@0 176 {
michael@0 177 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 178 }
michael@0 179
michael@0 180 NS_IMETHODIMP DummyChannel::GetOwner(nsISupports**)
michael@0 181 {
michael@0 182 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 183 }
michael@0 184
michael@0 185 NS_IMETHODIMP DummyChannel::SetOwner(nsISupports*)
michael@0 186 {
michael@0 187 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 188 }
michael@0 189
michael@0 190 NS_IMETHODIMP DummyChannel::GetNotificationCallbacks(nsIInterfaceRequestor**)
michael@0 191 {
michael@0 192 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 193 }
michael@0 194
michael@0 195 NS_IMETHODIMP DummyChannel::SetNotificationCallbacks(nsIInterfaceRequestor*)
michael@0 196 {
michael@0 197 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 198 }
michael@0 199
michael@0 200 NS_IMETHODIMP DummyChannel::GetSecurityInfo(nsISupports**)
michael@0 201 {
michael@0 202 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 203 }
michael@0 204
michael@0 205 NS_IMETHODIMP DummyChannel::GetContentType(nsACString&)
michael@0 206 {
michael@0 207 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 208 }
michael@0 209
michael@0 210 NS_IMETHODIMP DummyChannel::SetContentType(const nsACString&)
michael@0 211 {
michael@0 212 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 213 }
michael@0 214
michael@0 215 NS_IMETHODIMP DummyChannel::GetContentCharset(nsACString&)
michael@0 216 {
michael@0 217 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 218 }
michael@0 219
michael@0 220 NS_IMETHODIMP DummyChannel::SetContentCharset(const nsACString&)
michael@0 221 {
michael@0 222 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 223 }
michael@0 224
michael@0 225 NS_IMETHODIMP DummyChannel::GetContentLength(int64_t*)
michael@0 226 {
michael@0 227 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 228 }
michael@0 229
michael@0 230 NS_IMETHODIMP DummyChannel::SetContentLength(int64_t)
michael@0 231 {
michael@0 232 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 233 }
michael@0 234
michael@0 235 NS_IMETHODIMP DummyChannel::GetContentDisposition(uint32_t*)
michael@0 236 {
michael@0 237 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 238 }
michael@0 239
michael@0 240 NS_IMETHODIMP DummyChannel::SetContentDisposition(uint32_t)
michael@0 241 {
michael@0 242 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 243 }
michael@0 244
michael@0 245 NS_IMETHODIMP DummyChannel::GetURI(nsIURI**)
michael@0 246 {
michael@0 247 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 248 }
michael@0 249
michael@0 250 NS_IMETHODIMP DummyChannel::GetContentDispositionFilename(nsAString&)
michael@0 251 {
michael@0 252 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 253 }
michael@0 254
michael@0 255 NS_IMETHODIMP DummyChannel::SetContentDispositionFilename(nsAString const &)
michael@0 256 {
michael@0 257 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 258 }
michael@0 259
michael@0 260 NS_IMETHODIMP DummyChannel::GetContentDispositionHeader(nsACString&)
michael@0 261 {
michael@0 262 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 263 }
michael@0 264
michael@0 265 /**
michael@0 266 * app:// protocol implementation.
michael@0 267 */
michael@0 268
michael@0 269 AppProtocolHandler::AppProtocolHandler() {
michael@0 270 }
michael@0 271
michael@0 272 AppProtocolHandler::~AppProtocolHandler() {
michael@0 273 mAppInfoCache.Clear();
michael@0 274 }
michael@0 275
michael@0 276 NS_IMPL_ISUPPORTS(AppProtocolHandler, nsIProtocolHandler)
michael@0 277
michael@0 278 /* static */
michael@0 279 nsresult
michael@0 280 AppProtocolHandler::Create(nsISupports* aOuter,
michael@0 281 const nsIID& aIID,
michael@0 282 void* *aResult)
michael@0 283 {
michael@0 284 // Instantiate the service here since that intializes gJarHandler, which we
michael@0 285 // use indirectly (via our new JarChannel) in NewChannel.
michael@0 286 nsCOMPtr<nsIProtocolHandler> jarInitializer(
michael@0 287 do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "jar"));
michael@0 288 AppProtocolHandler* ph = new AppProtocolHandler();
michael@0 289 if (ph == nullptr) {
michael@0 290 return NS_ERROR_OUT_OF_MEMORY;
michael@0 291 }
michael@0 292 NS_ADDREF(ph);
michael@0 293 nsresult rv = ph->QueryInterface(aIID, aResult);
michael@0 294 NS_RELEASE(ph);
michael@0 295 return rv;
michael@0 296 }
michael@0 297
michael@0 298 NS_IMETHODIMP
michael@0 299 AppProtocolHandler::GetScheme(nsACString &aResult)
michael@0 300 {
michael@0 301 aResult.AssignLiteral("app");
michael@0 302 return NS_OK;
michael@0 303 }
michael@0 304
michael@0 305 NS_IMETHODIMP
michael@0 306 AppProtocolHandler::GetDefaultPort(int32_t *aResult)
michael@0 307 {
michael@0 308 // No ports for the app protocol.
michael@0 309 *aResult = -1;
michael@0 310 return NS_OK;
michael@0 311 }
michael@0 312
michael@0 313 NS_IMETHODIMP
michael@0 314 AppProtocolHandler::GetProtocolFlags(uint32_t *aResult)
michael@0 315 {
michael@0 316 *aResult = URI_NOAUTH |
michael@0 317 URI_DANGEROUS_TO_LOAD |
michael@0 318 URI_CROSS_ORIGIN_NEEDS_WEBAPPS_PERM;
michael@0 319 return NS_OK;
michael@0 320 }
michael@0 321
michael@0 322 NS_IMETHODIMP
michael@0 323 AppProtocolHandler::NewURI(const nsACString &aSpec,
michael@0 324 const char *aCharset, // ignore charset info
michael@0 325 nsIURI *aBaseURI,
michael@0 326 nsIURI **result)
michael@0 327 {
michael@0 328 nsresult rv;
michael@0 329 nsCOMPtr<nsIStandardURL> surl(do_CreateInstance(NS_STANDARDURL_CONTRACTID, &rv));
michael@0 330 NS_ENSURE_SUCCESS(rv, rv);
michael@0 331
michael@0 332 rv = surl->Init(nsIStandardURL::URLTYPE_STANDARD, -1, aSpec, aCharset, aBaseURI);
michael@0 333 NS_ENSURE_SUCCESS(rv, rv);
michael@0 334
michael@0 335 nsCOMPtr<nsIURL> url(do_QueryInterface(surl, &rv));
michael@0 336 NS_ENSURE_SUCCESS(rv, rv);
michael@0 337
michael@0 338 url.forget(result);
michael@0 339 return NS_OK;
michael@0 340 }
michael@0 341
michael@0 342 // We map app://ABCDEF/path/to/file.ext to
michael@0 343 // jar:file:///path/to/profile/webapps/ABCDEF/application.zip!/path/to/file.ext
michael@0 344 NS_IMETHODIMP
michael@0 345 AppProtocolHandler::NewChannel(nsIURI* aUri, nsIChannel* *aResult)
michael@0 346 {
michael@0 347 NS_ENSURE_ARG_POINTER(aUri);
michael@0 348 nsRefPtr<nsJARChannel> channel = new nsJARChannel();
michael@0 349
michael@0 350 nsAutoCString host;
michael@0 351 nsresult rv = aUri->GetHost(host);
michael@0 352 NS_ENSURE_SUCCESS(rv, rv);
michael@0 353
michael@0 354 nsAutoCString fileSpec;
michael@0 355 nsCOMPtr<nsIURL> url = do_QueryInterface(aUri);
michael@0 356 rv = url->GetFilePath(fileSpec);
michael@0 357 NS_ENSURE_SUCCESS(rv, rv);
michael@0 358
michael@0 359 mozilla::dom::AppInfo *appInfo;
michael@0 360
michael@0 361 if (!mAppInfoCache.Get(host, &appInfo)) {
michael@0 362 nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
michael@0 363 if (!appsService) {
michael@0 364 return NS_ERROR_FAILURE;
michael@0 365 }
michael@0 366
michael@0 367 mozilla::AutoSafeJSContext cx;
michael@0 368 JS::RootedValue jsInfo(cx);
michael@0 369 rv = appsService->GetAppInfo(NS_ConvertUTF8toUTF16(host), &jsInfo);
michael@0 370 if (NS_FAILED(rv) || !jsInfo.isObject()) {
michael@0 371 // Return a DummyChannel.
michael@0 372 printf_stderr("!! Creating a dummy channel for %s (no appInfo)\n", host.get());
michael@0 373 NS_IF_ADDREF(*aResult = new DummyChannel());
michael@0 374 return NS_OK;
michael@0 375 }
michael@0 376
michael@0 377 appInfo = new mozilla::dom::AppInfo();
michael@0 378 JSAutoCompartment ac(cx, &jsInfo.toObject());
michael@0 379 if (!appInfo->Init(cx, jsInfo) || appInfo->mPath.IsEmpty()) {
michael@0 380 // Return a DummyChannel.
michael@0 381 printf_stderr("!! Creating a dummy channel for %s (invalid appInfo)\n", host.get());
michael@0 382 NS_IF_ADDREF(*aResult = new DummyChannel());
michael@0 383 return NS_OK;
michael@0 384 }
michael@0 385 mAppInfoCache.Put(host, appInfo);
michael@0 386 }
michael@0 387
michael@0 388 bool noRemote = (appInfo->mIsCoreApp ||
michael@0 389 XRE_GetProcessType() == GeckoProcessType_Default);
michael@0 390
michael@0 391 // In-parent and CoreApps can directly access files, so use jar:file://
michael@0 392 nsAutoCString jarSpec(noRemote ? "jar:file://"
michael@0 393 : "jar:remoteopenfile://");
michael@0 394 jarSpec += NS_ConvertUTF16toUTF8(appInfo->mPath) +
michael@0 395 NS_LITERAL_CSTRING("/application.zip!") +
michael@0 396 fileSpec;
michael@0 397
michael@0 398 nsCOMPtr<nsIURI> jarURI;
michael@0 399 rv = NS_NewURI(getter_AddRefs(jarURI),
michael@0 400 jarSpec, nullptr, nullptr);
michael@0 401 NS_ENSURE_SUCCESS(rv, rv);
michael@0 402
michael@0 403 rv = channel->Init(jarURI);
michael@0 404 NS_ENSURE_SUCCESS(rv, rv);
michael@0 405
michael@0 406 rv = channel->SetAppURI(aUri);
michael@0 407 NS_ENSURE_SUCCESS(rv, rv);
michael@0 408
michael@0 409 rv = channel->SetOriginalURI(aUri);
michael@0 410 NS_ENSURE_SUCCESS(rv, rv);
michael@0 411
michael@0 412 channel.forget(aResult);
michael@0 413 return NS_OK;
michael@0 414 }
michael@0 415
michael@0 416 NS_IMETHODIMP
michael@0 417 AppProtocolHandler::AllowPort(int32_t aPort, const char *aScheme, bool *aRetval)
michael@0 418 {
michael@0 419 // No port allowed for this scheme.
michael@0 420 *aRetval = false;
michael@0 421 return NS_OK;
michael@0 422 }
michael@0 423

mercurial