Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : // vim:ts=4 sw=4 sts=4 et cin:
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 "nsIFile.h"
8 : #include "nsFileProtocolHandler.h"
9 : #include "nsFileChannel.h"
10 : #include "nsStandardURL.h"
11 : #include "nsURLHelper.h"
12 :
13 : #include "nsNetUtil.h"
14 :
15 : #include "FileChannelChild.h"
16 :
17 : // URL file handling, copied and modified from xpfe/components/bookmarks/src/nsBookmarksService.cpp
18 : #ifdef XP_WIN
19 : #include <shlobj.h>
20 : #include <intshcut.h>
21 : #include "nsIFileURL.h"
22 : #ifdef CompareString
23 : #undef CompareString
24 : #endif
25 : #endif
26 :
27 : // URL file handling for freedesktop.org
28 : #ifdef XP_UNIX
29 : #include "nsINIParser.h"
30 : #define DESKTOP_ENTRY_SECTION "Desktop Entry"
31 : #endif
32 :
33 : //-----------------------------------------------------------------------------
34 :
35 3 : nsFileProtocolHandler::nsFileProtocolHandler()
36 : {
37 3 : }
38 :
39 : nsresult
40 3 : nsFileProtocolHandler::Init()
41 : {
42 3 : return NS_OK;
43 : }
44 :
45 44071 : NS_IMPL_ISUPPORTS(nsFileProtocolHandler,
46 : nsIFileProtocolHandler,
47 : nsIProtocolHandler,
48 : nsISupportsWeakReference)
49 :
50 : //-----------------------------------------------------------------------------
51 : // nsIProtocolHandler methods:
52 :
53 : #if defined(XP_WIN)
54 : NS_IMETHODIMP
55 : nsFileProtocolHandler::ReadURLFile(nsIFile* aFile, nsIURI** aURI)
56 : {
57 : nsAutoString path;
58 : nsresult rv = aFile->GetPath(path);
59 : if (NS_FAILED(rv))
60 : return rv;
61 :
62 : if (path.Length() < 4)
63 : return NS_ERROR_NOT_AVAILABLE;
64 : if (!StringTail(path, 4).LowerCaseEqualsLiteral(".url"))
65 : return NS_ERROR_NOT_AVAILABLE;
66 :
67 : HRESULT result;
68 :
69 : rv = NS_ERROR_NOT_AVAILABLE;
70 :
71 : IUniformResourceLocatorW* urlLink = nullptr;
72 : result = ::CoCreateInstance(CLSID_InternetShortcut, nullptr, CLSCTX_INPROC_SERVER,
73 : IID_IUniformResourceLocatorW, (void**)&urlLink);
74 : if (SUCCEEDED(result) && urlLink) {
75 : IPersistFile* urlFile = nullptr;
76 : result = urlLink->QueryInterface(IID_IPersistFile, (void**)&urlFile);
77 : if (SUCCEEDED(result) && urlFile) {
78 : result = urlFile->Load(path.get(), STGM_READ);
79 : if (SUCCEEDED(result) ) {
80 : LPWSTR lpTemp = nullptr;
81 :
82 : // The URL this method will give us back seems to be already
83 : // escaped. Hence, do not do escaping of our own.
84 : result = urlLink->GetURL(&lpTemp);
85 : if (SUCCEEDED(result) && lpTemp) {
86 : rv = NS_NewURI(aURI, nsDependentString(lpTemp));
87 : // free the string that GetURL alloc'd
88 : CoTaskMemFree(lpTemp);
89 : }
90 : }
91 : urlFile->Release();
92 : }
93 : urlLink->Release();
94 : }
95 : return rv;
96 : }
97 :
98 : #elif defined(XP_UNIX)
99 : NS_IMETHODIMP
100 172 : nsFileProtocolHandler::ReadURLFile(nsIFile* aFile, nsIURI** aURI)
101 : {
102 : // We only support desktop files that end in ".desktop" like the spec says:
103 : // http://standards.freedesktop.org/desktop-entry-spec/latest/ar01s02.html
104 344 : nsAutoCString leafName;
105 172 : nsresult rv = aFile->GetNativeLeafName(leafName);
106 688 : if (NS_FAILED(rv) ||
107 688 : !StringEndsWith(leafName, NS_LITERAL_CSTRING(".desktop")))
108 172 : return NS_ERROR_NOT_AVAILABLE;
109 :
110 0 : bool isFile = false;
111 0 : rv = aFile->IsFile(&isFile);
112 0 : if (NS_FAILED(rv) || !isFile) {
113 0 : return NS_ERROR_NOT_AVAILABLE;
114 : }
115 :
116 0 : nsINIParser parser;
117 0 : rv = parser.Init(aFile);
118 0 : if (NS_FAILED(rv))
119 0 : return rv;
120 :
121 0 : nsAutoCString type;
122 0 : parser.GetString(DESKTOP_ENTRY_SECTION, "Type", type);
123 0 : if (!type.EqualsLiteral("Link"))
124 0 : return NS_ERROR_NOT_AVAILABLE;
125 :
126 0 : nsAutoCString url;
127 0 : rv = parser.GetString(DESKTOP_ENTRY_SECTION, "URL", url);
128 0 : if (NS_FAILED(rv) || url.IsEmpty())
129 0 : return NS_ERROR_NOT_AVAILABLE;
130 :
131 0 : return NS_NewURI(aURI, url);
132 : }
133 :
134 : #else // other platforms
135 : NS_IMETHODIMP
136 : nsFileProtocolHandler::ReadURLFile(nsIFile* aFile, nsIURI** aURI)
137 : {
138 : return NS_ERROR_NOT_AVAILABLE;
139 : }
140 : #endif // ReadURLFile()
141 :
142 : NS_IMETHODIMP
143 0 : nsFileProtocolHandler::GetScheme(nsACString &result)
144 : {
145 0 : result.AssignLiteral("file");
146 0 : return NS_OK;
147 : }
148 :
149 : NS_IMETHODIMP
150 0 : nsFileProtocolHandler::GetDefaultPort(int32_t *result)
151 : {
152 0 : *result = -1; // no port for file: URLs
153 0 : return NS_OK;
154 : }
155 :
156 : NS_IMETHODIMP
157 1371 : nsFileProtocolHandler::GetProtocolFlags(uint32_t *result)
158 : {
159 1371 : *result = URI_NOAUTH | URI_IS_LOCAL_FILE | URI_IS_LOCAL_RESOURCE;
160 1371 : return NS_OK;
161 : }
162 :
163 : NS_IMETHODIMP
164 1939 : nsFileProtocolHandler::NewURI(const nsACString &spec,
165 : const char *charset,
166 : nsIURI *baseURI,
167 : nsIURI **result)
168 : {
169 3878 : nsCOMPtr<nsIStandardURL> url = new nsStandardURL(true);
170 1939 : if (!url)
171 0 : return NS_ERROR_OUT_OF_MEMORY;
172 :
173 1939 : const nsACString *specPtr = &spec;
174 :
175 : #if defined(XP_WIN)
176 : nsAutoCString buf;
177 : if (net_NormalizeFileURL(spec, buf))
178 : specPtr = &buf;
179 : #endif
180 :
181 1939 : nsresult rv = url->Init(nsIStandardURL::URLTYPE_NO_AUTHORITY, -1,
182 1939 : *specPtr, charset, baseURI);
183 1939 : if (NS_FAILED(rv)) return rv;
184 :
185 1939 : return CallQueryInterface(url, result);
186 : }
187 :
188 : NS_IMETHODIMP
189 1171 : nsFileProtocolHandler::NewChannel2(nsIURI* uri,
190 : nsILoadInfo* aLoadInfo,
191 : nsIChannel** result)
192 : {
193 : nsresult rv;
194 :
195 : nsFileChannel *chan;
196 1171 : if (IsNeckoChild()) {
197 279 : chan = new mozilla::net::FileChannelChild(uri);
198 : } else {
199 892 : chan = new nsFileChannel(uri);
200 : }
201 1171 : if (!chan)
202 0 : return NS_ERROR_OUT_OF_MEMORY;
203 1171 : NS_ADDREF(chan);
204 :
205 : // set the loadInfo on the new channel ; must do this
206 : // before calling Init() on it, since it needs the load
207 : // info be already set.
208 1171 : rv = chan->SetLoadInfo(aLoadInfo);
209 1171 : if (NS_FAILED(rv)) {
210 0 : NS_RELEASE(chan);
211 0 : return rv;
212 : }
213 :
214 1171 : rv = chan->Init();
215 1171 : if (NS_FAILED(rv)) {
216 0 : NS_RELEASE(chan);
217 0 : return rv;
218 : }
219 :
220 1171 : *result = chan;
221 1171 : return NS_OK;
222 : }
223 :
224 : NS_IMETHODIMP
225 0 : nsFileProtocolHandler::NewChannel(nsIURI *uri, nsIChannel **result)
226 : {
227 0 : return NewChannel2(uri, nullptr, result);
228 : }
229 :
230 : NS_IMETHODIMP
231 0 : nsFileProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *result)
232 : {
233 : // don't override anything.
234 0 : *result = false;
235 0 : return NS_OK;
236 : }
237 :
238 : //-----------------------------------------------------------------------------
239 : // nsIFileProtocolHandler methods:
240 :
241 : NS_IMETHODIMP
242 1121 : nsFileProtocolHandler::NewFileURI(nsIFile *file, nsIURI **result)
243 : {
244 1121 : NS_ENSURE_ARG_POINTER(file);
245 : nsresult rv;
246 :
247 2242 : nsCOMPtr<nsIFileURL> url = new nsStandardURL(true);
248 1121 : if (!url)
249 0 : return NS_ERROR_OUT_OF_MEMORY;
250 :
251 : // NOTE: the origin charset is assigned the value of the platform
252 : // charset by the SetFile method.
253 1121 : rv = url->SetFile(file);
254 1121 : if (NS_FAILED(rv)) return rv;
255 :
256 1121 : return CallQueryInterface(url, result);
257 : }
258 :
259 : NS_IMETHODIMP
260 0 : nsFileProtocolHandler::GetURLSpecFromFile(nsIFile *file, nsACString &result)
261 : {
262 0 : NS_ENSURE_ARG_POINTER(file);
263 0 : return net_GetURLSpecFromFile(file, result);
264 : }
265 :
266 : NS_IMETHODIMP
267 790 : nsFileProtocolHandler::GetURLSpecFromActualFile(nsIFile *file,
268 : nsACString &result)
269 : {
270 790 : NS_ENSURE_ARG_POINTER(file);
271 790 : return net_GetURLSpecFromActualFile(file, result);
272 : }
273 :
274 : NS_IMETHODIMP
275 0 : nsFileProtocolHandler::GetURLSpecFromDir(nsIFile *file, nsACString &result)
276 : {
277 0 : NS_ENSURE_ARG_POINTER(file);
278 0 : return net_GetURLSpecFromDir(file, result);
279 : }
280 :
281 : NS_IMETHODIMP
282 0 : nsFileProtocolHandler::GetFileFromURLSpec(const nsACString &spec, nsIFile **result)
283 : {
284 0 : return net_GetFileFromURLSpec(spec, result);
285 : }
|