1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "mozilla/chrome/RegistryMessageUtils.h"
7 #include "mozilla/dom/ContentParent.h"
8 #include "mozilla/ClearOnShutdown.h"
9 #include "mozilla/Unused.h"
10 
11 #include "nsResProtocolHandler.h"
12 #include "nsNetCID.h"
13 #include "nsNetUtil.h"
14 #include "nsURLHelper.h"
15 #include "nsEscape.h"
16 
17 #include "mozilla/Omnijar.h"
18 
19 using mozilla::LogLevel;
20 using mozilla::Unused;
21 using mozilla::dom::ContentParent;
22 
23 #define kAPP "app"
24 #define kGRE "gre"
25 #define kAndroid "android"
26 
27 mozilla::StaticRefPtr<nsResProtocolHandler> nsResProtocolHandler::sSingleton;
28 
GetSingleton()29 already_AddRefed<nsResProtocolHandler> nsResProtocolHandler::GetSingleton() {
30   if (!sSingleton) {
31     RefPtr<nsResProtocolHandler> handler = new nsResProtocolHandler();
32     if (NS_WARN_IF(NS_FAILED(handler->Init()))) {
33       return nullptr;
34     }
35     sSingleton = handler;
36     ClearOnShutdown(&sSingleton);
37   }
38   return do_AddRef(sSingleton);
39 }
40 
Init()41 nsresult nsResProtocolHandler::Init() {
42   nsresult rv;
43   rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::APP, mAppURI);
44   NS_ENSURE_SUCCESS(rv, rv);
45   rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::GRE, mGREURI);
46   NS_ENSURE_SUCCESS(rv, rv);
47 
48   // mozilla::Omnijar::GetURIString always returns a string ending with /,
49   // and we want to remove it.
50   mGREURI.Truncate(mGREURI.Length() - 1);
51   if (mAppURI.Length()) {
52     mAppURI.Truncate(mAppURI.Length() - 1);
53   } else {
54     mAppURI = mGREURI;
55   }
56 
57 #ifdef ANDROID
58   rv = GetApkURI(mApkURI);
59 #endif
60 
61   // XXXbsmedberg Neil wants a resource://pchrome/ for the profile chrome dir...
62   // but once I finish multiple chrome registration I'm not sure that it is
63   // needed
64 
65   // XXX dveditz: resource://pchrome/ defeats profile directory salting
66   // if web content can load it. Tread carefully.
67 
68   return rv;
69 }
70 
71 #ifdef ANDROID
GetApkURI(nsACString & aResult)72 nsresult nsResProtocolHandler::GetApkURI(nsACString& aResult) {
73   nsCString::const_iterator start, iter;
74   mGREURI.BeginReading(start);
75   mGREURI.EndReading(iter);
76   nsCString::const_iterator start_iter = start;
77 
78   // This is like jar:jar:file://path/to/apk/base.apk!/path/to/omni.ja!/
79   bool found = FindInReadable("!/"_ns, start_iter, iter);
80   NS_ENSURE_TRUE(found, NS_ERROR_UNEXPECTED);
81 
82   // like jar:jar:file://path/to/apk/base.apk!/
83   const nsDependentCSubstring& withoutPath = Substring(start, iter);
84   NS_ENSURE_TRUE(withoutPath.Length() >= 4, NS_ERROR_UNEXPECTED);
85 
86   // Let's make sure we're removing what we expect to remove
87   NS_ENSURE_TRUE(Substring(withoutPath, 0, 4).EqualsLiteral("jar:"),
88                  NS_ERROR_UNEXPECTED);
89 
90   // like jar:file://path/to/apk/base.apk!/
91   aResult = ToNewCString(Substring(withoutPath, 4));
92 
93   // Remove the trailing /
94   NS_ENSURE_TRUE(aResult.Length() >= 1, NS_ERROR_UNEXPECTED);
95   aResult.Truncate(aResult.Length() - 1);
96   return NS_OK;
97 }
98 #endif
99 
100 //----------------------------------------------------------------------------
101 // nsResProtocolHandler::nsISupports
102 //----------------------------------------------------------------------------
103 
NS_IMPL_QUERY_INTERFACE(nsResProtocolHandler,nsIResProtocolHandler,nsISubstitutingProtocolHandler,nsIProtocolHandler,nsISupportsWeakReference)104 NS_IMPL_QUERY_INTERFACE(nsResProtocolHandler, nsIResProtocolHandler,
105                         nsISubstitutingProtocolHandler, nsIProtocolHandler,
106                         nsISupportsWeakReference)
107 NS_IMPL_ADDREF_INHERITED(nsResProtocolHandler, SubstitutingProtocolHandler)
108 NS_IMPL_RELEASE_INHERITED(nsResProtocolHandler, SubstitutingProtocolHandler)
109 
110 NS_IMETHODIMP
111 nsResProtocolHandler::AllowContentToAccess(nsIURI* aURI, bool* aResult) {
112   *aResult = false;
113 
114   nsAutoCString host;
115   nsresult rv = aURI->GetAsciiHost(host);
116   NS_ENSURE_SUCCESS(rv, rv);
117 
118   uint32_t flags;
119   rv = GetSubstitutionFlags(host, &flags);
120   NS_ENSURE_SUCCESS(rv, rv);
121 
122   *aResult = flags & nsISubstitutingProtocolHandler::ALLOW_CONTENT_ACCESS;
123   return NS_OK;
124 }
125 
GetSubstitutionInternal(const nsACString & aRoot,nsIURI ** aResult,uint32_t * aFlags)126 nsresult nsResProtocolHandler::GetSubstitutionInternal(const nsACString& aRoot,
127                                                        nsIURI** aResult,
128                                                        uint32_t* aFlags) {
129   nsAutoCString uri;
130 
131   if (!ResolveSpecialCases(aRoot, "/"_ns, "/"_ns, uri)) {
132     return NS_ERROR_NOT_AVAILABLE;
133   }
134 
135   if (aRoot.Equals(kAndroid)) {
136     *aFlags = nsISubstitutingProtocolHandler::RESOLVE_JAR_URI;
137   } else {
138     *aFlags = 0;  // No content access.
139   }
140   return NS_NewURI(aResult, uri);
141 }
142 
ResolveSpecialCases(const nsACString & aHost,const nsACString & aPath,const nsACString & aPathname,nsACString & aResult)143 bool nsResProtocolHandler::ResolveSpecialCases(const nsACString& aHost,
144                                                const nsACString& aPath,
145                                                const nsACString& aPathname,
146                                                nsACString& aResult) {
147   if (aHost.EqualsLiteral("") || aHost.EqualsLiteral(kAPP)) {
148     aResult.Assign(mAppURI);
149   } else if (aHost.Equals(kGRE)) {
150     aResult.Assign(mGREURI);
151 #ifdef ANDROID
152   } else if (aHost.Equals(kAndroid)) {
153     aResult.Assign(mApkURI);
154 #endif
155   } else {
156     return false;
157   }
158   aResult.Append(aPath);
159   return true;
160 }
161 
SetSubstitution(const nsACString & aRoot,nsIURI * aBaseURI)162 nsresult nsResProtocolHandler::SetSubstitution(const nsACString& aRoot,
163                                                nsIURI* aBaseURI) {
164   MOZ_ASSERT(!aRoot.EqualsLiteral(""));
165   MOZ_ASSERT(!aRoot.EqualsLiteral(kAPP));
166   MOZ_ASSERT(!aRoot.EqualsLiteral(kGRE));
167   MOZ_ASSERT(!aRoot.EqualsLiteral(kAndroid));
168   return SubstitutingProtocolHandler::SetSubstitution(aRoot, aBaseURI);
169 }
170 
SetSubstitutionWithFlags(const nsACString & aRoot,nsIURI * aBaseURI,uint32_t aFlags)171 nsresult nsResProtocolHandler::SetSubstitutionWithFlags(const nsACString& aRoot,
172                                                         nsIURI* aBaseURI,
173                                                         uint32_t aFlags) {
174   MOZ_ASSERT(!aRoot.EqualsLiteral(""));
175   MOZ_ASSERT(!aRoot.EqualsLiteral(kAPP));
176   MOZ_ASSERT(!aRoot.EqualsLiteral(kGRE));
177   MOZ_ASSERT(!aRoot.EqualsLiteral(kAndroid));
178   return SubstitutingProtocolHandler::SetSubstitutionWithFlags(aRoot, aBaseURI,
179                                                                aFlags);
180 }
181 
HasSubstitution(const nsACString & aRoot,bool * aResult)182 nsresult nsResProtocolHandler::HasSubstitution(const nsACString& aRoot,
183                                                bool* aResult) {
184   if (aRoot.EqualsLiteral(kAPP) || aRoot.EqualsLiteral(kGRE)
185 #ifdef ANDROID
186       || aRoot.EqualsLiteral(kAndroid)
187 #endif
188   ) {
189     *aResult = true;
190     return NS_OK;
191   }
192 
193   return mozilla::net::SubstitutingProtocolHandler::HasSubstitution(aRoot,
194                                                                     aResult);
195 }
196