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