dom/base/URL.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:0d46ce9bebff
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 "URL.h"
7
8 #include "nsGlobalWindow.h"
9 #include "nsIDOMFile.h"
10 #include "DOMMediaStream.h"
11 #include "mozilla/dom/MediaSource.h"
12 #include "mozilla/dom/URLBinding.h"
13 #include "nsHostObjectProtocolHandler.h"
14 #include "nsServiceManagerUtils.h"
15 #include "nsIIOService.h"
16 #include "nsEscape.h"
17 #include "nsNetCID.h"
18 #include "nsIURL.h"
19
20 namespace mozilla {
21 namespace dom {
22
23 NS_IMPL_CYCLE_COLLECTION_CLASS(URL)
24
25 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(URL)
26 if (tmp->mSearchParams) {
27 tmp->mSearchParams->RemoveObserver(tmp);
28 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSearchParams)
29 }
30 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
31
32 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(URL)
33 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSearchParams)
34 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
35
36 NS_IMPL_CYCLE_COLLECTING_ADDREF(URL)
37 NS_IMPL_CYCLE_COLLECTING_RELEASE(URL)
38
39 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URL)
40 NS_INTERFACE_MAP_ENTRY(nsISupports)
41 NS_INTERFACE_MAP_END
42
43 URL::URL(nsIURI* aURI)
44 : mURI(aURI)
45 {
46 }
47
48 JSObject*
49 URL::WrapObject(JSContext* aCx)
50 {
51 return URLBinding::Wrap(aCx, this);
52 }
53
54 /* static */ already_AddRefed<URL>
55 URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
56 URL& aBase, ErrorResult& aRv)
57 {
58 nsresult rv;
59 nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
60 if (NS_FAILED(rv)) {
61 aRv.Throw(rv);
62 return nullptr;
63 }
64
65 nsCOMPtr<nsIURI> uri;
66 rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aUrl), nullptr, aBase.GetURI(),
67 getter_AddRefs(uri));
68 if (NS_FAILED(rv)) {
69 nsAutoString label(aUrl);
70 aRv.ThrowTypeError(MSG_INVALID_URL, &label);
71 return nullptr;
72 }
73
74 nsRefPtr<URL> url = new URL(uri);
75 return url.forget();
76 }
77
78 /* static */ already_AddRefed<URL>
79 URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl,
80 const nsAString& aBase, ErrorResult& aRv)
81 {
82 nsresult rv;
83 nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
84 if (NS_FAILED(rv)) {
85 aRv.Throw(rv);
86 return nullptr;
87 }
88
89 nsCOMPtr<nsIURI> baseUri;
90 rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aBase), nullptr, nullptr,
91 getter_AddRefs(baseUri));
92 if (NS_FAILED(rv)) {
93 nsAutoString label(aBase);
94 aRv.ThrowTypeError(MSG_INVALID_URL, &label);
95 return nullptr;
96 }
97
98 nsCOMPtr<nsIURI> uri;
99 rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aUrl), nullptr, baseUri,
100 getter_AddRefs(uri));
101 if (NS_FAILED(rv)) {
102 nsAutoString label(aUrl);
103 aRv.ThrowTypeError(MSG_INVALID_URL, &label);
104 return nullptr;
105 }
106
107 nsRefPtr<URL> url = new URL(uri);
108 return url.forget();
109 }
110
111 void
112 URL::CreateObjectURL(const GlobalObject& aGlobal,
113 nsIDOMBlob* aBlob,
114 const objectURLOptions& aOptions,
115 nsString& aResult,
116 ErrorResult& aError)
117 {
118 CreateObjectURLInternal(aGlobal, aBlob,
119 NS_LITERAL_CSTRING(BLOBURI_SCHEME), aOptions, aResult,
120 aError);
121 }
122
123 void
124 URL::CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream,
125 const mozilla::dom::objectURLOptions& aOptions,
126 nsString& aResult,
127 ErrorResult& aError)
128 {
129 CreateObjectURLInternal(aGlobal, &aStream,
130 NS_LITERAL_CSTRING(MEDIASTREAMURI_SCHEME), aOptions,
131 aResult, aError);
132 }
133
134 void
135 URL::CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource,
136 const objectURLOptions& aOptions,
137 nsString& aResult,
138 ErrorResult& aError)
139 {
140 CreateObjectURLInternal(aGlobal, &aSource,
141 NS_LITERAL_CSTRING(MEDIASOURCEURI_SCHEME), aOptions,
142 aResult, aError);
143 }
144
145 void
146 URL::CreateObjectURLInternal(const GlobalObject& aGlobal, nsISupports* aObject,
147 const nsACString& aScheme,
148 const objectURLOptions& aOptions,
149 nsString& aResult, ErrorResult& aError)
150 {
151 nsCOMPtr<nsIPrincipal> principal = nsContentUtils::GetObjectPrincipal(aGlobal.Get());
152
153 nsCString url;
154 nsresult rv = nsHostObjectProtocolHandler::AddDataEntry(aScheme, aObject,
155 principal, url);
156 if (NS_FAILED(rv)) {
157 aError.Throw(rv);
158 return;
159 }
160
161 nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal.GetAsSupports());
162 nsGlobalWindow* window = static_cast<nsGlobalWindow*>(w.get());
163
164 if (window) {
165 NS_PRECONDITION(window->IsInnerWindow(), "Should be inner window");
166
167 if (!window->GetExtantDoc()) {
168 aError.Throw(NS_ERROR_INVALID_POINTER);
169 return;
170 }
171
172 nsIDocument* doc = window->GetExtantDoc();
173 if (doc) {
174 doc->RegisterHostObjectUri(url);
175 }
176 }
177
178 CopyASCIItoUTF16(url, aResult);
179 }
180
181 void
182 URL::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL)
183 {
184 nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aGlobal.Get());
185
186 NS_LossyConvertUTF16toASCII asciiurl(aURL);
187
188 nsIPrincipal* urlPrincipal =
189 nsHostObjectProtocolHandler::GetDataEntryPrincipal(asciiurl);
190
191 if (urlPrincipal && principal->Subsumes(urlPrincipal)) {
192 nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal.GetAsSupports());
193 nsGlobalWindow* window = static_cast<nsGlobalWindow*>(w.get());
194
195 if (window && window->GetExtantDoc()) {
196 window->GetExtantDoc()->UnregisterHostObjectUri(asciiurl);
197 }
198 nsHostObjectProtocolHandler::RemoveDataEntry(asciiurl);
199 }
200 }
201
202 void
203 URL::GetHref(nsString& aHref) const
204 {
205 aHref.Truncate();
206
207 nsAutoCString href;
208 nsresult rv = mURI->GetSpec(href);
209 if (NS_SUCCEEDED(rv)) {
210 CopyUTF8toUTF16(href, aHref);
211 }
212 }
213
214 void
215 URL::SetHref(const nsAString& aHref, ErrorResult& aRv)
216 {
217 nsCString href = NS_ConvertUTF16toUTF8(aHref);
218
219 nsresult rv;
220 nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv));
221 if (NS_FAILED(rv)) {
222 aRv.Throw(rv);
223 return;
224 }
225
226 nsCOMPtr<nsIURI> uri;
227 rv = ioService->NewURI(href, nullptr, nullptr, getter_AddRefs(uri));
228 if (NS_FAILED(rv)) {
229 nsAutoString label(aHref);
230 aRv.ThrowTypeError(MSG_INVALID_URL, &label);
231 return;
232 }
233
234 mURI = uri;
235 UpdateURLSearchParams();
236 }
237
238 void
239 URL::GetOrigin(nsString& aOrigin) const
240 {
241 nsContentUtils::GetUTFNonNullOrigin(mURI, aOrigin);
242 }
243
244 void
245 URL::GetProtocol(nsString& aProtocol) const
246 {
247 nsCString protocol;
248 if (NS_SUCCEEDED(mURI->GetScheme(protocol))) {
249 aProtocol.Truncate();
250 }
251
252 CopyASCIItoUTF16(protocol, aProtocol);
253 aProtocol.Append(char16_t(':'));
254 }
255
256 void
257 URL::SetProtocol(const nsAString& aProtocol)
258 {
259 nsAString::const_iterator start, end;
260 aProtocol.BeginReading(start);
261 aProtocol.EndReading(end);
262 nsAString::const_iterator iter(start);
263
264 FindCharInReadable(':', iter, end);
265 mURI->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter)));
266 }
267
268 #define URL_GETTER( value, func ) \
269 value.Truncate(); \
270 nsAutoCString tmp; \
271 nsresult rv = mURI->func(tmp); \
272 if (NS_SUCCEEDED(rv)) { \
273 CopyUTF8toUTF16(tmp, value); \
274 }
275
276 void
277 URL::GetUsername(nsString& aUsername) const
278 {
279 URL_GETTER(aUsername, GetUsername);
280 }
281
282 void
283 URL::SetUsername(const nsAString& aUsername)
284 {
285 mURI->SetUsername(NS_ConvertUTF16toUTF8(aUsername));
286 }
287
288 void
289 URL::GetPassword(nsString& aPassword) const
290 {
291 URL_GETTER(aPassword, GetPassword);
292 }
293
294 void
295 URL::SetPassword(const nsAString& aPassword)
296 {
297 mURI->SetPassword(NS_ConvertUTF16toUTF8(aPassword));
298 }
299
300 void
301 URL::GetHost(nsString& aHost) const
302 {
303 URL_GETTER(aHost, GetHostPort);
304 }
305
306 void
307 URL::SetHost(const nsAString& aHost)
308 {
309 mURI->SetHostPort(NS_ConvertUTF16toUTF8(aHost));
310 }
311
312 void
313 URL::URLSearchParamsUpdated()
314 {
315 MOZ_ASSERT(mSearchParams);
316
317 nsAutoString search;
318 mSearchParams->Serialize(search);
319 SetSearchInternal(search);
320 }
321
322 void
323 URL::UpdateURLSearchParams()
324 {
325 if (!mSearchParams) {
326 return;
327 }
328
329 nsAutoCString search;
330 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
331 if (url) {
332 nsresult rv = url->GetQuery(search);
333 if (NS_FAILED(rv)) {
334 NS_WARNING("Failed to get the query from a nsIURL.");
335 }
336 }
337
338 mSearchParams->ParseInput(search, this);
339 }
340
341 void
342 URL::GetHostname(nsString& aHostname) const
343 {
344 URL_GETTER(aHostname, GetHost);
345 }
346
347 void
348 URL::SetHostname(const nsAString& aHostname)
349 {
350 // nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname
351 // The return code is silently ignored
352 mURI->SetHost(NS_ConvertUTF16toUTF8(aHostname));
353 }
354
355 void
356 URL::GetPort(nsString& aPort) const
357 {
358 aPort.Truncate();
359
360 int32_t port;
361 nsresult rv = mURI->GetPort(&port);
362 if (NS_SUCCEEDED(rv) && port != -1) {
363 nsAutoString portStr;
364 portStr.AppendInt(port, 10);
365 aPort.Assign(portStr);
366 }
367 }
368
369 void
370 URL::SetPort(const nsAString& aPort)
371 {
372 nsresult rv;
373 nsAutoString portStr(aPort);
374 int32_t port = -1;
375
376 // nsIURI uses -1 as default value.
377 if (!portStr.IsEmpty()) {
378 port = portStr.ToInteger(&rv);
379 if (NS_FAILED(rv)) {
380 return;
381 }
382 }
383
384 mURI->SetPort(port);
385 }
386
387 void
388 URL::GetPathname(nsString& aPathname) const
389 {
390 aPathname.Truncate();
391
392 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
393 if (!url) {
394 // Do not throw! Not having a valid URI or URL should result in an empty
395 // string.
396 return;
397 }
398
399 nsAutoCString file;
400 nsresult rv = url->GetFilePath(file);
401 if (NS_SUCCEEDED(rv)) {
402 CopyUTF8toUTF16(file, aPathname);
403 }
404 }
405
406 void
407 URL::SetPathname(const nsAString& aPathname)
408 {
409 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
410 if (!url) {
411 // Ignore failures to be compatible with NS4.
412 return;
413 }
414
415 url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname));
416 }
417
418 void
419 URL::GetSearch(nsString& aSearch) const
420 {
421 aSearch.Truncate();
422
423 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
424 if (!url) {
425 // Do not throw! Not having a valid URI or URL should result in an empty
426 // string.
427 return;
428 }
429
430 nsAutoCString search;
431 nsresult rv = url->GetQuery(search);
432 if (NS_SUCCEEDED(rv) && !search.IsEmpty()) {
433 CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch);
434 }
435 }
436
437 void
438 URL::SetSearch(const nsAString& aSearch)
439 {
440 SetSearchInternal(aSearch);
441 UpdateURLSearchParams();
442 }
443
444 void
445 URL::SetSearchInternal(const nsAString& aSearch)
446 {
447 nsCOMPtr<nsIURL> url(do_QueryInterface(mURI));
448 if (!url) {
449 // Ignore failures to be compatible with NS4.
450 return;
451 }
452
453 url->SetQuery(NS_ConvertUTF16toUTF8(aSearch));
454 }
455
456 URLSearchParams*
457 URL::SearchParams()
458 {
459 CreateSearchParamsIfNeeded();
460 return mSearchParams;
461 }
462
463 void
464 URL::SetSearchParams(URLSearchParams& aSearchParams)
465 {
466 if (mSearchParams) {
467 mSearchParams->RemoveObserver(this);
468 }
469
470 // the observer will be cleared using the cycle collector.
471 mSearchParams = &aSearchParams;
472 mSearchParams->AddObserver(this);
473
474 nsAutoString search;
475 mSearchParams->Serialize(search);
476 SetSearchInternal(search);
477 }
478
479 void
480 URL::GetHash(nsString& aHash) const
481 {
482 aHash.Truncate();
483
484 nsAutoCString ref;
485 nsresult rv = mURI->GetRef(ref);
486 if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) {
487 NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes!
488 aHash.Assign(char16_t('#'));
489 AppendUTF8toUTF16(ref, aHash);
490 }
491 }
492
493 void
494 URL::SetHash(const nsAString& aHash)
495 {
496 mURI->SetRef(NS_ConvertUTF16toUTF8(aHash));
497 }
498
499 bool IsChromeURI(nsIURI* aURI)
500 {
501 bool isChrome = false;
502 if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)))
503 return isChrome;
504 return false;
505 }
506
507 void
508 URL::CreateSearchParamsIfNeeded()
509 {
510 if (!mSearchParams) {
511 mSearchParams = new URLSearchParams();
512 mSearchParams->AddObserver(this);
513 UpdateURLSearchParams();
514 }
515 }
516
517 }
518 }

mercurial