1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/base/URL.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,518 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "URL.h" 1.10 + 1.11 +#include "nsGlobalWindow.h" 1.12 +#include "nsIDOMFile.h" 1.13 +#include "DOMMediaStream.h" 1.14 +#include "mozilla/dom/MediaSource.h" 1.15 +#include "mozilla/dom/URLBinding.h" 1.16 +#include "nsHostObjectProtocolHandler.h" 1.17 +#include "nsServiceManagerUtils.h" 1.18 +#include "nsIIOService.h" 1.19 +#include "nsEscape.h" 1.20 +#include "nsNetCID.h" 1.21 +#include "nsIURL.h" 1.22 + 1.23 +namespace mozilla { 1.24 +namespace dom { 1.25 + 1.26 +NS_IMPL_CYCLE_COLLECTION_CLASS(URL) 1.27 + 1.28 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(URL) 1.29 + if (tmp->mSearchParams) { 1.30 + tmp->mSearchParams->RemoveObserver(tmp); 1.31 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mSearchParams) 1.32 + } 1.33 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.34 + 1.35 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(URL) 1.36 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSearchParams) 1.37 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.38 + 1.39 +NS_IMPL_CYCLE_COLLECTING_ADDREF(URL) 1.40 +NS_IMPL_CYCLE_COLLECTING_RELEASE(URL) 1.41 + 1.42 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(URL) 1.43 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.44 +NS_INTERFACE_MAP_END 1.45 + 1.46 +URL::URL(nsIURI* aURI) 1.47 + : mURI(aURI) 1.48 +{ 1.49 +} 1.50 + 1.51 +JSObject* 1.52 +URL::WrapObject(JSContext* aCx) 1.53 +{ 1.54 + return URLBinding::Wrap(aCx, this); 1.55 +} 1.56 + 1.57 +/* static */ already_AddRefed<URL> 1.58 +URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl, 1.59 + URL& aBase, ErrorResult& aRv) 1.60 +{ 1.61 + nsresult rv; 1.62 + nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); 1.63 + if (NS_FAILED(rv)) { 1.64 + aRv.Throw(rv); 1.65 + return nullptr; 1.66 + } 1.67 + 1.68 + nsCOMPtr<nsIURI> uri; 1.69 + rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aUrl), nullptr, aBase.GetURI(), 1.70 + getter_AddRefs(uri)); 1.71 + if (NS_FAILED(rv)) { 1.72 + nsAutoString label(aUrl); 1.73 + aRv.ThrowTypeError(MSG_INVALID_URL, &label); 1.74 + return nullptr; 1.75 + } 1.76 + 1.77 + nsRefPtr<URL> url = new URL(uri); 1.78 + return url.forget(); 1.79 +} 1.80 + 1.81 +/* static */ already_AddRefed<URL> 1.82 +URL::Constructor(const GlobalObject& aGlobal, const nsAString& aUrl, 1.83 + const nsAString& aBase, ErrorResult& aRv) 1.84 +{ 1.85 + nsresult rv; 1.86 + nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); 1.87 + if (NS_FAILED(rv)) { 1.88 + aRv.Throw(rv); 1.89 + return nullptr; 1.90 + } 1.91 + 1.92 + nsCOMPtr<nsIURI> baseUri; 1.93 + rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aBase), nullptr, nullptr, 1.94 + getter_AddRefs(baseUri)); 1.95 + if (NS_FAILED(rv)) { 1.96 + nsAutoString label(aBase); 1.97 + aRv.ThrowTypeError(MSG_INVALID_URL, &label); 1.98 + return nullptr; 1.99 + } 1.100 + 1.101 + nsCOMPtr<nsIURI> uri; 1.102 + rv = ioService->NewURI(NS_ConvertUTF16toUTF8(aUrl), nullptr, baseUri, 1.103 + getter_AddRefs(uri)); 1.104 + if (NS_FAILED(rv)) { 1.105 + nsAutoString label(aUrl); 1.106 + aRv.ThrowTypeError(MSG_INVALID_URL, &label); 1.107 + return nullptr; 1.108 + } 1.109 + 1.110 + nsRefPtr<URL> url = new URL(uri); 1.111 + return url.forget(); 1.112 +} 1.113 + 1.114 +void 1.115 +URL::CreateObjectURL(const GlobalObject& aGlobal, 1.116 + nsIDOMBlob* aBlob, 1.117 + const objectURLOptions& aOptions, 1.118 + nsString& aResult, 1.119 + ErrorResult& aError) 1.120 +{ 1.121 + CreateObjectURLInternal(aGlobal, aBlob, 1.122 + NS_LITERAL_CSTRING(BLOBURI_SCHEME), aOptions, aResult, 1.123 + aError); 1.124 +} 1.125 + 1.126 +void 1.127 +URL::CreateObjectURL(const GlobalObject& aGlobal, DOMMediaStream& aStream, 1.128 + const mozilla::dom::objectURLOptions& aOptions, 1.129 + nsString& aResult, 1.130 + ErrorResult& aError) 1.131 +{ 1.132 + CreateObjectURLInternal(aGlobal, &aStream, 1.133 + NS_LITERAL_CSTRING(MEDIASTREAMURI_SCHEME), aOptions, 1.134 + aResult, aError); 1.135 +} 1.136 + 1.137 +void 1.138 +URL::CreateObjectURL(const GlobalObject& aGlobal, MediaSource& aSource, 1.139 + const objectURLOptions& aOptions, 1.140 + nsString& aResult, 1.141 + ErrorResult& aError) 1.142 +{ 1.143 + CreateObjectURLInternal(aGlobal, &aSource, 1.144 + NS_LITERAL_CSTRING(MEDIASOURCEURI_SCHEME), aOptions, 1.145 + aResult, aError); 1.146 +} 1.147 + 1.148 +void 1.149 +URL::CreateObjectURLInternal(const GlobalObject& aGlobal, nsISupports* aObject, 1.150 + const nsACString& aScheme, 1.151 + const objectURLOptions& aOptions, 1.152 + nsString& aResult, ErrorResult& aError) 1.153 +{ 1.154 + nsCOMPtr<nsIPrincipal> principal = nsContentUtils::GetObjectPrincipal(aGlobal.Get()); 1.155 + 1.156 + nsCString url; 1.157 + nsresult rv = nsHostObjectProtocolHandler::AddDataEntry(aScheme, aObject, 1.158 + principal, url); 1.159 + if (NS_FAILED(rv)) { 1.160 + aError.Throw(rv); 1.161 + return; 1.162 + } 1.163 + 1.164 + nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal.GetAsSupports()); 1.165 + nsGlobalWindow* window = static_cast<nsGlobalWindow*>(w.get()); 1.166 + 1.167 + if (window) { 1.168 + NS_PRECONDITION(window->IsInnerWindow(), "Should be inner window"); 1.169 + 1.170 + if (!window->GetExtantDoc()) { 1.171 + aError.Throw(NS_ERROR_INVALID_POINTER); 1.172 + return; 1.173 + } 1.174 + 1.175 + nsIDocument* doc = window->GetExtantDoc(); 1.176 + if (doc) { 1.177 + doc->RegisterHostObjectUri(url); 1.178 + } 1.179 + } 1.180 + 1.181 + CopyASCIItoUTF16(url, aResult); 1.182 +} 1.183 + 1.184 +void 1.185 +URL::RevokeObjectURL(const GlobalObject& aGlobal, const nsAString& aURL) 1.186 +{ 1.187 + nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(aGlobal.Get()); 1.188 + 1.189 + NS_LossyConvertUTF16toASCII asciiurl(aURL); 1.190 + 1.191 + nsIPrincipal* urlPrincipal = 1.192 + nsHostObjectProtocolHandler::GetDataEntryPrincipal(asciiurl); 1.193 + 1.194 + if (urlPrincipal && principal->Subsumes(urlPrincipal)) { 1.195 + nsCOMPtr<nsPIDOMWindow> w = do_QueryInterface(aGlobal.GetAsSupports()); 1.196 + nsGlobalWindow* window = static_cast<nsGlobalWindow*>(w.get()); 1.197 + 1.198 + if (window && window->GetExtantDoc()) { 1.199 + window->GetExtantDoc()->UnregisterHostObjectUri(asciiurl); 1.200 + } 1.201 + nsHostObjectProtocolHandler::RemoveDataEntry(asciiurl); 1.202 + } 1.203 +} 1.204 + 1.205 +void 1.206 +URL::GetHref(nsString& aHref) const 1.207 +{ 1.208 + aHref.Truncate(); 1.209 + 1.210 + nsAutoCString href; 1.211 + nsresult rv = mURI->GetSpec(href); 1.212 + if (NS_SUCCEEDED(rv)) { 1.213 + CopyUTF8toUTF16(href, aHref); 1.214 + } 1.215 +} 1.216 + 1.217 +void 1.218 +URL::SetHref(const nsAString& aHref, ErrorResult& aRv) 1.219 +{ 1.220 + nsCString href = NS_ConvertUTF16toUTF8(aHref); 1.221 + 1.222 + nsresult rv; 1.223 + nsCOMPtr<nsIIOService> ioService(do_GetService(NS_IOSERVICE_CONTRACTID, &rv)); 1.224 + if (NS_FAILED(rv)) { 1.225 + aRv.Throw(rv); 1.226 + return; 1.227 + } 1.228 + 1.229 + nsCOMPtr<nsIURI> uri; 1.230 + rv = ioService->NewURI(href, nullptr, nullptr, getter_AddRefs(uri)); 1.231 + if (NS_FAILED(rv)) { 1.232 + nsAutoString label(aHref); 1.233 + aRv.ThrowTypeError(MSG_INVALID_URL, &label); 1.234 + return; 1.235 + } 1.236 + 1.237 + mURI = uri; 1.238 + UpdateURLSearchParams(); 1.239 +} 1.240 + 1.241 +void 1.242 +URL::GetOrigin(nsString& aOrigin) const 1.243 +{ 1.244 + nsContentUtils::GetUTFNonNullOrigin(mURI, aOrigin); 1.245 +} 1.246 + 1.247 +void 1.248 +URL::GetProtocol(nsString& aProtocol) const 1.249 +{ 1.250 + nsCString protocol; 1.251 + if (NS_SUCCEEDED(mURI->GetScheme(protocol))) { 1.252 + aProtocol.Truncate(); 1.253 + } 1.254 + 1.255 + CopyASCIItoUTF16(protocol, aProtocol); 1.256 + aProtocol.Append(char16_t(':')); 1.257 +} 1.258 + 1.259 +void 1.260 +URL::SetProtocol(const nsAString& aProtocol) 1.261 +{ 1.262 + nsAString::const_iterator start, end; 1.263 + aProtocol.BeginReading(start); 1.264 + aProtocol.EndReading(end); 1.265 + nsAString::const_iterator iter(start); 1.266 + 1.267 + FindCharInReadable(':', iter, end); 1.268 + mURI->SetScheme(NS_ConvertUTF16toUTF8(Substring(start, iter))); 1.269 +} 1.270 + 1.271 +#define URL_GETTER( value, func ) \ 1.272 + value.Truncate(); \ 1.273 + nsAutoCString tmp; \ 1.274 + nsresult rv = mURI->func(tmp); \ 1.275 + if (NS_SUCCEEDED(rv)) { \ 1.276 + CopyUTF8toUTF16(tmp, value); \ 1.277 + } 1.278 + 1.279 +void 1.280 +URL::GetUsername(nsString& aUsername) const 1.281 +{ 1.282 + URL_GETTER(aUsername, GetUsername); 1.283 +} 1.284 + 1.285 +void 1.286 +URL::SetUsername(const nsAString& aUsername) 1.287 +{ 1.288 + mURI->SetUsername(NS_ConvertUTF16toUTF8(aUsername)); 1.289 +} 1.290 + 1.291 +void 1.292 +URL::GetPassword(nsString& aPassword) const 1.293 +{ 1.294 + URL_GETTER(aPassword, GetPassword); 1.295 +} 1.296 + 1.297 +void 1.298 +URL::SetPassword(const nsAString& aPassword) 1.299 +{ 1.300 + mURI->SetPassword(NS_ConvertUTF16toUTF8(aPassword)); 1.301 +} 1.302 + 1.303 +void 1.304 +URL::GetHost(nsString& aHost) const 1.305 +{ 1.306 + URL_GETTER(aHost, GetHostPort); 1.307 +} 1.308 + 1.309 +void 1.310 +URL::SetHost(const nsAString& aHost) 1.311 +{ 1.312 + mURI->SetHostPort(NS_ConvertUTF16toUTF8(aHost)); 1.313 +} 1.314 + 1.315 +void 1.316 +URL::URLSearchParamsUpdated() 1.317 +{ 1.318 + MOZ_ASSERT(mSearchParams); 1.319 + 1.320 + nsAutoString search; 1.321 + mSearchParams->Serialize(search); 1.322 + SetSearchInternal(search); 1.323 +} 1.324 + 1.325 +void 1.326 +URL::UpdateURLSearchParams() 1.327 +{ 1.328 + if (!mSearchParams) { 1.329 + return; 1.330 + } 1.331 + 1.332 + nsAutoCString search; 1.333 + nsCOMPtr<nsIURL> url(do_QueryInterface(mURI)); 1.334 + if (url) { 1.335 + nsresult rv = url->GetQuery(search); 1.336 + if (NS_FAILED(rv)) { 1.337 + NS_WARNING("Failed to get the query from a nsIURL."); 1.338 + } 1.339 + } 1.340 + 1.341 + mSearchParams->ParseInput(search, this); 1.342 +} 1.343 + 1.344 +void 1.345 +URL::GetHostname(nsString& aHostname) const 1.346 +{ 1.347 + URL_GETTER(aHostname, GetHost); 1.348 +} 1.349 + 1.350 +void 1.351 +URL::SetHostname(const nsAString& aHostname) 1.352 +{ 1.353 + // nsStandardURL returns NS_ERROR_UNEXPECTED for an empty hostname 1.354 + // The return code is silently ignored 1.355 + mURI->SetHost(NS_ConvertUTF16toUTF8(aHostname)); 1.356 +} 1.357 + 1.358 +void 1.359 +URL::GetPort(nsString& aPort) const 1.360 +{ 1.361 + aPort.Truncate(); 1.362 + 1.363 + int32_t port; 1.364 + nsresult rv = mURI->GetPort(&port); 1.365 + if (NS_SUCCEEDED(rv) && port != -1) { 1.366 + nsAutoString portStr; 1.367 + portStr.AppendInt(port, 10); 1.368 + aPort.Assign(portStr); 1.369 + } 1.370 +} 1.371 + 1.372 +void 1.373 +URL::SetPort(const nsAString& aPort) 1.374 +{ 1.375 + nsresult rv; 1.376 + nsAutoString portStr(aPort); 1.377 + int32_t port = -1; 1.378 + 1.379 + // nsIURI uses -1 as default value. 1.380 + if (!portStr.IsEmpty()) { 1.381 + port = portStr.ToInteger(&rv); 1.382 + if (NS_FAILED(rv)) { 1.383 + return; 1.384 + } 1.385 + } 1.386 + 1.387 + mURI->SetPort(port); 1.388 +} 1.389 + 1.390 +void 1.391 +URL::GetPathname(nsString& aPathname) const 1.392 +{ 1.393 + aPathname.Truncate(); 1.394 + 1.395 + nsCOMPtr<nsIURL> url(do_QueryInterface(mURI)); 1.396 + if (!url) { 1.397 + // Do not throw! Not having a valid URI or URL should result in an empty 1.398 + // string. 1.399 + return; 1.400 + } 1.401 + 1.402 + nsAutoCString file; 1.403 + nsresult rv = url->GetFilePath(file); 1.404 + if (NS_SUCCEEDED(rv)) { 1.405 + CopyUTF8toUTF16(file, aPathname); 1.406 + } 1.407 +} 1.408 + 1.409 +void 1.410 +URL::SetPathname(const nsAString& aPathname) 1.411 +{ 1.412 + nsCOMPtr<nsIURL> url(do_QueryInterface(mURI)); 1.413 + if (!url) { 1.414 + // Ignore failures to be compatible with NS4. 1.415 + return; 1.416 + } 1.417 + 1.418 + url->SetFilePath(NS_ConvertUTF16toUTF8(aPathname)); 1.419 +} 1.420 + 1.421 +void 1.422 +URL::GetSearch(nsString& aSearch) const 1.423 +{ 1.424 + aSearch.Truncate(); 1.425 + 1.426 + nsCOMPtr<nsIURL> url(do_QueryInterface(mURI)); 1.427 + if (!url) { 1.428 + // Do not throw! Not having a valid URI or URL should result in an empty 1.429 + // string. 1.430 + return; 1.431 + } 1.432 + 1.433 + nsAutoCString search; 1.434 + nsresult rv = url->GetQuery(search); 1.435 + if (NS_SUCCEEDED(rv) && !search.IsEmpty()) { 1.436 + CopyUTF8toUTF16(NS_LITERAL_CSTRING("?") + search, aSearch); 1.437 + } 1.438 +} 1.439 + 1.440 +void 1.441 +URL::SetSearch(const nsAString& aSearch) 1.442 +{ 1.443 + SetSearchInternal(aSearch); 1.444 + UpdateURLSearchParams(); 1.445 +} 1.446 + 1.447 +void 1.448 +URL::SetSearchInternal(const nsAString& aSearch) 1.449 +{ 1.450 + nsCOMPtr<nsIURL> url(do_QueryInterface(mURI)); 1.451 + if (!url) { 1.452 + // Ignore failures to be compatible with NS4. 1.453 + return; 1.454 + } 1.455 + 1.456 + url->SetQuery(NS_ConvertUTF16toUTF8(aSearch)); 1.457 +} 1.458 + 1.459 +URLSearchParams* 1.460 +URL::SearchParams() 1.461 +{ 1.462 + CreateSearchParamsIfNeeded(); 1.463 + return mSearchParams; 1.464 +} 1.465 + 1.466 +void 1.467 +URL::SetSearchParams(URLSearchParams& aSearchParams) 1.468 +{ 1.469 + if (mSearchParams) { 1.470 + mSearchParams->RemoveObserver(this); 1.471 + } 1.472 + 1.473 + // the observer will be cleared using the cycle collector. 1.474 + mSearchParams = &aSearchParams; 1.475 + mSearchParams->AddObserver(this); 1.476 + 1.477 + nsAutoString search; 1.478 + mSearchParams->Serialize(search); 1.479 + SetSearchInternal(search); 1.480 +} 1.481 + 1.482 +void 1.483 +URL::GetHash(nsString& aHash) const 1.484 +{ 1.485 + aHash.Truncate(); 1.486 + 1.487 + nsAutoCString ref; 1.488 + nsresult rv = mURI->GetRef(ref); 1.489 + if (NS_SUCCEEDED(rv) && !ref.IsEmpty()) { 1.490 + NS_UnescapeURL(ref); // XXX may result in random non-ASCII bytes! 1.491 + aHash.Assign(char16_t('#')); 1.492 + AppendUTF8toUTF16(ref, aHash); 1.493 + } 1.494 +} 1.495 + 1.496 +void 1.497 +URL::SetHash(const nsAString& aHash) 1.498 +{ 1.499 + mURI->SetRef(NS_ConvertUTF16toUTF8(aHash)); 1.500 +} 1.501 + 1.502 +bool IsChromeURI(nsIURI* aURI) 1.503 +{ 1.504 + bool isChrome = false; 1.505 + if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome))) 1.506 + return isChrome; 1.507 + return false; 1.508 +} 1.509 + 1.510 +void 1.511 +URL::CreateSearchParamsIfNeeded() 1.512 +{ 1.513 + if (!mSearchParams) { 1.514 + mSearchParams = new URLSearchParams(); 1.515 + mSearchParams->AddObserver(this); 1.516 + UpdateURLSearchParams(); 1.517 + } 1.518 +} 1.519 + 1.520 +} 1.521 +}