Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
michael@0 | 2 | /* vim:set ts=4 sw=4 sts=4 et cin: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #ifndef nsNetUtil_h__ |
michael@0 | 8 | #define nsNetUtil_h__ |
michael@0 | 9 | |
michael@0 | 10 | #include "nsError.h" |
michael@0 | 11 | #include "nsNetCID.h" |
michael@0 | 12 | #include "nsStringGlue.h" |
michael@0 | 13 | #include "nsMemory.h" |
michael@0 | 14 | #include "nsCOMPtr.h" |
michael@0 | 15 | #include "prio.h" // for read/write flags, permissions, etc. |
michael@0 | 16 | #include "nsHashKeys.h" |
michael@0 | 17 | |
michael@0 | 18 | #include "plstr.h" |
michael@0 | 19 | #include "nsIURI.h" |
michael@0 | 20 | #include "nsIStandardURL.h" |
michael@0 | 21 | #include "nsIURLParser.h" |
michael@0 | 22 | #include "nsIUUIDGenerator.h" |
michael@0 | 23 | #include "nsIInputStream.h" |
michael@0 | 24 | #include "nsIOutputStream.h" |
michael@0 | 25 | #include "nsISafeOutputStream.h" |
michael@0 | 26 | #include "nsIStreamListener.h" |
michael@0 | 27 | #include "nsIRequestObserverProxy.h" |
michael@0 | 28 | #include "nsISimpleStreamListener.h" |
michael@0 | 29 | #include "nsILoadGroup.h" |
michael@0 | 30 | #include "nsIInterfaceRequestor.h" |
michael@0 | 31 | #include "nsIInterfaceRequestorUtils.h" |
michael@0 | 32 | #include "nsIIOService.h" |
michael@0 | 33 | #include "nsIServiceManager.h" |
michael@0 | 34 | #include "nsIChannel.h" |
michael@0 | 35 | #include "nsChannelProperties.h" |
michael@0 | 36 | #include "nsIInputStreamChannel.h" |
michael@0 | 37 | #include "nsITransport.h" |
michael@0 | 38 | #include "nsIStreamTransportService.h" |
michael@0 | 39 | #include "nsIHttpChannel.h" |
michael@0 | 40 | #include "nsIDownloader.h" |
michael@0 | 41 | #include "nsIStreamLoader.h" |
michael@0 | 42 | #include "nsIUnicharStreamLoader.h" |
michael@0 | 43 | #include "nsIPipe.h" |
michael@0 | 44 | #include "nsIProtocolHandler.h" |
michael@0 | 45 | #include "nsIFileProtocolHandler.h" |
michael@0 | 46 | #include "nsIStringStream.h" |
michael@0 | 47 | #include "nsIFile.h" |
michael@0 | 48 | #include "nsIFileStreams.h" |
michael@0 | 49 | #include "nsIFileURL.h" |
michael@0 | 50 | #include "nsIProtocolProxyService.h" |
michael@0 | 51 | #include "nsIProxyInfo.h" |
michael@0 | 52 | #include "nsIFileStreams.h" |
michael@0 | 53 | #include "nsIBufferedStreams.h" |
michael@0 | 54 | #include "nsIInputStreamPump.h" |
michael@0 | 55 | #include "nsIAsyncStreamCopier.h" |
michael@0 | 56 | #include "nsIPersistentProperties2.h" |
michael@0 | 57 | #include "nsISyncStreamListener.h" |
michael@0 | 58 | #include "nsInterfaceRequestorAgg.h" |
michael@0 | 59 | #include "nsINetUtil.h" |
michael@0 | 60 | #include "nsIURIWithPrincipal.h" |
michael@0 | 61 | #include "nsIAuthPrompt.h" |
michael@0 | 62 | #include "nsIAuthPrompt2.h" |
michael@0 | 63 | #include "nsIAuthPromptAdapterFactory.h" |
michael@0 | 64 | #include "nsComponentManagerUtils.h" |
michael@0 | 65 | #include "nsServiceManagerUtils.h" |
michael@0 | 66 | #include "nsINestedURI.h" |
michael@0 | 67 | #include "nsIMutable.h" |
michael@0 | 68 | #include "nsIPropertyBag2.h" |
michael@0 | 69 | #include "nsIWritablePropertyBag2.h" |
michael@0 | 70 | #include "nsIIDNService.h" |
michael@0 | 71 | #include "nsIChannelEventSink.h" |
michael@0 | 72 | #include "nsIChannelPolicy.h" |
michael@0 | 73 | #include "nsISocketProviderService.h" |
michael@0 | 74 | #include "nsISocketProvider.h" |
michael@0 | 75 | #include "nsIRedirectChannelRegistrar.h" |
michael@0 | 76 | #include "nsIMIMEHeaderParam.h" |
michael@0 | 77 | #include "nsILoadContext.h" |
michael@0 | 78 | #include "mozilla/Services.h" |
michael@0 | 79 | #include "nsIPrivateBrowsingChannel.h" |
michael@0 | 80 | #include "mozIApplicationClearPrivateDataParams.h" |
michael@0 | 81 | #include "nsIOfflineCacheUpdate.h" |
michael@0 | 82 | #include "nsIContentSniffer.h" |
michael@0 | 83 | #include "nsCategoryCache.h" |
michael@0 | 84 | #include "nsStringStream.h" |
michael@0 | 85 | #include "nsIViewSourceChannel.h" |
michael@0 | 86 | |
michael@0 | 87 | #include <limits> |
michael@0 | 88 | |
michael@0 | 89 | #ifdef MOZILLA_INTERNAL_API |
michael@0 | 90 | |
michael@0 | 91 | #include "nsReadableUtils.h" |
michael@0 | 92 | |
michael@0 | 93 | inline already_AddRefed<nsIIOService> |
michael@0 | 94 | do_GetIOService(nsresult* error = 0) |
michael@0 | 95 | { |
michael@0 | 96 | nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService(); |
michael@0 | 97 | if (error) |
michael@0 | 98 | *error = io ? NS_OK : NS_ERROR_FAILURE; |
michael@0 | 99 | return io.forget(); |
michael@0 | 100 | } |
michael@0 | 101 | |
michael@0 | 102 | inline already_AddRefed<nsINetUtil> |
michael@0 | 103 | do_GetNetUtil(nsresult *error = 0) |
michael@0 | 104 | { |
michael@0 | 105 | nsCOMPtr<nsIIOService> io = mozilla::services::GetIOService(); |
michael@0 | 106 | nsCOMPtr<nsINetUtil> util; |
michael@0 | 107 | if (io) |
michael@0 | 108 | util = do_QueryInterface(io); |
michael@0 | 109 | |
michael@0 | 110 | if (error) |
michael@0 | 111 | *error = !!util ? NS_OK : NS_ERROR_FAILURE; |
michael@0 | 112 | return util.forget(); |
michael@0 | 113 | } |
michael@0 | 114 | #else |
michael@0 | 115 | // Helper, to simplify getting the I/O service. |
michael@0 | 116 | inline const nsGetServiceByContractIDWithError |
michael@0 | 117 | do_GetIOService(nsresult* error = 0) |
michael@0 | 118 | { |
michael@0 | 119 | return nsGetServiceByContractIDWithError(NS_IOSERVICE_CONTRACTID, error); |
michael@0 | 120 | } |
michael@0 | 121 | |
michael@0 | 122 | // An alias to do_GetIOService |
michael@0 | 123 | inline const nsGetServiceByContractIDWithError |
michael@0 | 124 | do_GetNetUtil(nsresult* error = 0) |
michael@0 | 125 | { |
michael@0 | 126 | return do_GetIOService(error); |
michael@0 | 127 | } |
michael@0 | 128 | #endif |
michael@0 | 129 | |
michael@0 | 130 | // private little helper function... don't call this directly! |
michael@0 | 131 | inline nsresult |
michael@0 | 132 | net_EnsureIOService(nsIIOService **ios, nsCOMPtr<nsIIOService> &grip) |
michael@0 | 133 | { |
michael@0 | 134 | nsresult rv = NS_OK; |
michael@0 | 135 | if (!*ios) { |
michael@0 | 136 | grip = do_GetIOService(&rv); |
michael@0 | 137 | *ios = grip; |
michael@0 | 138 | } |
michael@0 | 139 | return rv; |
michael@0 | 140 | } |
michael@0 | 141 | |
michael@0 | 142 | inline nsresult |
michael@0 | 143 | NS_NewURI(nsIURI **result, |
michael@0 | 144 | const nsACString &spec, |
michael@0 | 145 | const char *charset = nullptr, |
michael@0 | 146 | nsIURI *baseURI = nullptr, |
michael@0 | 147 | nsIIOService *ioService = nullptr) // pass in nsIIOService to optimize callers |
michael@0 | 148 | { |
michael@0 | 149 | nsresult rv; |
michael@0 | 150 | nsCOMPtr<nsIIOService> grip; |
michael@0 | 151 | rv = net_EnsureIOService(&ioService, grip); |
michael@0 | 152 | if (ioService) |
michael@0 | 153 | rv = ioService->NewURI(spec, charset, baseURI, result); |
michael@0 | 154 | return rv; |
michael@0 | 155 | } |
michael@0 | 156 | |
michael@0 | 157 | inline nsresult |
michael@0 | 158 | NS_NewURI(nsIURI* *result, |
michael@0 | 159 | const nsAString& spec, |
michael@0 | 160 | const char *charset = nullptr, |
michael@0 | 161 | nsIURI* baseURI = nullptr, |
michael@0 | 162 | nsIIOService* ioService = nullptr) // pass in nsIIOService to optimize callers |
michael@0 | 163 | { |
michael@0 | 164 | return NS_NewURI(result, NS_ConvertUTF16toUTF8(spec), charset, baseURI, ioService); |
michael@0 | 165 | } |
michael@0 | 166 | |
michael@0 | 167 | inline nsresult |
michael@0 | 168 | NS_NewURI(nsIURI* *result, |
michael@0 | 169 | const char *spec, |
michael@0 | 170 | nsIURI* baseURI = nullptr, |
michael@0 | 171 | nsIIOService* ioService = nullptr) // pass in nsIIOService to optimize callers |
michael@0 | 172 | { |
michael@0 | 173 | return NS_NewURI(result, nsDependentCString(spec), nullptr, baseURI, ioService); |
michael@0 | 174 | } |
michael@0 | 175 | |
michael@0 | 176 | inline nsresult |
michael@0 | 177 | NS_NewFileURI(nsIURI* *result, |
michael@0 | 178 | nsIFile* spec, |
michael@0 | 179 | nsIIOService* ioService = nullptr) // pass in nsIIOService to optimize callers |
michael@0 | 180 | { |
michael@0 | 181 | nsresult rv; |
michael@0 | 182 | nsCOMPtr<nsIIOService> grip; |
michael@0 | 183 | rv = net_EnsureIOService(&ioService, grip); |
michael@0 | 184 | if (ioService) |
michael@0 | 185 | rv = ioService->NewFileURI(spec, result); |
michael@0 | 186 | return rv; |
michael@0 | 187 | } |
michael@0 | 188 | |
michael@0 | 189 | inline nsresult |
michael@0 | 190 | NS_NewChannel(nsIChannel **result, |
michael@0 | 191 | nsIURI *uri, |
michael@0 | 192 | nsIIOService *ioService = nullptr, // pass in nsIIOService to optimize callers |
michael@0 | 193 | nsILoadGroup *loadGroup = nullptr, |
michael@0 | 194 | nsIInterfaceRequestor *callbacks = nullptr, |
michael@0 | 195 | uint32_t loadFlags = nsIRequest::LOAD_NORMAL, |
michael@0 | 196 | nsIChannelPolicy *channelPolicy = nullptr) |
michael@0 | 197 | { |
michael@0 | 198 | nsresult rv; |
michael@0 | 199 | nsCOMPtr<nsIIOService> grip; |
michael@0 | 200 | rv = net_EnsureIOService(&ioService, grip); |
michael@0 | 201 | if (ioService) { |
michael@0 | 202 | nsCOMPtr<nsIChannel> chan; |
michael@0 | 203 | rv = ioService->NewChannelFromURI(uri, getter_AddRefs(chan)); |
michael@0 | 204 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 205 | if (loadGroup) { |
michael@0 | 206 | rv = chan->SetLoadGroup(loadGroup); |
michael@0 | 207 | } |
michael@0 | 208 | if (callbacks) { |
michael@0 | 209 | nsresult tmp = chan->SetNotificationCallbacks(callbacks); |
michael@0 | 210 | if (NS_FAILED(tmp)) { |
michael@0 | 211 | rv = tmp; |
michael@0 | 212 | } |
michael@0 | 213 | } |
michael@0 | 214 | if (loadFlags != nsIRequest::LOAD_NORMAL) { |
michael@0 | 215 | // Retain the LOAD_REPLACE load flag if set. |
michael@0 | 216 | nsLoadFlags normalLoadFlags = 0; |
michael@0 | 217 | chan->GetLoadFlags(&normalLoadFlags); |
michael@0 | 218 | nsresult tmp = chan->SetLoadFlags(loadFlags | |
michael@0 | 219 | (normalLoadFlags & |
michael@0 | 220 | nsIChannel::LOAD_REPLACE)); |
michael@0 | 221 | if (NS_FAILED(tmp)) { |
michael@0 | 222 | rv = tmp; |
michael@0 | 223 | } |
michael@0 | 224 | } |
michael@0 | 225 | if (channelPolicy) { |
michael@0 | 226 | nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(chan); |
michael@0 | 227 | if (props) { |
michael@0 | 228 | props->SetPropertyAsInterface(NS_CHANNEL_PROP_CHANNEL_POLICY, |
michael@0 | 229 | channelPolicy); |
michael@0 | 230 | } |
michael@0 | 231 | } |
michael@0 | 232 | if (NS_SUCCEEDED(rv)) |
michael@0 | 233 | chan.forget(result); |
michael@0 | 234 | } |
michael@0 | 235 | } |
michael@0 | 236 | return rv; |
michael@0 | 237 | } |
michael@0 | 238 | |
michael@0 | 239 | // Use this function with CAUTION. It creates a stream that blocks when you |
michael@0 | 240 | // Read() from it and blocking the UI thread is a bad idea. If you don't want |
michael@0 | 241 | // to implement a full blown asynchronous consumer (via nsIStreamListener) look |
michael@0 | 242 | // at nsIStreamLoader instead. |
michael@0 | 243 | inline nsresult |
michael@0 | 244 | NS_OpenURI(nsIInputStream **result, |
michael@0 | 245 | nsIURI *uri, |
michael@0 | 246 | nsIIOService *ioService = nullptr, // pass in nsIIOService to optimize callers |
michael@0 | 247 | nsILoadGroup *loadGroup = nullptr, |
michael@0 | 248 | nsIInterfaceRequestor *callbacks = nullptr, |
michael@0 | 249 | uint32_t loadFlags = nsIRequest::LOAD_NORMAL, |
michael@0 | 250 | nsIChannel **channelOut = nullptr) |
michael@0 | 251 | { |
michael@0 | 252 | nsresult rv; |
michael@0 | 253 | nsCOMPtr<nsIChannel> channel; |
michael@0 | 254 | rv = NS_NewChannel(getter_AddRefs(channel), uri, ioService, |
michael@0 | 255 | loadGroup, callbacks, loadFlags); |
michael@0 | 256 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 257 | nsIInputStream *stream; |
michael@0 | 258 | rv = channel->Open(&stream); |
michael@0 | 259 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 260 | *result = stream; |
michael@0 | 261 | if (channelOut) { |
michael@0 | 262 | *channelOut = nullptr; |
michael@0 | 263 | channel.swap(*channelOut); |
michael@0 | 264 | } |
michael@0 | 265 | } |
michael@0 | 266 | } |
michael@0 | 267 | return rv; |
michael@0 | 268 | } |
michael@0 | 269 | |
michael@0 | 270 | inline nsresult |
michael@0 | 271 | NS_OpenURI(nsIStreamListener *listener, |
michael@0 | 272 | nsISupports *context, |
michael@0 | 273 | nsIURI *uri, |
michael@0 | 274 | nsIIOService *ioService = nullptr, // pass in nsIIOService to optimize callers |
michael@0 | 275 | nsILoadGroup *loadGroup = nullptr, |
michael@0 | 276 | nsIInterfaceRequestor *callbacks = nullptr, |
michael@0 | 277 | uint32_t loadFlags = nsIRequest::LOAD_NORMAL) |
michael@0 | 278 | { |
michael@0 | 279 | nsresult rv; |
michael@0 | 280 | nsCOMPtr<nsIChannel> channel; |
michael@0 | 281 | rv = NS_NewChannel(getter_AddRefs(channel), uri, ioService, |
michael@0 | 282 | loadGroup, callbacks, loadFlags); |
michael@0 | 283 | if (NS_SUCCEEDED(rv)) |
michael@0 | 284 | rv = channel->AsyncOpen(listener, context); |
michael@0 | 285 | return rv; |
michael@0 | 286 | } |
michael@0 | 287 | |
michael@0 | 288 | inline nsresult |
michael@0 | 289 | NS_MakeAbsoluteURI(nsACString &result, |
michael@0 | 290 | const nsACString &spec, |
michael@0 | 291 | nsIURI *baseURI) |
michael@0 | 292 | { |
michael@0 | 293 | nsresult rv; |
michael@0 | 294 | if (!baseURI) { |
michael@0 | 295 | NS_WARNING("It doesn't make sense to not supply a base URI"); |
michael@0 | 296 | result = spec; |
michael@0 | 297 | rv = NS_OK; |
michael@0 | 298 | } |
michael@0 | 299 | else if (spec.IsEmpty()) |
michael@0 | 300 | rv = baseURI->GetSpec(result); |
michael@0 | 301 | else |
michael@0 | 302 | rv = baseURI->Resolve(spec, result); |
michael@0 | 303 | return rv; |
michael@0 | 304 | } |
michael@0 | 305 | |
michael@0 | 306 | inline nsresult |
michael@0 | 307 | NS_MakeAbsoluteURI(char **result, |
michael@0 | 308 | const char *spec, |
michael@0 | 309 | nsIURI *baseURI) |
michael@0 | 310 | { |
michael@0 | 311 | nsresult rv; |
michael@0 | 312 | nsAutoCString resultBuf; |
michael@0 | 313 | rv = NS_MakeAbsoluteURI(resultBuf, nsDependentCString(spec), baseURI); |
michael@0 | 314 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 315 | *result = ToNewCString(resultBuf); |
michael@0 | 316 | if (!*result) |
michael@0 | 317 | rv = NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 318 | } |
michael@0 | 319 | return rv; |
michael@0 | 320 | } |
michael@0 | 321 | |
michael@0 | 322 | inline nsresult |
michael@0 | 323 | NS_MakeAbsoluteURI(nsAString &result, |
michael@0 | 324 | const nsAString &spec, |
michael@0 | 325 | nsIURI *baseURI) |
michael@0 | 326 | { |
michael@0 | 327 | nsresult rv; |
michael@0 | 328 | if (!baseURI) { |
michael@0 | 329 | NS_WARNING("It doesn't make sense to not supply a base URI"); |
michael@0 | 330 | result = spec; |
michael@0 | 331 | rv = NS_OK; |
michael@0 | 332 | } |
michael@0 | 333 | else { |
michael@0 | 334 | nsAutoCString resultBuf; |
michael@0 | 335 | if (spec.IsEmpty()) |
michael@0 | 336 | rv = baseURI->GetSpec(resultBuf); |
michael@0 | 337 | else |
michael@0 | 338 | rv = baseURI->Resolve(NS_ConvertUTF16toUTF8(spec), resultBuf); |
michael@0 | 339 | if (NS_SUCCEEDED(rv)) |
michael@0 | 340 | CopyUTF8toUTF16(resultBuf, result); |
michael@0 | 341 | } |
michael@0 | 342 | return rv; |
michael@0 | 343 | } |
michael@0 | 344 | |
michael@0 | 345 | /** |
michael@0 | 346 | * This function is a helper function to get a scheme's default port. |
michael@0 | 347 | */ |
michael@0 | 348 | inline int32_t |
michael@0 | 349 | NS_GetDefaultPort(const char *scheme, |
michael@0 | 350 | nsIIOService* ioService = nullptr) |
michael@0 | 351 | { |
michael@0 | 352 | nsresult rv; |
michael@0 | 353 | |
michael@0 | 354 | nsCOMPtr<nsIIOService> grip; |
michael@0 | 355 | net_EnsureIOService(&ioService, grip); |
michael@0 | 356 | if (!ioService) |
michael@0 | 357 | return -1; |
michael@0 | 358 | |
michael@0 | 359 | nsCOMPtr<nsIProtocolHandler> handler; |
michael@0 | 360 | rv = ioService->GetProtocolHandler(scheme, getter_AddRefs(handler)); |
michael@0 | 361 | if (NS_FAILED(rv)) |
michael@0 | 362 | return -1; |
michael@0 | 363 | int32_t port; |
michael@0 | 364 | rv = handler->GetDefaultPort(&port); |
michael@0 | 365 | return NS_SUCCEEDED(rv) ? port : -1; |
michael@0 | 366 | } |
michael@0 | 367 | |
michael@0 | 368 | /** |
michael@0 | 369 | * This function is a helper function to apply the ToAscii conversion |
michael@0 | 370 | * to a string |
michael@0 | 371 | */ |
michael@0 | 372 | inline bool |
michael@0 | 373 | NS_StringToACE(const nsACString &idn, nsACString &result) |
michael@0 | 374 | { |
michael@0 | 375 | nsCOMPtr<nsIIDNService> idnSrv = do_GetService(NS_IDNSERVICE_CONTRACTID); |
michael@0 | 376 | if (!idnSrv) |
michael@0 | 377 | return false; |
michael@0 | 378 | nsresult rv = idnSrv->ConvertUTF8toACE(idn, result); |
michael@0 | 379 | if (NS_FAILED(rv)) |
michael@0 | 380 | return false; |
michael@0 | 381 | |
michael@0 | 382 | return true; |
michael@0 | 383 | } |
michael@0 | 384 | |
michael@0 | 385 | /** |
michael@0 | 386 | * This function is a helper function to get a protocol's default port if the |
michael@0 | 387 | * URI does not specify a port explicitly. Returns -1 if this protocol has no |
michael@0 | 388 | * concept of ports or if there was an error getting the port. |
michael@0 | 389 | */ |
michael@0 | 390 | inline int32_t |
michael@0 | 391 | NS_GetRealPort(nsIURI* aURI) |
michael@0 | 392 | { |
michael@0 | 393 | int32_t port; |
michael@0 | 394 | nsresult rv = aURI->GetPort(&port); |
michael@0 | 395 | if (NS_FAILED(rv)) |
michael@0 | 396 | return -1; |
michael@0 | 397 | |
michael@0 | 398 | if (port != -1) |
michael@0 | 399 | return port; // explicitly specified |
michael@0 | 400 | |
michael@0 | 401 | // Otherwise, we have to get the default port from the protocol handler |
michael@0 | 402 | |
michael@0 | 403 | // Need the scheme first |
michael@0 | 404 | nsAutoCString scheme; |
michael@0 | 405 | rv = aURI->GetScheme(scheme); |
michael@0 | 406 | if (NS_FAILED(rv)) |
michael@0 | 407 | return -1; |
michael@0 | 408 | |
michael@0 | 409 | return NS_GetDefaultPort(scheme.get()); |
michael@0 | 410 | } |
michael@0 | 411 | |
michael@0 | 412 | inline nsresult |
michael@0 | 413 | NS_NewInputStreamChannel(nsIChannel **result, |
michael@0 | 414 | nsIURI *uri, |
michael@0 | 415 | nsIInputStream *stream, |
michael@0 | 416 | const nsACString &contentType, |
michael@0 | 417 | const nsACString *contentCharset) |
michael@0 | 418 | { |
michael@0 | 419 | nsresult rv; |
michael@0 | 420 | nsCOMPtr<nsIInputStreamChannel> isc = |
michael@0 | 421 | do_CreateInstance(NS_INPUTSTREAMCHANNEL_CONTRACTID, &rv); |
michael@0 | 422 | if (NS_FAILED(rv)) |
michael@0 | 423 | return rv; |
michael@0 | 424 | rv = isc->SetURI(uri); |
michael@0 | 425 | nsresult tmp = isc->SetContentStream(stream); |
michael@0 | 426 | if (NS_FAILED(tmp)) { |
michael@0 | 427 | rv = tmp; |
michael@0 | 428 | } |
michael@0 | 429 | if (NS_FAILED(rv)) |
michael@0 | 430 | return rv; |
michael@0 | 431 | nsCOMPtr<nsIChannel> chan = do_QueryInterface(isc, &rv); |
michael@0 | 432 | if (NS_FAILED(rv)) |
michael@0 | 433 | return rv; |
michael@0 | 434 | if (!contentType.IsEmpty()) |
michael@0 | 435 | rv = chan->SetContentType(contentType); |
michael@0 | 436 | if (contentCharset && !contentCharset->IsEmpty()) { |
michael@0 | 437 | tmp = chan->SetContentCharset(*contentCharset); |
michael@0 | 438 | if (NS_FAILED(tmp)) { |
michael@0 | 439 | rv = tmp; |
michael@0 | 440 | } |
michael@0 | 441 | } |
michael@0 | 442 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 443 | *result = nullptr; |
michael@0 | 444 | chan.swap(*result); |
michael@0 | 445 | } |
michael@0 | 446 | return rv; |
michael@0 | 447 | } |
michael@0 | 448 | |
michael@0 | 449 | inline nsresult |
michael@0 | 450 | NS_NewInputStreamChannel(nsIChannel **result, |
michael@0 | 451 | nsIURI *uri, |
michael@0 | 452 | nsIInputStream *stream, |
michael@0 | 453 | const nsACString &contentType = EmptyCString()) |
michael@0 | 454 | { |
michael@0 | 455 | return NS_NewInputStreamChannel(result, uri, stream, contentType, nullptr); |
michael@0 | 456 | } |
michael@0 | 457 | |
michael@0 | 458 | inline nsresult |
michael@0 | 459 | NS_NewInputStreamChannel(nsIChannel **result, |
michael@0 | 460 | nsIURI *uri, |
michael@0 | 461 | nsIInputStream *stream, |
michael@0 | 462 | const nsACString &contentType, |
michael@0 | 463 | const nsACString &contentCharset) |
michael@0 | 464 | { |
michael@0 | 465 | return NS_NewInputStreamChannel(result, uri, stream, contentType, |
michael@0 | 466 | &contentCharset); |
michael@0 | 467 | } |
michael@0 | 468 | |
michael@0 | 469 | inline nsresult |
michael@0 | 470 | NS_NewInputStreamChannel(nsIChannel **result, |
michael@0 | 471 | nsIURI *uri, |
michael@0 | 472 | const nsAString &data, |
michael@0 | 473 | const nsACString &contentType, |
michael@0 | 474 | bool isSrcdocChannel = false) |
michael@0 | 475 | { |
michael@0 | 476 | |
michael@0 | 477 | nsresult rv; |
michael@0 | 478 | |
michael@0 | 479 | nsCOMPtr<nsIStringInputStream> stream; |
michael@0 | 480 | stream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv); |
michael@0 | 481 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 482 | |
michael@0 | 483 | #ifdef MOZILLA_INTERNAL_API |
michael@0 | 484 | uint32_t len; |
michael@0 | 485 | char* utf8Bytes = ToNewUTF8String(data, &len); |
michael@0 | 486 | rv = stream->AdoptData(utf8Bytes, len); |
michael@0 | 487 | #else |
michael@0 | 488 | char* utf8Bytes = ToNewUTF8String(data); |
michael@0 | 489 | rv = stream->AdoptData(utf8Bytes, strlen(utf8Bytes)); |
michael@0 | 490 | #endif |
michael@0 | 491 | |
michael@0 | 492 | nsCOMPtr<nsIChannel> chan; |
michael@0 | 493 | |
michael@0 | 494 | rv = NS_NewInputStreamChannel(getter_AddRefs(chan), uri, stream, |
michael@0 | 495 | contentType, NS_LITERAL_CSTRING("UTF-8")); |
michael@0 | 496 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 497 | |
michael@0 | 498 | if (isSrcdocChannel) { |
michael@0 | 499 | nsCOMPtr<nsIInputStreamChannel> inStrmChan = do_QueryInterface(chan); |
michael@0 | 500 | NS_ENSURE_TRUE(inStrmChan, NS_ERROR_FAILURE); |
michael@0 | 501 | inStrmChan->SetSrcdocData(data); |
michael@0 | 502 | } |
michael@0 | 503 | |
michael@0 | 504 | *result = nullptr; |
michael@0 | 505 | chan.swap(*result); |
michael@0 | 506 | |
michael@0 | 507 | return NS_OK; |
michael@0 | 508 | } |
michael@0 | 509 | |
michael@0 | 510 | inline nsresult |
michael@0 | 511 | NS_NewInputStreamPump(nsIInputStreamPump **result, |
michael@0 | 512 | nsIInputStream *stream, |
michael@0 | 513 | int64_t streamPos = int64_t(-1), |
michael@0 | 514 | int64_t streamLen = int64_t(-1), |
michael@0 | 515 | uint32_t segsize = 0, |
michael@0 | 516 | uint32_t segcount = 0, |
michael@0 | 517 | bool closeWhenDone = false) |
michael@0 | 518 | { |
michael@0 | 519 | nsresult rv; |
michael@0 | 520 | nsCOMPtr<nsIInputStreamPump> pump = |
michael@0 | 521 | do_CreateInstance(NS_INPUTSTREAMPUMP_CONTRACTID, &rv); |
michael@0 | 522 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 523 | rv = pump->Init(stream, streamPos, streamLen, |
michael@0 | 524 | segsize, segcount, closeWhenDone); |
michael@0 | 525 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 526 | *result = nullptr; |
michael@0 | 527 | pump.swap(*result); |
michael@0 | 528 | } |
michael@0 | 529 | } |
michael@0 | 530 | return rv; |
michael@0 | 531 | } |
michael@0 | 532 | |
michael@0 | 533 | // NOTE: you will need to specify whether or not your streams are buffered |
michael@0 | 534 | // (i.e., do they implement ReadSegments/WriteSegments). the default |
michael@0 | 535 | // assumption of TRUE for both streams might not be right for you! |
michael@0 | 536 | inline nsresult |
michael@0 | 537 | NS_NewAsyncStreamCopier(nsIAsyncStreamCopier **result, |
michael@0 | 538 | nsIInputStream *source, |
michael@0 | 539 | nsIOutputStream *sink, |
michael@0 | 540 | nsIEventTarget *target, |
michael@0 | 541 | bool sourceBuffered = true, |
michael@0 | 542 | bool sinkBuffered = true, |
michael@0 | 543 | uint32_t chunkSize = 0, |
michael@0 | 544 | bool closeSource = true, |
michael@0 | 545 | bool closeSink = true) |
michael@0 | 546 | { |
michael@0 | 547 | nsresult rv; |
michael@0 | 548 | nsCOMPtr<nsIAsyncStreamCopier> copier = |
michael@0 | 549 | do_CreateInstance(NS_ASYNCSTREAMCOPIER_CONTRACTID, &rv); |
michael@0 | 550 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 551 | rv = copier->Init(source, sink, target, sourceBuffered, sinkBuffered, |
michael@0 | 552 | chunkSize, closeSource, closeSink); |
michael@0 | 553 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 554 | *result = nullptr; |
michael@0 | 555 | copier.swap(*result); |
michael@0 | 556 | } |
michael@0 | 557 | } |
michael@0 | 558 | return rv; |
michael@0 | 559 | } |
michael@0 | 560 | |
michael@0 | 561 | inline nsresult |
michael@0 | 562 | NS_NewLoadGroup(nsILoadGroup **result, |
michael@0 | 563 | nsIRequestObserver *obs) |
michael@0 | 564 | { |
michael@0 | 565 | nsresult rv; |
michael@0 | 566 | nsCOMPtr<nsILoadGroup> group = |
michael@0 | 567 | do_CreateInstance(NS_LOADGROUP_CONTRACTID, &rv); |
michael@0 | 568 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 569 | rv = group->SetGroupObserver(obs); |
michael@0 | 570 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 571 | *result = nullptr; |
michael@0 | 572 | group.swap(*result); |
michael@0 | 573 | } |
michael@0 | 574 | } |
michael@0 | 575 | return rv; |
michael@0 | 576 | } |
michael@0 | 577 | |
michael@0 | 578 | inline nsresult |
michael@0 | 579 | NS_NewDownloader(nsIStreamListener **result, |
michael@0 | 580 | nsIDownloadObserver *observer, |
michael@0 | 581 | nsIFile *downloadLocation = nullptr) |
michael@0 | 582 | { |
michael@0 | 583 | nsresult rv; |
michael@0 | 584 | nsCOMPtr<nsIDownloader> downloader = |
michael@0 | 585 | do_CreateInstance(NS_DOWNLOADER_CONTRACTID, &rv); |
michael@0 | 586 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 587 | rv = downloader->Init(observer, downloadLocation); |
michael@0 | 588 | if (NS_SUCCEEDED(rv)) |
michael@0 | 589 | NS_ADDREF(*result = downloader); |
michael@0 | 590 | } |
michael@0 | 591 | return rv; |
michael@0 | 592 | } |
michael@0 | 593 | |
michael@0 | 594 | inline nsresult |
michael@0 | 595 | NS_NewStreamLoader(nsIStreamLoader **result, |
michael@0 | 596 | nsIStreamLoaderObserver *observer) |
michael@0 | 597 | { |
michael@0 | 598 | nsresult rv; |
michael@0 | 599 | nsCOMPtr<nsIStreamLoader> loader = |
michael@0 | 600 | do_CreateInstance(NS_STREAMLOADER_CONTRACTID, &rv); |
michael@0 | 601 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 602 | rv = loader->Init(observer); |
michael@0 | 603 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 604 | *result = nullptr; |
michael@0 | 605 | loader.swap(*result); |
michael@0 | 606 | } |
michael@0 | 607 | } |
michael@0 | 608 | return rv; |
michael@0 | 609 | } |
michael@0 | 610 | |
michael@0 | 611 | inline nsresult |
michael@0 | 612 | NS_NewStreamLoader(nsIStreamLoader **result, |
michael@0 | 613 | nsIURI *uri, |
michael@0 | 614 | nsIStreamLoaderObserver *observer, |
michael@0 | 615 | nsISupports *context = nullptr, |
michael@0 | 616 | nsILoadGroup *loadGroup = nullptr, |
michael@0 | 617 | nsIInterfaceRequestor *callbacks = nullptr, |
michael@0 | 618 | uint32_t loadFlags = nsIRequest::LOAD_NORMAL, |
michael@0 | 619 | nsIURI *referrer = nullptr) |
michael@0 | 620 | { |
michael@0 | 621 | nsresult rv; |
michael@0 | 622 | nsCOMPtr<nsIChannel> channel; |
michael@0 | 623 | rv = NS_NewChannel(getter_AddRefs(channel), |
michael@0 | 624 | uri, |
michael@0 | 625 | nullptr, |
michael@0 | 626 | loadGroup, |
michael@0 | 627 | callbacks, |
michael@0 | 628 | loadFlags); |
michael@0 | 629 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 630 | nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(channel)); |
michael@0 | 631 | if (httpChannel) |
michael@0 | 632 | httpChannel->SetReferrer(referrer); |
michael@0 | 633 | rv = NS_NewStreamLoader(result, observer); |
michael@0 | 634 | if (NS_SUCCEEDED(rv)) |
michael@0 | 635 | rv = channel->AsyncOpen(*result, context); |
michael@0 | 636 | } |
michael@0 | 637 | return rv; |
michael@0 | 638 | } |
michael@0 | 639 | |
michael@0 | 640 | inline nsresult |
michael@0 | 641 | NS_NewUnicharStreamLoader(nsIUnicharStreamLoader **result, |
michael@0 | 642 | nsIUnicharStreamLoaderObserver *observer) |
michael@0 | 643 | { |
michael@0 | 644 | nsresult rv; |
michael@0 | 645 | nsCOMPtr<nsIUnicharStreamLoader> loader = |
michael@0 | 646 | do_CreateInstance(NS_UNICHARSTREAMLOADER_CONTRACTID, &rv); |
michael@0 | 647 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 648 | rv = loader->Init(observer); |
michael@0 | 649 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 650 | *result = nullptr; |
michael@0 | 651 | loader.swap(*result); |
michael@0 | 652 | } |
michael@0 | 653 | } |
michael@0 | 654 | return rv; |
michael@0 | 655 | } |
michael@0 | 656 | |
michael@0 | 657 | inline nsresult |
michael@0 | 658 | NS_NewSyncStreamListener(nsIStreamListener **result, |
michael@0 | 659 | nsIInputStream **stream) |
michael@0 | 660 | { |
michael@0 | 661 | nsresult rv; |
michael@0 | 662 | nsCOMPtr<nsISyncStreamListener> listener = |
michael@0 | 663 | do_CreateInstance(NS_SYNCSTREAMLISTENER_CONTRACTID, &rv); |
michael@0 | 664 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 665 | rv = listener->GetInputStream(stream); |
michael@0 | 666 | if (NS_SUCCEEDED(rv)) |
michael@0 | 667 | NS_ADDREF(*result = listener); // cannot use nsCOMPtr::swap |
michael@0 | 668 | } |
michael@0 | 669 | return rv; |
michael@0 | 670 | } |
michael@0 | 671 | |
michael@0 | 672 | /** |
michael@0 | 673 | * Implement the nsIChannel::Open(nsIInputStream**) method using the channel's |
michael@0 | 674 | * AsyncOpen method. |
michael@0 | 675 | * |
michael@0 | 676 | * NOTE: Reading from the returned nsIInputStream may spin the current |
michael@0 | 677 | * thread's event queue, which could result in any event being processed. |
michael@0 | 678 | */ |
michael@0 | 679 | inline nsresult |
michael@0 | 680 | NS_ImplementChannelOpen(nsIChannel *channel, |
michael@0 | 681 | nsIInputStream **result) |
michael@0 | 682 | { |
michael@0 | 683 | nsCOMPtr<nsIStreamListener> listener; |
michael@0 | 684 | nsCOMPtr<nsIInputStream> stream; |
michael@0 | 685 | nsresult rv = NS_NewSyncStreamListener(getter_AddRefs(listener), |
michael@0 | 686 | getter_AddRefs(stream)); |
michael@0 | 687 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 688 | rv = channel->AsyncOpen(listener, nullptr); |
michael@0 | 689 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 690 | uint64_t n; |
michael@0 | 691 | // block until the initial response is received or an error occurs. |
michael@0 | 692 | rv = stream->Available(&n); |
michael@0 | 693 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 694 | *result = nullptr; |
michael@0 | 695 | stream.swap(*result); |
michael@0 | 696 | } |
michael@0 | 697 | } |
michael@0 | 698 | } |
michael@0 | 699 | return rv; |
michael@0 | 700 | } |
michael@0 | 701 | |
michael@0 | 702 | inline nsresult |
michael@0 | 703 | NS_NewRequestObserverProxy(nsIRequestObserver **result, |
michael@0 | 704 | nsIRequestObserver *observer, |
michael@0 | 705 | nsISupports *context) |
michael@0 | 706 | { |
michael@0 | 707 | nsresult rv; |
michael@0 | 708 | nsCOMPtr<nsIRequestObserverProxy> proxy = |
michael@0 | 709 | do_CreateInstance(NS_REQUESTOBSERVERPROXY_CONTRACTID, &rv); |
michael@0 | 710 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 711 | rv = proxy->Init(observer, context); |
michael@0 | 712 | if (NS_SUCCEEDED(rv)) |
michael@0 | 713 | NS_ADDREF(*result = proxy); // cannot use nsCOMPtr::swap |
michael@0 | 714 | } |
michael@0 | 715 | return rv; |
michael@0 | 716 | } |
michael@0 | 717 | |
michael@0 | 718 | inline nsresult |
michael@0 | 719 | NS_NewSimpleStreamListener(nsIStreamListener **result, |
michael@0 | 720 | nsIOutputStream *sink, |
michael@0 | 721 | nsIRequestObserver *observer = nullptr) |
michael@0 | 722 | { |
michael@0 | 723 | nsresult rv; |
michael@0 | 724 | nsCOMPtr<nsISimpleStreamListener> listener = |
michael@0 | 725 | do_CreateInstance(NS_SIMPLESTREAMLISTENER_CONTRACTID, &rv); |
michael@0 | 726 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 727 | rv = listener->Init(sink, observer); |
michael@0 | 728 | if (NS_SUCCEEDED(rv)) |
michael@0 | 729 | NS_ADDREF(*result = listener); // cannot use nsCOMPtr::swap |
michael@0 | 730 | } |
michael@0 | 731 | return rv; |
michael@0 | 732 | } |
michael@0 | 733 | |
michael@0 | 734 | inline nsresult |
michael@0 | 735 | NS_CheckPortSafety(int32_t port, |
michael@0 | 736 | const char *scheme, |
michael@0 | 737 | nsIIOService *ioService = nullptr) |
michael@0 | 738 | { |
michael@0 | 739 | nsresult rv; |
michael@0 | 740 | nsCOMPtr<nsIIOService> grip; |
michael@0 | 741 | rv = net_EnsureIOService(&ioService, grip); |
michael@0 | 742 | if (ioService) { |
michael@0 | 743 | bool allow; |
michael@0 | 744 | rv = ioService->AllowPort(port, scheme, &allow); |
michael@0 | 745 | if (NS_SUCCEEDED(rv) && !allow) { |
michael@0 | 746 | NS_WARNING("port blocked"); |
michael@0 | 747 | rv = NS_ERROR_PORT_ACCESS_NOT_ALLOWED; |
michael@0 | 748 | } |
michael@0 | 749 | } |
michael@0 | 750 | return rv; |
michael@0 | 751 | } |
michael@0 | 752 | |
michael@0 | 753 | // Determine if this URI is using a safe port. |
michael@0 | 754 | inline nsresult |
michael@0 | 755 | NS_CheckPortSafety(nsIURI *uri) { |
michael@0 | 756 | int32_t port; |
michael@0 | 757 | nsresult rv = uri->GetPort(&port); |
michael@0 | 758 | if (NS_FAILED(rv) || port == -1) // port undefined or default-valued |
michael@0 | 759 | return NS_OK; |
michael@0 | 760 | nsAutoCString scheme; |
michael@0 | 761 | uri->GetScheme(scheme); |
michael@0 | 762 | return NS_CheckPortSafety(port, scheme.get()); |
michael@0 | 763 | } |
michael@0 | 764 | |
michael@0 | 765 | inline nsresult |
michael@0 | 766 | NS_NewProxyInfo(const nsACString &type, |
michael@0 | 767 | const nsACString &host, |
michael@0 | 768 | int32_t port, |
michael@0 | 769 | uint32_t flags, |
michael@0 | 770 | nsIProxyInfo **result) |
michael@0 | 771 | { |
michael@0 | 772 | nsresult rv; |
michael@0 | 773 | nsCOMPtr<nsIProtocolProxyService> pps = |
michael@0 | 774 | do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv); |
michael@0 | 775 | if (NS_SUCCEEDED(rv)) |
michael@0 | 776 | rv = pps->NewProxyInfo(type, host, port, flags, UINT32_MAX, nullptr, |
michael@0 | 777 | result); |
michael@0 | 778 | return rv; |
michael@0 | 779 | } |
michael@0 | 780 | |
michael@0 | 781 | inline nsresult |
michael@0 | 782 | NS_GetFileProtocolHandler(nsIFileProtocolHandler **result, |
michael@0 | 783 | nsIIOService *ioService = nullptr) |
michael@0 | 784 | { |
michael@0 | 785 | nsresult rv; |
michael@0 | 786 | nsCOMPtr<nsIIOService> grip; |
michael@0 | 787 | rv = net_EnsureIOService(&ioService, grip); |
michael@0 | 788 | if (ioService) { |
michael@0 | 789 | nsCOMPtr<nsIProtocolHandler> handler; |
michael@0 | 790 | rv = ioService->GetProtocolHandler("file", getter_AddRefs(handler)); |
michael@0 | 791 | if (NS_SUCCEEDED(rv)) |
michael@0 | 792 | rv = CallQueryInterface(handler, result); |
michael@0 | 793 | } |
michael@0 | 794 | return rv; |
michael@0 | 795 | } |
michael@0 | 796 | |
michael@0 | 797 | inline nsresult |
michael@0 | 798 | NS_GetFileFromURLSpec(const nsACString &inURL, |
michael@0 | 799 | nsIFile **result, |
michael@0 | 800 | nsIIOService *ioService = nullptr) |
michael@0 | 801 | { |
michael@0 | 802 | nsresult rv; |
michael@0 | 803 | nsCOMPtr<nsIFileProtocolHandler> fileHandler; |
michael@0 | 804 | rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService); |
michael@0 | 805 | if (NS_SUCCEEDED(rv)) |
michael@0 | 806 | rv = fileHandler->GetFileFromURLSpec(inURL, result); |
michael@0 | 807 | return rv; |
michael@0 | 808 | } |
michael@0 | 809 | |
michael@0 | 810 | inline nsresult |
michael@0 | 811 | NS_GetURLSpecFromFile(nsIFile *file, |
michael@0 | 812 | nsACString &url, |
michael@0 | 813 | nsIIOService *ioService = nullptr) |
michael@0 | 814 | { |
michael@0 | 815 | nsresult rv; |
michael@0 | 816 | nsCOMPtr<nsIFileProtocolHandler> fileHandler; |
michael@0 | 817 | rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService); |
michael@0 | 818 | if (NS_SUCCEEDED(rv)) |
michael@0 | 819 | rv = fileHandler->GetURLSpecFromFile(file, url); |
michael@0 | 820 | return rv; |
michael@0 | 821 | } |
michael@0 | 822 | |
michael@0 | 823 | /** |
michael@0 | 824 | * Converts the nsIFile to the corresponding URL string. |
michael@0 | 825 | * Should only be called on files which are not directories, |
michael@0 | 826 | * is otherwise identical to NS_GetURLSpecFromFile, but is |
michael@0 | 827 | * usually more efficient. |
michael@0 | 828 | * Warning: this restriction may not be enforced at runtime! |
michael@0 | 829 | */ |
michael@0 | 830 | inline nsresult |
michael@0 | 831 | NS_GetURLSpecFromActualFile(nsIFile *file, |
michael@0 | 832 | nsACString &url, |
michael@0 | 833 | nsIIOService *ioService = nullptr) |
michael@0 | 834 | { |
michael@0 | 835 | nsresult rv; |
michael@0 | 836 | nsCOMPtr<nsIFileProtocolHandler> fileHandler; |
michael@0 | 837 | rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService); |
michael@0 | 838 | if (NS_SUCCEEDED(rv)) |
michael@0 | 839 | rv = fileHandler->GetURLSpecFromActualFile(file, url); |
michael@0 | 840 | return rv; |
michael@0 | 841 | } |
michael@0 | 842 | |
michael@0 | 843 | /** |
michael@0 | 844 | * Converts the nsIFile to the corresponding URL string. |
michael@0 | 845 | * Should only be called on files which are directories, |
michael@0 | 846 | * is otherwise identical to NS_GetURLSpecFromFile, but is |
michael@0 | 847 | * usually more efficient. |
michael@0 | 848 | * Warning: this restriction may not be enforced at runtime! |
michael@0 | 849 | */ |
michael@0 | 850 | inline nsresult |
michael@0 | 851 | NS_GetURLSpecFromDir(nsIFile *file, |
michael@0 | 852 | nsACString &url, |
michael@0 | 853 | nsIIOService *ioService = nullptr) |
michael@0 | 854 | { |
michael@0 | 855 | nsresult rv; |
michael@0 | 856 | nsCOMPtr<nsIFileProtocolHandler> fileHandler; |
michael@0 | 857 | rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler), ioService); |
michael@0 | 858 | if (NS_SUCCEEDED(rv)) |
michael@0 | 859 | rv = fileHandler->GetURLSpecFromDir(file, url); |
michael@0 | 860 | return rv; |
michael@0 | 861 | } |
michael@0 | 862 | |
michael@0 | 863 | /** |
michael@0 | 864 | * Obtains the referrer for a given channel. This first tries to obtain the |
michael@0 | 865 | * referrer from the property docshell.internalReferrer, and if that doesn't |
michael@0 | 866 | * work and the channel is an nsIHTTPChannel, we check it's referrer property. |
michael@0 | 867 | * |
michael@0 | 868 | * @returns NS_ERROR_NOT_AVAILABLE if no referrer is available. |
michael@0 | 869 | */ |
michael@0 | 870 | inline nsresult |
michael@0 | 871 | NS_GetReferrerFromChannel(nsIChannel *channel, |
michael@0 | 872 | nsIURI **referrer) |
michael@0 | 873 | { |
michael@0 | 874 | nsresult rv = NS_ERROR_NOT_AVAILABLE; |
michael@0 | 875 | *referrer = nullptr; |
michael@0 | 876 | |
michael@0 | 877 | nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(channel)); |
michael@0 | 878 | if (props) { |
michael@0 | 879 | // We have to check for a property on a property bag because the |
michael@0 | 880 | // referrer may be empty for security reasons (for example, when loading |
michael@0 | 881 | // an http page with an https referrer). |
michael@0 | 882 | rv = props->GetPropertyAsInterface(NS_LITERAL_STRING("docshell.internalReferrer"), |
michael@0 | 883 | NS_GET_IID(nsIURI), |
michael@0 | 884 | reinterpret_cast<void **>(referrer)); |
michael@0 | 885 | if (NS_FAILED(rv)) |
michael@0 | 886 | *referrer = nullptr; |
michael@0 | 887 | } |
michael@0 | 888 | |
michael@0 | 889 | // if that didn't work, we can still try to get the referrer from the |
michael@0 | 890 | // nsIHttpChannel (if we can QI to it) |
michael@0 | 891 | if (!(*referrer)) { |
michael@0 | 892 | nsCOMPtr<nsIHttpChannel> chan(do_QueryInterface(channel)); |
michael@0 | 893 | if (chan) { |
michael@0 | 894 | rv = chan->GetReferrer(referrer); |
michael@0 | 895 | if (NS_FAILED(rv)) |
michael@0 | 896 | *referrer = nullptr; |
michael@0 | 897 | } |
michael@0 | 898 | } |
michael@0 | 899 | return rv; |
michael@0 | 900 | } |
michael@0 | 901 | |
michael@0 | 902 | inline nsresult |
michael@0 | 903 | NS_ParseContentType(const nsACString &rawContentType, |
michael@0 | 904 | nsCString &contentType, |
michael@0 | 905 | nsCString &contentCharset) |
michael@0 | 906 | { |
michael@0 | 907 | // contentCharset is left untouched if not present in rawContentType |
michael@0 | 908 | nsresult rv; |
michael@0 | 909 | nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv); |
michael@0 | 910 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 911 | nsCString charset; |
michael@0 | 912 | bool hadCharset; |
michael@0 | 913 | rv = util->ParseContentType(rawContentType, charset, &hadCharset, |
michael@0 | 914 | contentType); |
michael@0 | 915 | if (NS_SUCCEEDED(rv) && hadCharset) |
michael@0 | 916 | contentCharset = charset; |
michael@0 | 917 | return rv; |
michael@0 | 918 | } |
michael@0 | 919 | |
michael@0 | 920 | inline nsresult |
michael@0 | 921 | NS_ExtractCharsetFromContentType(const nsACString &rawContentType, |
michael@0 | 922 | nsCString &contentCharset, |
michael@0 | 923 | bool *hadCharset, |
michael@0 | 924 | int32_t *charsetStart, |
michael@0 | 925 | int32_t *charsetEnd) |
michael@0 | 926 | { |
michael@0 | 927 | // contentCharset is left untouched if not present in rawContentType |
michael@0 | 928 | nsresult rv; |
michael@0 | 929 | nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv); |
michael@0 | 930 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 931 | |
michael@0 | 932 | return util->ExtractCharsetFromContentType(rawContentType, |
michael@0 | 933 | contentCharset, |
michael@0 | 934 | charsetStart, |
michael@0 | 935 | charsetEnd, |
michael@0 | 936 | hadCharset); |
michael@0 | 937 | } |
michael@0 | 938 | |
michael@0 | 939 | inline nsresult |
michael@0 | 940 | NS_NewLocalFileInputStream(nsIInputStream **result, |
michael@0 | 941 | nsIFile *file, |
michael@0 | 942 | int32_t ioFlags = -1, |
michael@0 | 943 | int32_t perm = -1, |
michael@0 | 944 | int32_t behaviorFlags = 0) |
michael@0 | 945 | { |
michael@0 | 946 | nsresult rv; |
michael@0 | 947 | nsCOMPtr<nsIFileInputStream> in = |
michael@0 | 948 | do_CreateInstance(NS_LOCALFILEINPUTSTREAM_CONTRACTID, &rv); |
michael@0 | 949 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 950 | rv = in->Init(file, ioFlags, perm, behaviorFlags); |
michael@0 | 951 | if (NS_SUCCEEDED(rv)) |
michael@0 | 952 | in.forget(result); |
michael@0 | 953 | } |
michael@0 | 954 | return rv; |
michael@0 | 955 | } |
michael@0 | 956 | |
michael@0 | 957 | inline nsresult |
michael@0 | 958 | NS_NewPartialLocalFileInputStream(nsIInputStream **result, |
michael@0 | 959 | nsIFile *file, |
michael@0 | 960 | uint64_t offset, |
michael@0 | 961 | uint64_t length, |
michael@0 | 962 | int32_t ioFlags = -1, |
michael@0 | 963 | int32_t perm = -1, |
michael@0 | 964 | int32_t behaviorFlags = 0) |
michael@0 | 965 | { |
michael@0 | 966 | nsresult rv; |
michael@0 | 967 | nsCOMPtr<nsIPartialFileInputStream> in = |
michael@0 | 968 | do_CreateInstance(NS_PARTIALLOCALFILEINPUTSTREAM_CONTRACTID, &rv); |
michael@0 | 969 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 970 | rv = in->Init(file, offset, length, ioFlags, perm, behaviorFlags); |
michael@0 | 971 | if (NS_SUCCEEDED(rv)) |
michael@0 | 972 | rv = CallQueryInterface(in, result); |
michael@0 | 973 | } |
michael@0 | 974 | return rv; |
michael@0 | 975 | } |
michael@0 | 976 | |
michael@0 | 977 | inline nsresult |
michael@0 | 978 | NS_NewLocalFileOutputStream(nsIOutputStream **result, |
michael@0 | 979 | nsIFile *file, |
michael@0 | 980 | int32_t ioFlags = -1, |
michael@0 | 981 | int32_t perm = -1, |
michael@0 | 982 | int32_t behaviorFlags = 0) |
michael@0 | 983 | { |
michael@0 | 984 | nsresult rv; |
michael@0 | 985 | nsCOMPtr<nsIFileOutputStream> out = |
michael@0 | 986 | do_CreateInstance(NS_LOCALFILEOUTPUTSTREAM_CONTRACTID, &rv); |
michael@0 | 987 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 988 | rv = out->Init(file, ioFlags, perm, behaviorFlags); |
michael@0 | 989 | if (NS_SUCCEEDED(rv)) |
michael@0 | 990 | out.forget(result); |
michael@0 | 991 | } |
michael@0 | 992 | return rv; |
michael@0 | 993 | } |
michael@0 | 994 | |
michael@0 | 995 | // returns a file output stream which can be QI'ed to nsISafeOutputStream. |
michael@0 | 996 | inline nsresult |
michael@0 | 997 | NS_NewAtomicFileOutputStream(nsIOutputStream **result, |
michael@0 | 998 | nsIFile *file, |
michael@0 | 999 | int32_t ioFlags = -1, |
michael@0 | 1000 | int32_t perm = -1, |
michael@0 | 1001 | int32_t behaviorFlags = 0) |
michael@0 | 1002 | { |
michael@0 | 1003 | nsresult rv; |
michael@0 | 1004 | nsCOMPtr<nsIFileOutputStream> out = |
michael@0 | 1005 | do_CreateInstance(NS_ATOMICLOCALFILEOUTPUTSTREAM_CONTRACTID, &rv); |
michael@0 | 1006 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1007 | rv = out->Init(file, ioFlags, perm, behaviorFlags); |
michael@0 | 1008 | if (NS_SUCCEEDED(rv)) |
michael@0 | 1009 | out.forget(result); |
michael@0 | 1010 | } |
michael@0 | 1011 | return rv; |
michael@0 | 1012 | } |
michael@0 | 1013 | |
michael@0 | 1014 | // returns a file output stream which can be QI'ed to nsISafeOutputStream. |
michael@0 | 1015 | inline nsresult |
michael@0 | 1016 | NS_NewSafeLocalFileOutputStream(nsIOutputStream **result, |
michael@0 | 1017 | nsIFile *file, |
michael@0 | 1018 | int32_t ioFlags = -1, |
michael@0 | 1019 | int32_t perm = -1, |
michael@0 | 1020 | int32_t behaviorFlags = 0) |
michael@0 | 1021 | { |
michael@0 | 1022 | nsresult rv; |
michael@0 | 1023 | nsCOMPtr<nsIFileOutputStream> out = |
michael@0 | 1024 | do_CreateInstance(NS_SAFELOCALFILEOUTPUTSTREAM_CONTRACTID, &rv); |
michael@0 | 1025 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1026 | rv = out->Init(file, ioFlags, perm, behaviorFlags); |
michael@0 | 1027 | if (NS_SUCCEEDED(rv)) |
michael@0 | 1028 | out.forget(result); |
michael@0 | 1029 | } |
michael@0 | 1030 | return rv; |
michael@0 | 1031 | } |
michael@0 | 1032 | |
michael@0 | 1033 | inline nsresult |
michael@0 | 1034 | NS_NewLocalFileStream(nsIFileStream **result, |
michael@0 | 1035 | nsIFile *file, |
michael@0 | 1036 | int32_t ioFlags = -1, |
michael@0 | 1037 | int32_t perm = -1, |
michael@0 | 1038 | int32_t behaviorFlags = 0) |
michael@0 | 1039 | { |
michael@0 | 1040 | nsresult rv; |
michael@0 | 1041 | nsCOMPtr<nsIFileStream> stream = |
michael@0 | 1042 | do_CreateInstance(NS_LOCALFILESTREAM_CONTRACTID, &rv); |
michael@0 | 1043 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1044 | rv = stream->Init(file, ioFlags, perm, behaviorFlags); |
michael@0 | 1045 | if (NS_SUCCEEDED(rv)) |
michael@0 | 1046 | stream.forget(result); |
michael@0 | 1047 | } |
michael@0 | 1048 | return rv; |
michael@0 | 1049 | } |
michael@0 | 1050 | |
michael@0 | 1051 | // returns the input end of a pipe. the output end of the pipe |
michael@0 | 1052 | // is attached to the original stream. data from the original |
michael@0 | 1053 | // stream is read into the pipe on a background thread. |
michael@0 | 1054 | inline nsresult |
michael@0 | 1055 | NS_BackgroundInputStream(nsIInputStream **result, |
michael@0 | 1056 | nsIInputStream *stream, |
michael@0 | 1057 | uint32_t segmentSize = 0, |
michael@0 | 1058 | uint32_t segmentCount = 0) |
michael@0 | 1059 | { |
michael@0 | 1060 | nsresult rv; |
michael@0 | 1061 | nsCOMPtr<nsIStreamTransportService> sts = |
michael@0 | 1062 | do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); |
michael@0 | 1063 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1064 | nsCOMPtr<nsITransport> inTransport; |
michael@0 | 1065 | rv = sts->CreateInputTransport(stream, int64_t(-1), int64_t(-1), |
michael@0 | 1066 | true, getter_AddRefs(inTransport)); |
michael@0 | 1067 | if (NS_SUCCEEDED(rv)) |
michael@0 | 1068 | rv = inTransport->OpenInputStream(nsITransport::OPEN_BLOCKING, |
michael@0 | 1069 | segmentSize, segmentCount, |
michael@0 | 1070 | result); |
michael@0 | 1071 | } |
michael@0 | 1072 | return rv; |
michael@0 | 1073 | } |
michael@0 | 1074 | |
michael@0 | 1075 | // returns the output end of a pipe. the input end of the pipe |
michael@0 | 1076 | // is attached to the original stream. data written to the pipe |
michael@0 | 1077 | // is copied to the original stream on a background thread. |
michael@0 | 1078 | inline nsresult |
michael@0 | 1079 | NS_BackgroundOutputStream(nsIOutputStream **result, |
michael@0 | 1080 | nsIOutputStream *stream, |
michael@0 | 1081 | uint32_t segmentSize = 0, |
michael@0 | 1082 | uint32_t segmentCount = 0) |
michael@0 | 1083 | { |
michael@0 | 1084 | nsresult rv; |
michael@0 | 1085 | nsCOMPtr<nsIStreamTransportService> sts = |
michael@0 | 1086 | do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv); |
michael@0 | 1087 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1088 | nsCOMPtr<nsITransport> inTransport; |
michael@0 | 1089 | rv = sts->CreateOutputTransport(stream, int64_t(-1), int64_t(-1), |
michael@0 | 1090 | true, getter_AddRefs(inTransport)); |
michael@0 | 1091 | if (NS_SUCCEEDED(rv)) |
michael@0 | 1092 | rv = inTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING, |
michael@0 | 1093 | segmentSize, segmentCount, |
michael@0 | 1094 | result); |
michael@0 | 1095 | } |
michael@0 | 1096 | return rv; |
michael@0 | 1097 | } |
michael@0 | 1098 | |
michael@0 | 1099 | MOZ_WARN_UNUSED_RESULT inline nsresult |
michael@0 | 1100 | NS_NewBufferedInputStream(nsIInputStream **result, |
michael@0 | 1101 | nsIInputStream *str, |
michael@0 | 1102 | uint32_t bufferSize) |
michael@0 | 1103 | { |
michael@0 | 1104 | nsresult rv; |
michael@0 | 1105 | nsCOMPtr<nsIBufferedInputStream> in = |
michael@0 | 1106 | do_CreateInstance(NS_BUFFEREDINPUTSTREAM_CONTRACTID, &rv); |
michael@0 | 1107 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1108 | rv = in->Init(str, bufferSize); |
michael@0 | 1109 | if (NS_SUCCEEDED(rv)) |
michael@0 | 1110 | NS_ADDREF(*result = in); // cannot use nsCOMPtr::swap |
michael@0 | 1111 | } |
michael@0 | 1112 | return rv; |
michael@0 | 1113 | } |
michael@0 | 1114 | |
michael@0 | 1115 | // note: the resulting stream can be QI'ed to nsISafeOutputStream iff the |
michael@0 | 1116 | // provided stream supports it. |
michael@0 | 1117 | inline nsresult |
michael@0 | 1118 | NS_NewBufferedOutputStream(nsIOutputStream **result, |
michael@0 | 1119 | nsIOutputStream *str, |
michael@0 | 1120 | uint32_t bufferSize) |
michael@0 | 1121 | { |
michael@0 | 1122 | nsresult rv; |
michael@0 | 1123 | nsCOMPtr<nsIBufferedOutputStream> out = |
michael@0 | 1124 | do_CreateInstance(NS_BUFFEREDOUTPUTSTREAM_CONTRACTID, &rv); |
michael@0 | 1125 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1126 | rv = out->Init(str, bufferSize); |
michael@0 | 1127 | if (NS_SUCCEEDED(rv)) |
michael@0 | 1128 | NS_ADDREF(*result = out); // cannot use nsCOMPtr::swap |
michael@0 | 1129 | } |
michael@0 | 1130 | return rv; |
michael@0 | 1131 | } |
michael@0 | 1132 | |
michael@0 | 1133 | /** |
michael@0 | 1134 | * Attempts to buffer a given output stream. If this fails, it returns the |
michael@0 | 1135 | * passed-in output stream. |
michael@0 | 1136 | * |
michael@0 | 1137 | * @param aOutputStream |
michael@0 | 1138 | * The output stream we want to buffer. This cannot be null. |
michael@0 | 1139 | * @param aBufferSize |
michael@0 | 1140 | * The size of the buffer for the buffered output stream. |
michael@0 | 1141 | * @returns an nsIOutputStream that is buffered with the specified buffer size, |
michael@0 | 1142 | * or is aOutputStream if creating the new buffered stream failed. |
michael@0 | 1143 | */ |
michael@0 | 1144 | inline already_AddRefed<nsIOutputStream> |
michael@0 | 1145 | NS_BufferOutputStream(nsIOutputStream *aOutputStream, |
michael@0 | 1146 | uint32_t aBufferSize) |
michael@0 | 1147 | { |
michael@0 | 1148 | NS_ASSERTION(aOutputStream, "No output stream given!"); |
michael@0 | 1149 | |
michael@0 | 1150 | nsCOMPtr<nsIOutputStream> bos; |
michael@0 | 1151 | nsresult rv = NS_NewBufferedOutputStream(getter_AddRefs(bos), aOutputStream, |
michael@0 | 1152 | aBufferSize); |
michael@0 | 1153 | if (NS_SUCCEEDED(rv)) |
michael@0 | 1154 | return bos.forget(); |
michael@0 | 1155 | |
michael@0 | 1156 | bos = aOutputStream; |
michael@0 | 1157 | return bos.forget(); |
michael@0 | 1158 | } |
michael@0 | 1159 | |
michael@0 | 1160 | // returns an input stream compatible with nsIUploadChannel::SetUploadStream() |
michael@0 | 1161 | inline nsresult |
michael@0 | 1162 | NS_NewPostDataStream(nsIInputStream **result, |
michael@0 | 1163 | bool isFile, |
michael@0 | 1164 | const nsACString &data) |
michael@0 | 1165 | { |
michael@0 | 1166 | nsresult rv; |
michael@0 | 1167 | |
michael@0 | 1168 | if (isFile) { |
michael@0 | 1169 | nsCOMPtr<nsIFile> file; |
michael@0 | 1170 | nsCOMPtr<nsIInputStream> fileStream; |
michael@0 | 1171 | |
michael@0 | 1172 | rv = NS_NewNativeLocalFile(data, false, getter_AddRefs(file)); |
michael@0 | 1173 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1174 | rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream), file); |
michael@0 | 1175 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1176 | // wrap the file stream with a buffered input stream |
michael@0 | 1177 | rv = NS_NewBufferedInputStream(result, fileStream, 8192); |
michael@0 | 1178 | } |
michael@0 | 1179 | } |
michael@0 | 1180 | return rv; |
michael@0 | 1181 | } |
michael@0 | 1182 | |
michael@0 | 1183 | // otherwise, create a string stream for the data (copies) |
michael@0 | 1184 | nsCOMPtr<nsIStringInputStream> stream |
michael@0 | 1185 | (do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv)); |
michael@0 | 1186 | if (NS_FAILED(rv)) |
michael@0 | 1187 | return rv; |
michael@0 | 1188 | |
michael@0 | 1189 | rv = stream->SetData(data.BeginReading(), data.Length()); |
michael@0 | 1190 | if (NS_FAILED(rv)) |
michael@0 | 1191 | return rv; |
michael@0 | 1192 | |
michael@0 | 1193 | NS_ADDREF(*result = stream); |
michael@0 | 1194 | return NS_OK; |
michael@0 | 1195 | } |
michael@0 | 1196 | |
michael@0 | 1197 | inline nsresult |
michael@0 | 1198 | NS_ReadInputStreamToBuffer(nsIInputStream *aInputStream, |
michael@0 | 1199 | void** aDest, |
michael@0 | 1200 | uint32_t aCount) |
michael@0 | 1201 | { |
michael@0 | 1202 | nsresult rv; |
michael@0 | 1203 | |
michael@0 | 1204 | if (!*aDest) { |
michael@0 | 1205 | *aDest = malloc(aCount); |
michael@0 | 1206 | if (!*aDest) |
michael@0 | 1207 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 1208 | } |
michael@0 | 1209 | |
michael@0 | 1210 | char * p = reinterpret_cast<char*>(*aDest); |
michael@0 | 1211 | uint32_t bytesRead; |
michael@0 | 1212 | uint32_t totalRead = 0; |
michael@0 | 1213 | while (1) { |
michael@0 | 1214 | rv = aInputStream->Read(p + totalRead, aCount - totalRead, &bytesRead); |
michael@0 | 1215 | if (!NS_SUCCEEDED(rv)) |
michael@0 | 1216 | return rv; |
michael@0 | 1217 | totalRead += bytesRead; |
michael@0 | 1218 | if (totalRead == aCount) |
michael@0 | 1219 | break; |
michael@0 | 1220 | // if Read reads 0 bytes, we've hit EOF |
michael@0 | 1221 | if (bytesRead == 0) |
michael@0 | 1222 | return NS_ERROR_UNEXPECTED; |
michael@0 | 1223 | } |
michael@0 | 1224 | return rv; |
michael@0 | 1225 | } |
michael@0 | 1226 | |
michael@0 | 1227 | // external code can't see fallible_t |
michael@0 | 1228 | #ifdef MOZILLA_INTERNAL_API |
michael@0 | 1229 | |
michael@0 | 1230 | inline nsresult |
michael@0 | 1231 | NS_ReadInputStreamToString(nsIInputStream *aInputStream, |
michael@0 | 1232 | nsACString &aDest, |
michael@0 | 1233 | uint32_t aCount) |
michael@0 | 1234 | { |
michael@0 | 1235 | if (!aDest.SetLength(aCount, mozilla::fallible_t())) |
michael@0 | 1236 | return NS_ERROR_OUT_OF_MEMORY; |
michael@0 | 1237 | void* dest = aDest.BeginWriting(); |
michael@0 | 1238 | return NS_ReadInputStreamToBuffer(aInputStream, &dest, aCount); |
michael@0 | 1239 | } |
michael@0 | 1240 | |
michael@0 | 1241 | #endif |
michael@0 | 1242 | |
michael@0 | 1243 | inline nsresult |
michael@0 | 1244 | NS_LoadPersistentPropertiesFromURI(nsIPersistentProperties **result, |
michael@0 | 1245 | nsIURI *uri, |
michael@0 | 1246 | nsIIOService *ioService = nullptr) |
michael@0 | 1247 | { |
michael@0 | 1248 | nsCOMPtr<nsIInputStream> in; |
michael@0 | 1249 | nsresult rv = NS_OpenURI(getter_AddRefs(in), uri, ioService); |
michael@0 | 1250 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1251 | nsCOMPtr<nsIPersistentProperties> properties = |
michael@0 | 1252 | do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID, &rv); |
michael@0 | 1253 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1254 | rv = properties->Load(in); |
michael@0 | 1255 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1256 | *result = nullptr; |
michael@0 | 1257 | properties.swap(*result); |
michael@0 | 1258 | } |
michael@0 | 1259 | } |
michael@0 | 1260 | } |
michael@0 | 1261 | return rv; |
michael@0 | 1262 | } |
michael@0 | 1263 | |
michael@0 | 1264 | inline nsresult |
michael@0 | 1265 | NS_LoadPersistentPropertiesFromURISpec(nsIPersistentProperties **result, |
michael@0 | 1266 | const nsACString &spec, |
michael@0 | 1267 | const char *charset = nullptr, |
michael@0 | 1268 | nsIURI *baseURI = nullptr, |
michael@0 | 1269 | nsIIOService *ioService = nullptr) |
michael@0 | 1270 | { |
michael@0 | 1271 | nsCOMPtr<nsIURI> uri; |
michael@0 | 1272 | nsresult rv = |
michael@0 | 1273 | NS_NewURI(getter_AddRefs(uri), spec, charset, baseURI, ioService); |
michael@0 | 1274 | |
michael@0 | 1275 | if (NS_SUCCEEDED(rv)) |
michael@0 | 1276 | rv = NS_LoadPersistentPropertiesFromURI(result, uri, ioService); |
michael@0 | 1277 | |
michael@0 | 1278 | return rv; |
michael@0 | 1279 | } |
michael@0 | 1280 | |
michael@0 | 1281 | /** |
michael@0 | 1282 | * NS_QueryNotificationCallbacks implements the canonical algorithm for |
michael@0 | 1283 | * querying interfaces from a channel's notification callbacks. It first |
michael@0 | 1284 | * searches the channel's notificationCallbacks attribute, and if the interface |
michael@0 | 1285 | * is not found there, then it inspects the notificationCallbacks attribute of |
michael@0 | 1286 | * the channel's loadGroup. |
michael@0 | 1287 | * |
michael@0 | 1288 | * Note: templatized only because nsIWebSocketChannel is currently not an |
michael@0 | 1289 | * nsIChannel. |
michael@0 | 1290 | */ |
michael@0 | 1291 | template <class T> inline void |
michael@0 | 1292 | NS_QueryNotificationCallbacks(T *channel, |
michael@0 | 1293 | const nsIID &iid, |
michael@0 | 1294 | void **result) |
michael@0 | 1295 | { |
michael@0 | 1296 | NS_PRECONDITION(channel, "null channel"); |
michael@0 | 1297 | *result = nullptr; |
michael@0 | 1298 | |
michael@0 | 1299 | nsCOMPtr<nsIInterfaceRequestor> cbs; |
michael@0 | 1300 | channel->GetNotificationCallbacks(getter_AddRefs(cbs)); |
michael@0 | 1301 | if (cbs) |
michael@0 | 1302 | cbs->GetInterface(iid, result); |
michael@0 | 1303 | if (!*result) { |
michael@0 | 1304 | // try load group's notification callbacks... |
michael@0 | 1305 | nsCOMPtr<nsILoadGroup> loadGroup; |
michael@0 | 1306 | channel->GetLoadGroup(getter_AddRefs(loadGroup)); |
michael@0 | 1307 | if (loadGroup) { |
michael@0 | 1308 | loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs)); |
michael@0 | 1309 | if (cbs) |
michael@0 | 1310 | cbs->GetInterface(iid, result); |
michael@0 | 1311 | } |
michael@0 | 1312 | } |
michael@0 | 1313 | } |
michael@0 | 1314 | |
michael@0 | 1315 | // template helper: |
michael@0 | 1316 | // Note: "class C" templatized only because nsIWebSocketChannel is currently not |
michael@0 | 1317 | // an nsIChannel. |
michael@0 | 1318 | |
michael@0 | 1319 | template <class C, class T> inline void |
michael@0 | 1320 | NS_QueryNotificationCallbacks(C *channel, |
michael@0 | 1321 | nsCOMPtr<T> &result) |
michael@0 | 1322 | { |
michael@0 | 1323 | NS_QueryNotificationCallbacks(channel, NS_GET_TEMPLATE_IID(T), |
michael@0 | 1324 | getter_AddRefs(result)); |
michael@0 | 1325 | } |
michael@0 | 1326 | |
michael@0 | 1327 | /** |
michael@0 | 1328 | * Alternate form of NS_QueryNotificationCallbacks designed for use by |
michael@0 | 1329 | * nsIChannel implementations. |
michael@0 | 1330 | */ |
michael@0 | 1331 | inline void |
michael@0 | 1332 | NS_QueryNotificationCallbacks(nsIInterfaceRequestor *callbacks, |
michael@0 | 1333 | nsILoadGroup *loadGroup, |
michael@0 | 1334 | const nsIID &iid, |
michael@0 | 1335 | void **result) |
michael@0 | 1336 | { |
michael@0 | 1337 | *result = nullptr; |
michael@0 | 1338 | |
michael@0 | 1339 | if (callbacks) |
michael@0 | 1340 | callbacks->GetInterface(iid, result); |
michael@0 | 1341 | if (!*result) { |
michael@0 | 1342 | // try load group's notification callbacks... |
michael@0 | 1343 | if (loadGroup) { |
michael@0 | 1344 | nsCOMPtr<nsIInterfaceRequestor> cbs; |
michael@0 | 1345 | loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs)); |
michael@0 | 1346 | if (cbs) |
michael@0 | 1347 | cbs->GetInterface(iid, result); |
michael@0 | 1348 | } |
michael@0 | 1349 | } |
michael@0 | 1350 | } |
michael@0 | 1351 | |
michael@0 | 1352 | /** |
michael@0 | 1353 | * Returns true if channel is using Private Browsing, or false if not. |
michael@0 | 1354 | * Returns false if channel's callbacks don't implement nsILoadContext. |
michael@0 | 1355 | */ |
michael@0 | 1356 | inline bool |
michael@0 | 1357 | NS_UsePrivateBrowsing(nsIChannel *channel) |
michael@0 | 1358 | { |
michael@0 | 1359 | bool isPrivate = false; |
michael@0 | 1360 | bool isOverriden = false; |
michael@0 | 1361 | nsCOMPtr<nsIPrivateBrowsingChannel> pbChannel = do_QueryInterface(channel); |
michael@0 | 1362 | if (pbChannel && |
michael@0 | 1363 | NS_SUCCEEDED(pbChannel->IsPrivateModeOverriden(&isPrivate, &isOverriden)) && |
michael@0 | 1364 | isOverriden) { |
michael@0 | 1365 | return isPrivate; |
michael@0 | 1366 | } |
michael@0 | 1367 | nsCOMPtr<nsILoadContext> loadContext; |
michael@0 | 1368 | NS_QueryNotificationCallbacks(channel, loadContext); |
michael@0 | 1369 | return loadContext && loadContext->UsePrivateBrowsing(); |
michael@0 | 1370 | } |
michael@0 | 1371 | |
michael@0 | 1372 | // Constants duplicated from nsIScriptSecurityManager so we avoid having necko |
michael@0 | 1373 | // know about script security manager. |
michael@0 | 1374 | #define NECKO_NO_APP_ID 0 |
michael@0 | 1375 | #define NECKO_UNKNOWN_APP_ID UINT32_MAX |
michael@0 | 1376 | // special app id reserved for separating the safebrowsing cookie |
michael@0 | 1377 | #define NECKO_SAFEBROWSING_APP_ID UINT32_MAX - 1 |
michael@0 | 1378 | |
michael@0 | 1379 | /** |
michael@0 | 1380 | * Gets AppId and isInBrowserElement from channel's nsILoadContext. |
michael@0 | 1381 | * Returns false if error or channel's callbacks don't implement nsILoadContext. |
michael@0 | 1382 | */ |
michael@0 | 1383 | inline bool |
michael@0 | 1384 | NS_GetAppInfo(nsIChannel *aChannel, uint32_t *aAppID, bool *aIsInBrowserElement) |
michael@0 | 1385 | { |
michael@0 | 1386 | nsCOMPtr<nsILoadContext> loadContext; |
michael@0 | 1387 | NS_QueryNotificationCallbacks(aChannel, loadContext); |
michael@0 | 1388 | if (!loadContext) { |
michael@0 | 1389 | return false; |
michael@0 | 1390 | } |
michael@0 | 1391 | |
michael@0 | 1392 | nsresult rv = loadContext->GetAppId(aAppID); |
michael@0 | 1393 | NS_ENSURE_SUCCESS(rv, false); |
michael@0 | 1394 | |
michael@0 | 1395 | rv = loadContext->GetIsInBrowserElement(aIsInBrowserElement); |
michael@0 | 1396 | NS_ENSURE_SUCCESS(rv, false); |
michael@0 | 1397 | |
michael@0 | 1398 | return true; |
michael@0 | 1399 | } |
michael@0 | 1400 | |
michael@0 | 1401 | /** |
michael@0 | 1402 | * Gets appId and browserOnly parameters from the TOPIC_WEB_APP_CLEAR_DATA |
michael@0 | 1403 | * nsIObserverService notification. Used when clearing user data or |
michael@0 | 1404 | * uninstalling web apps. |
michael@0 | 1405 | */ |
michael@0 | 1406 | inline nsresult |
michael@0 | 1407 | NS_GetAppInfoFromClearDataNotification(nsISupports *aSubject, |
michael@0 | 1408 | uint32_t *aAppID, bool* aBrowserOnly) |
michael@0 | 1409 | { |
michael@0 | 1410 | nsresult rv; |
michael@0 | 1411 | |
michael@0 | 1412 | nsCOMPtr<mozIApplicationClearPrivateDataParams> |
michael@0 | 1413 | clearParams(do_QueryInterface(aSubject)); |
michael@0 | 1414 | MOZ_ASSERT(clearParams); |
michael@0 | 1415 | if (!clearParams) { |
michael@0 | 1416 | return NS_ERROR_UNEXPECTED; |
michael@0 | 1417 | } |
michael@0 | 1418 | |
michael@0 | 1419 | uint32_t appId; |
michael@0 | 1420 | rv = clearParams->GetAppId(&appId); |
michael@0 | 1421 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
michael@0 | 1422 | MOZ_ASSERT(appId != NECKO_UNKNOWN_APP_ID); |
michael@0 | 1423 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1424 | if (appId == NECKO_UNKNOWN_APP_ID) { |
michael@0 | 1425 | return NS_ERROR_UNEXPECTED; |
michael@0 | 1426 | } |
michael@0 | 1427 | |
michael@0 | 1428 | bool browserOnly = false; |
michael@0 | 1429 | rv = clearParams->GetBrowserOnly(&browserOnly); |
michael@0 | 1430 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
michael@0 | 1431 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1432 | |
michael@0 | 1433 | *aAppID = appId; |
michael@0 | 1434 | *aBrowserOnly = browserOnly; |
michael@0 | 1435 | return NS_OK; |
michael@0 | 1436 | } |
michael@0 | 1437 | |
michael@0 | 1438 | /** |
michael@0 | 1439 | * Determines whether appcache should be checked for a given URI. |
michael@0 | 1440 | */ |
michael@0 | 1441 | inline bool |
michael@0 | 1442 | NS_ShouldCheckAppCache(nsIURI *aURI, bool usePrivateBrowsing) |
michael@0 | 1443 | { |
michael@0 | 1444 | if (usePrivateBrowsing) { |
michael@0 | 1445 | return false; |
michael@0 | 1446 | } |
michael@0 | 1447 | |
michael@0 | 1448 | nsCOMPtr<nsIOfflineCacheUpdateService> offlineService = |
michael@0 | 1449 | do_GetService("@mozilla.org/offlinecacheupdate-service;1"); |
michael@0 | 1450 | if (!offlineService) { |
michael@0 | 1451 | return false; |
michael@0 | 1452 | } |
michael@0 | 1453 | |
michael@0 | 1454 | bool allowed; |
michael@0 | 1455 | nsresult rv = offlineService->OfflineAppAllowedForURI(aURI, |
michael@0 | 1456 | nullptr, |
michael@0 | 1457 | &allowed); |
michael@0 | 1458 | return NS_SUCCEEDED(rv) && allowed; |
michael@0 | 1459 | } |
michael@0 | 1460 | |
michael@0 | 1461 | inline bool |
michael@0 | 1462 | NS_ShouldCheckAppCache(nsIPrincipal * aPrincipal, bool usePrivateBrowsing) |
michael@0 | 1463 | { |
michael@0 | 1464 | if (usePrivateBrowsing) { |
michael@0 | 1465 | return false; |
michael@0 | 1466 | } |
michael@0 | 1467 | |
michael@0 | 1468 | nsCOMPtr<nsIOfflineCacheUpdateService> offlineService = |
michael@0 | 1469 | do_GetService("@mozilla.org/offlinecacheupdate-service;1"); |
michael@0 | 1470 | if (!offlineService) { |
michael@0 | 1471 | return false; |
michael@0 | 1472 | } |
michael@0 | 1473 | |
michael@0 | 1474 | bool allowed; |
michael@0 | 1475 | nsresult rv = offlineService->OfflineAppAllowed(aPrincipal, |
michael@0 | 1476 | nullptr, |
michael@0 | 1477 | &allowed); |
michael@0 | 1478 | return NS_SUCCEEDED(rv) && allowed; |
michael@0 | 1479 | } |
michael@0 | 1480 | |
michael@0 | 1481 | /** |
michael@0 | 1482 | * Wraps an nsIAuthPrompt so that it can be used as an nsIAuthPrompt2. This |
michael@0 | 1483 | * method is provided mainly for use by other methods in this file. |
michael@0 | 1484 | * |
michael@0 | 1485 | * *aAuthPrompt2 should be set to null before calling this function. |
michael@0 | 1486 | */ |
michael@0 | 1487 | inline void |
michael@0 | 1488 | NS_WrapAuthPrompt(nsIAuthPrompt *aAuthPrompt, nsIAuthPrompt2** aAuthPrompt2) |
michael@0 | 1489 | { |
michael@0 | 1490 | nsCOMPtr<nsIAuthPromptAdapterFactory> factory = |
michael@0 | 1491 | do_GetService(NS_AUTHPROMPT_ADAPTER_FACTORY_CONTRACTID); |
michael@0 | 1492 | if (!factory) |
michael@0 | 1493 | return; |
michael@0 | 1494 | |
michael@0 | 1495 | NS_WARNING("Using deprecated nsIAuthPrompt"); |
michael@0 | 1496 | factory->CreateAdapter(aAuthPrompt, aAuthPrompt2); |
michael@0 | 1497 | } |
michael@0 | 1498 | |
michael@0 | 1499 | /** |
michael@0 | 1500 | * Gets an auth prompt from an interface requestor. This takes care of wrapping |
michael@0 | 1501 | * an nsIAuthPrompt so that it can be used as an nsIAuthPrompt2. |
michael@0 | 1502 | */ |
michael@0 | 1503 | inline void |
michael@0 | 1504 | NS_QueryAuthPrompt2(nsIInterfaceRequestor *aCallbacks, |
michael@0 | 1505 | nsIAuthPrompt2 **aAuthPrompt) |
michael@0 | 1506 | { |
michael@0 | 1507 | CallGetInterface(aCallbacks, aAuthPrompt); |
michael@0 | 1508 | if (*aAuthPrompt) |
michael@0 | 1509 | return; |
michael@0 | 1510 | |
michael@0 | 1511 | // Maybe only nsIAuthPrompt is provided and we have to wrap it. |
michael@0 | 1512 | nsCOMPtr<nsIAuthPrompt> prompt(do_GetInterface(aCallbacks)); |
michael@0 | 1513 | if (!prompt) |
michael@0 | 1514 | return; |
michael@0 | 1515 | |
michael@0 | 1516 | NS_WrapAuthPrompt(prompt, aAuthPrompt); |
michael@0 | 1517 | } |
michael@0 | 1518 | |
michael@0 | 1519 | /** |
michael@0 | 1520 | * Gets an nsIAuthPrompt2 from a channel. Use this instead of |
michael@0 | 1521 | * NS_QueryNotificationCallbacks for better backwards compatibility. |
michael@0 | 1522 | */ |
michael@0 | 1523 | inline void |
michael@0 | 1524 | NS_QueryAuthPrompt2(nsIChannel *aChannel, |
michael@0 | 1525 | nsIAuthPrompt2 **aAuthPrompt) |
michael@0 | 1526 | { |
michael@0 | 1527 | *aAuthPrompt = nullptr; |
michael@0 | 1528 | |
michael@0 | 1529 | // We want to use any auth prompt we can find on the channel's callbacks, |
michael@0 | 1530 | // and if that fails use the loadgroup's prompt (if any) |
michael@0 | 1531 | // Therefore, we can't just use NS_QueryNotificationCallbacks, because |
michael@0 | 1532 | // that would prefer a loadgroup's nsIAuthPrompt2 over a channel's |
michael@0 | 1533 | // nsIAuthPrompt. |
michael@0 | 1534 | nsCOMPtr<nsIInterfaceRequestor> callbacks; |
michael@0 | 1535 | aChannel->GetNotificationCallbacks(getter_AddRefs(callbacks)); |
michael@0 | 1536 | if (callbacks) { |
michael@0 | 1537 | NS_QueryAuthPrompt2(callbacks, aAuthPrompt); |
michael@0 | 1538 | if (*aAuthPrompt) |
michael@0 | 1539 | return; |
michael@0 | 1540 | } |
michael@0 | 1541 | |
michael@0 | 1542 | nsCOMPtr<nsILoadGroup> group; |
michael@0 | 1543 | aChannel->GetLoadGroup(getter_AddRefs(group)); |
michael@0 | 1544 | if (!group) |
michael@0 | 1545 | return; |
michael@0 | 1546 | |
michael@0 | 1547 | group->GetNotificationCallbacks(getter_AddRefs(callbacks)); |
michael@0 | 1548 | if (!callbacks) |
michael@0 | 1549 | return; |
michael@0 | 1550 | NS_QueryAuthPrompt2(callbacks, aAuthPrompt); |
michael@0 | 1551 | } |
michael@0 | 1552 | |
michael@0 | 1553 | /* template helper */ |
michael@0 | 1554 | template <class T> inline void |
michael@0 | 1555 | NS_QueryNotificationCallbacks(nsIInterfaceRequestor *callbacks, |
michael@0 | 1556 | nsILoadGroup *loadGroup, |
michael@0 | 1557 | nsCOMPtr<T> &result) |
michael@0 | 1558 | { |
michael@0 | 1559 | NS_QueryNotificationCallbacks(callbacks, loadGroup, |
michael@0 | 1560 | NS_GET_TEMPLATE_IID(T), |
michael@0 | 1561 | getter_AddRefs(result)); |
michael@0 | 1562 | } |
michael@0 | 1563 | |
michael@0 | 1564 | /* template helper */ |
michael@0 | 1565 | template <class T> inline void |
michael@0 | 1566 | NS_QueryNotificationCallbacks(const nsCOMPtr<nsIInterfaceRequestor> &aCallbacks, |
michael@0 | 1567 | const nsCOMPtr<nsILoadGroup> &aLoadGroup, |
michael@0 | 1568 | nsCOMPtr<T> &aResult) |
michael@0 | 1569 | { |
michael@0 | 1570 | NS_QueryNotificationCallbacks(aCallbacks.get(), aLoadGroup.get(), aResult); |
michael@0 | 1571 | } |
michael@0 | 1572 | |
michael@0 | 1573 | /* template helper */ |
michael@0 | 1574 | template <class T> inline void |
michael@0 | 1575 | NS_QueryNotificationCallbacks(const nsCOMPtr<nsIChannel> &aChannel, |
michael@0 | 1576 | nsCOMPtr<T> &aResult) |
michael@0 | 1577 | { |
michael@0 | 1578 | NS_QueryNotificationCallbacks(aChannel.get(), aResult); |
michael@0 | 1579 | } |
michael@0 | 1580 | |
michael@0 | 1581 | /** |
michael@0 | 1582 | * This function returns a nsIInterfaceRequestor instance that returns the |
michael@0 | 1583 | * same result as NS_QueryNotificationCallbacks when queried. It is useful |
michael@0 | 1584 | * as the value for nsISocketTransport::securityCallbacks. |
michael@0 | 1585 | */ |
michael@0 | 1586 | inline nsresult |
michael@0 | 1587 | NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor *callbacks, |
michael@0 | 1588 | nsILoadGroup *loadGroup, |
michael@0 | 1589 | nsIEventTarget *target, |
michael@0 | 1590 | nsIInterfaceRequestor **result) |
michael@0 | 1591 | { |
michael@0 | 1592 | nsCOMPtr<nsIInterfaceRequestor> cbs; |
michael@0 | 1593 | if (loadGroup) |
michael@0 | 1594 | loadGroup->GetNotificationCallbacks(getter_AddRefs(cbs)); |
michael@0 | 1595 | return NS_NewInterfaceRequestorAggregation(callbacks, cbs, target, result); |
michael@0 | 1596 | } |
michael@0 | 1597 | |
michael@0 | 1598 | inline nsresult |
michael@0 | 1599 | NS_NewNotificationCallbacksAggregation(nsIInterfaceRequestor *callbacks, |
michael@0 | 1600 | nsILoadGroup *loadGroup, |
michael@0 | 1601 | nsIInterfaceRequestor **result) |
michael@0 | 1602 | { |
michael@0 | 1603 | return NS_NewNotificationCallbacksAggregation(callbacks, loadGroup, nullptr, result); |
michael@0 | 1604 | } |
michael@0 | 1605 | |
michael@0 | 1606 | /** |
michael@0 | 1607 | * Helper function for testing online/offline state of the browser. |
michael@0 | 1608 | */ |
michael@0 | 1609 | inline bool |
michael@0 | 1610 | NS_IsOffline() |
michael@0 | 1611 | { |
michael@0 | 1612 | bool offline = true; |
michael@0 | 1613 | nsCOMPtr<nsIIOService> ios = do_GetIOService(); |
michael@0 | 1614 | if (ios) |
michael@0 | 1615 | ios->GetOffline(&offline); |
michael@0 | 1616 | return offline; |
michael@0 | 1617 | } |
michael@0 | 1618 | |
michael@0 | 1619 | /** |
michael@0 | 1620 | * Helper functions for implementing nsINestedURI::innermostURI. |
michael@0 | 1621 | * |
michael@0 | 1622 | * Note that NS_DoImplGetInnermostURI is "private" -- call |
michael@0 | 1623 | * NS_ImplGetInnermostURI instead. |
michael@0 | 1624 | */ |
michael@0 | 1625 | inline nsresult |
michael@0 | 1626 | NS_DoImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result) |
michael@0 | 1627 | { |
michael@0 | 1628 | NS_PRECONDITION(nestedURI, "Must have a nested URI!"); |
michael@0 | 1629 | NS_PRECONDITION(!*result, "Must have null *result"); |
michael@0 | 1630 | |
michael@0 | 1631 | nsCOMPtr<nsIURI> inner; |
michael@0 | 1632 | nsresult rv = nestedURI->GetInnerURI(getter_AddRefs(inner)); |
michael@0 | 1633 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1634 | |
michael@0 | 1635 | // We may need to loop here until we reach the innermost |
michael@0 | 1636 | // URI. |
michael@0 | 1637 | nsCOMPtr<nsINestedURI> nestedInner(do_QueryInterface(inner)); |
michael@0 | 1638 | while (nestedInner) { |
michael@0 | 1639 | rv = nestedInner->GetInnerURI(getter_AddRefs(inner)); |
michael@0 | 1640 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1641 | nestedInner = do_QueryInterface(inner); |
michael@0 | 1642 | } |
michael@0 | 1643 | |
michael@0 | 1644 | // Found the innermost one if we reach here. |
michael@0 | 1645 | inner.swap(*result); |
michael@0 | 1646 | |
michael@0 | 1647 | return rv; |
michael@0 | 1648 | } |
michael@0 | 1649 | |
michael@0 | 1650 | inline nsresult |
michael@0 | 1651 | NS_ImplGetInnermostURI(nsINestedURI* nestedURI, nsIURI** result) |
michael@0 | 1652 | { |
michael@0 | 1653 | // Make it safe to use swap() |
michael@0 | 1654 | *result = nullptr; |
michael@0 | 1655 | |
michael@0 | 1656 | return NS_DoImplGetInnermostURI(nestedURI, result); |
michael@0 | 1657 | } |
michael@0 | 1658 | |
michael@0 | 1659 | /** |
michael@0 | 1660 | * Helper function that ensures that |result| is a URI that's safe to |
michael@0 | 1661 | * return. If |uri| is immutable, just returns it, otherwise returns |
michael@0 | 1662 | * a clone. |uri| must not be null. |
michael@0 | 1663 | */ |
michael@0 | 1664 | inline nsresult |
michael@0 | 1665 | NS_EnsureSafeToReturn(nsIURI* uri, nsIURI** result) |
michael@0 | 1666 | { |
michael@0 | 1667 | NS_PRECONDITION(uri, "Must have a URI"); |
michael@0 | 1668 | |
michael@0 | 1669 | // Assume mutable until told otherwise |
michael@0 | 1670 | bool isMutable = true; |
michael@0 | 1671 | nsCOMPtr<nsIMutable> mutableObj(do_QueryInterface(uri)); |
michael@0 | 1672 | if (mutableObj) { |
michael@0 | 1673 | nsresult rv = mutableObj->GetMutable(&isMutable); |
michael@0 | 1674 | isMutable = NS_FAILED(rv) || isMutable; |
michael@0 | 1675 | } |
michael@0 | 1676 | |
michael@0 | 1677 | if (!isMutable) { |
michael@0 | 1678 | NS_ADDREF(*result = uri); |
michael@0 | 1679 | return NS_OK; |
michael@0 | 1680 | } |
michael@0 | 1681 | |
michael@0 | 1682 | nsresult rv = uri->Clone(result); |
michael@0 | 1683 | if (NS_SUCCEEDED(rv) && !*result) { |
michael@0 | 1684 | NS_ERROR("nsIURI.clone contract was violated"); |
michael@0 | 1685 | return NS_ERROR_UNEXPECTED; |
michael@0 | 1686 | } |
michael@0 | 1687 | |
michael@0 | 1688 | return rv; |
michael@0 | 1689 | } |
michael@0 | 1690 | |
michael@0 | 1691 | /** |
michael@0 | 1692 | * Helper function that tries to set the argument URI to be immutable |
michael@0 | 1693 | */ |
michael@0 | 1694 | inline void |
michael@0 | 1695 | NS_TryToSetImmutable(nsIURI* uri) |
michael@0 | 1696 | { |
michael@0 | 1697 | nsCOMPtr<nsIMutable> mutableObj(do_QueryInterface(uri)); |
michael@0 | 1698 | if (mutableObj) { |
michael@0 | 1699 | mutableObj->SetMutable(false); |
michael@0 | 1700 | } |
michael@0 | 1701 | } |
michael@0 | 1702 | |
michael@0 | 1703 | /** |
michael@0 | 1704 | * Helper function for calling ToImmutableURI. If all else fails, returns |
michael@0 | 1705 | * the input URI. The optional second arg indicates whether we had to fall |
michael@0 | 1706 | * back to the input URI. Passing in a null URI is ok. |
michael@0 | 1707 | */ |
michael@0 | 1708 | inline already_AddRefed<nsIURI> |
michael@0 | 1709 | NS_TryToMakeImmutable(nsIURI* uri, |
michael@0 | 1710 | nsresult* outRv = nullptr) |
michael@0 | 1711 | { |
michael@0 | 1712 | nsresult rv; |
michael@0 | 1713 | nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv); |
michael@0 | 1714 | |
michael@0 | 1715 | nsCOMPtr<nsIURI> result; |
michael@0 | 1716 | if (NS_SUCCEEDED(rv)) { |
michael@0 | 1717 | NS_ASSERTION(util, "do_GetNetUtil lied"); |
michael@0 | 1718 | rv = util->ToImmutableURI(uri, getter_AddRefs(result)); |
michael@0 | 1719 | } |
michael@0 | 1720 | |
michael@0 | 1721 | if (NS_FAILED(rv)) { |
michael@0 | 1722 | result = uri; |
michael@0 | 1723 | } |
michael@0 | 1724 | |
michael@0 | 1725 | if (outRv) { |
michael@0 | 1726 | *outRv = rv; |
michael@0 | 1727 | } |
michael@0 | 1728 | |
michael@0 | 1729 | return result.forget(); |
michael@0 | 1730 | } |
michael@0 | 1731 | |
michael@0 | 1732 | /** |
michael@0 | 1733 | * Helper function for testing whether the given URI, or any of its |
michael@0 | 1734 | * inner URIs, has all the given protocol flags. |
michael@0 | 1735 | */ |
michael@0 | 1736 | inline nsresult |
michael@0 | 1737 | NS_URIChainHasFlags(nsIURI *uri, |
michael@0 | 1738 | uint32_t flags, |
michael@0 | 1739 | bool *result) |
michael@0 | 1740 | { |
michael@0 | 1741 | nsresult rv; |
michael@0 | 1742 | nsCOMPtr<nsINetUtil> util = do_GetNetUtil(&rv); |
michael@0 | 1743 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1744 | |
michael@0 | 1745 | return util->URIChainHasFlags(uri, flags, result); |
michael@0 | 1746 | } |
michael@0 | 1747 | |
michael@0 | 1748 | /** |
michael@0 | 1749 | * Helper function for getting the innermost URI for a given URI. The return |
michael@0 | 1750 | * value could be just the object passed in if it's not a nested URI. |
michael@0 | 1751 | */ |
michael@0 | 1752 | inline already_AddRefed<nsIURI> |
michael@0 | 1753 | NS_GetInnermostURI(nsIURI* aURI) |
michael@0 | 1754 | { |
michael@0 | 1755 | NS_PRECONDITION(aURI, "Must have URI"); |
michael@0 | 1756 | |
michael@0 | 1757 | nsCOMPtr<nsIURI> uri = aURI; |
michael@0 | 1758 | |
michael@0 | 1759 | nsCOMPtr<nsINestedURI> nestedURI(do_QueryInterface(uri)); |
michael@0 | 1760 | if (!nestedURI) { |
michael@0 | 1761 | return uri.forget(); |
michael@0 | 1762 | } |
michael@0 | 1763 | |
michael@0 | 1764 | nsresult rv = nestedURI->GetInnermostURI(getter_AddRefs(uri)); |
michael@0 | 1765 | if (NS_FAILED(rv)) { |
michael@0 | 1766 | return nullptr; |
michael@0 | 1767 | } |
michael@0 | 1768 | |
michael@0 | 1769 | return uri.forget(); |
michael@0 | 1770 | } |
michael@0 | 1771 | |
michael@0 | 1772 | /** |
michael@0 | 1773 | * Get the "final" URI for a channel. This is either the same as GetURI or |
michael@0 | 1774 | * GetOriginalURI, depending on whether this channel has |
michael@0 | 1775 | * nsIChanel::LOAD_REPLACE set. For channels without that flag set, the final |
michael@0 | 1776 | * URI is the original URI, while for ones with the flag the final URI is the |
michael@0 | 1777 | * channel URI. |
michael@0 | 1778 | */ |
michael@0 | 1779 | inline nsresult |
michael@0 | 1780 | NS_GetFinalChannelURI(nsIChannel* channel, nsIURI** uri) |
michael@0 | 1781 | { |
michael@0 | 1782 | *uri = nullptr; |
michael@0 | 1783 | nsLoadFlags loadFlags = 0; |
michael@0 | 1784 | nsresult rv = channel->GetLoadFlags(&loadFlags); |
michael@0 | 1785 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1786 | |
michael@0 | 1787 | if (loadFlags & nsIChannel::LOAD_REPLACE) { |
michael@0 | 1788 | return channel->GetURI(uri); |
michael@0 | 1789 | } |
michael@0 | 1790 | |
michael@0 | 1791 | return channel->GetOriginalURI(uri); |
michael@0 | 1792 | } |
michael@0 | 1793 | |
michael@0 | 1794 | // NS_SecurityHashURI must return the same hash value for any two URIs that |
michael@0 | 1795 | // compare equal according to NS_SecurityCompareURIs. Unfortunately, in the |
michael@0 | 1796 | // case of files, it's not clear we can do anything better than returning |
michael@0 | 1797 | // the schemeHash, so hashing files degenerates to storing them in a list. |
michael@0 | 1798 | inline uint32_t |
michael@0 | 1799 | NS_SecurityHashURI(nsIURI* aURI) |
michael@0 | 1800 | { |
michael@0 | 1801 | nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI); |
michael@0 | 1802 | |
michael@0 | 1803 | nsAutoCString scheme; |
michael@0 | 1804 | uint32_t schemeHash = 0; |
michael@0 | 1805 | if (NS_SUCCEEDED(baseURI->GetScheme(scheme))) |
michael@0 | 1806 | schemeHash = mozilla::HashString(scheme); |
michael@0 | 1807 | |
michael@0 | 1808 | // TODO figure out how to hash file:// URIs |
michael@0 | 1809 | if (scheme.EqualsLiteral("file")) |
michael@0 | 1810 | return schemeHash; // sad face |
michael@0 | 1811 | |
michael@0 | 1812 | if (scheme.EqualsLiteral("imap") || |
michael@0 | 1813 | scheme.EqualsLiteral("mailbox") || |
michael@0 | 1814 | scheme.EqualsLiteral("news")) |
michael@0 | 1815 | { |
michael@0 | 1816 | nsAutoCString spec; |
michael@0 | 1817 | uint32_t specHash; |
michael@0 | 1818 | nsresult res = baseURI->GetSpec(spec); |
michael@0 | 1819 | if (NS_SUCCEEDED(res)) |
michael@0 | 1820 | specHash = mozilla::HashString(spec); |
michael@0 | 1821 | else |
michael@0 | 1822 | specHash = static_cast<uint32_t>(res); |
michael@0 | 1823 | return specHash; |
michael@0 | 1824 | } |
michael@0 | 1825 | |
michael@0 | 1826 | nsAutoCString host; |
michael@0 | 1827 | uint32_t hostHash = 0; |
michael@0 | 1828 | if (NS_SUCCEEDED(baseURI->GetAsciiHost(host))) |
michael@0 | 1829 | hostHash = mozilla::HashString(host); |
michael@0 | 1830 | |
michael@0 | 1831 | return mozilla::AddToHash(schemeHash, hostHash, NS_GetRealPort(baseURI)); |
michael@0 | 1832 | } |
michael@0 | 1833 | |
michael@0 | 1834 | inline bool |
michael@0 | 1835 | NS_SecurityCompareURIs(nsIURI* aSourceURI, |
michael@0 | 1836 | nsIURI* aTargetURI, |
michael@0 | 1837 | bool aStrictFileOriginPolicy) |
michael@0 | 1838 | { |
michael@0 | 1839 | // Note that this is not an Equals() test on purpose -- for URIs that don't |
michael@0 | 1840 | // support host/port, we want equality to basically be object identity, for |
michael@0 | 1841 | // security purposes. Otherwise, for example, two javascript: URIs that |
michael@0 | 1842 | // are otherwise unrelated could end up "same origin", which would be |
michael@0 | 1843 | // unfortunate. |
michael@0 | 1844 | if (aSourceURI && aSourceURI == aTargetURI) |
michael@0 | 1845 | { |
michael@0 | 1846 | return true; |
michael@0 | 1847 | } |
michael@0 | 1848 | |
michael@0 | 1849 | if (!aTargetURI || !aSourceURI) |
michael@0 | 1850 | { |
michael@0 | 1851 | return false; |
michael@0 | 1852 | } |
michael@0 | 1853 | |
michael@0 | 1854 | // If either URI is a nested URI, get the base URI |
michael@0 | 1855 | nsCOMPtr<nsIURI> sourceBaseURI = NS_GetInnermostURI(aSourceURI); |
michael@0 | 1856 | nsCOMPtr<nsIURI> targetBaseURI = NS_GetInnermostURI(aTargetURI); |
michael@0 | 1857 | |
michael@0 | 1858 | // If either uri is an nsIURIWithPrincipal |
michael@0 | 1859 | nsCOMPtr<nsIURIWithPrincipal> uriPrinc = do_QueryInterface(sourceBaseURI); |
michael@0 | 1860 | if (uriPrinc) { |
michael@0 | 1861 | uriPrinc->GetPrincipalUri(getter_AddRefs(sourceBaseURI)); |
michael@0 | 1862 | } |
michael@0 | 1863 | |
michael@0 | 1864 | uriPrinc = do_QueryInterface(targetBaseURI); |
michael@0 | 1865 | if (uriPrinc) { |
michael@0 | 1866 | uriPrinc->GetPrincipalUri(getter_AddRefs(targetBaseURI)); |
michael@0 | 1867 | } |
michael@0 | 1868 | |
michael@0 | 1869 | if (!sourceBaseURI || !targetBaseURI) |
michael@0 | 1870 | return false; |
michael@0 | 1871 | |
michael@0 | 1872 | // Compare schemes |
michael@0 | 1873 | nsAutoCString targetScheme; |
michael@0 | 1874 | bool sameScheme = false; |
michael@0 | 1875 | if (NS_FAILED( targetBaseURI->GetScheme(targetScheme) ) || |
michael@0 | 1876 | NS_FAILED( sourceBaseURI->SchemeIs(targetScheme.get(), &sameScheme) ) || |
michael@0 | 1877 | !sameScheme) |
michael@0 | 1878 | { |
michael@0 | 1879 | // Not same-origin if schemes differ |
michael@0 | 1880 | return false; |
michael@0 | 1881 | } |
michael@0 | 1882 | |
michael@0 | 1883 | // For file scheme, reject unless the files are identical. See |
michael@0 | 1884 | // NS_RelaxStrictFileOriginPolicy for enforcing file same-origin checking |
michael@0 | 1885 | if (targetScheme.EqualsLiteral("file")) |
michael@0 | 1886 | { |
michael@0 | 1887 | // in traditional unsafe behavior all files are the same origin |
michael@0 | 1888 | if (!aStrictFileOriginPolicy) |
michael@0 | 1889 | return true; |
michael@0 | 1890 | |
michael@0 | 1891 | nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(sourceBaseURI)); |
michael@0 | 1892 | nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(targetBaseURI)); |
michael@0 | 1893 | |
michael@0 | 1894 | if (!sourceFileURL || !targetFileURL) |
michael@0 | 1895 | return false; |
michael@0 | 1896 | |
michael@0 | 1897 | nsCOMPtr<nsIFile> sourceFile, targetFile; |
michael@0 | 1898 | |
michael@0 | 1899 | sourceFileURL->GetFile(getter_AddRefs(sourceFile)); |
michael@0 | 1900 | targetFileURL->GetFile(getter_AddRefs(targetFile)); |
michael@0 | 1901 | |
michael@0 | 1902 | if (!sourceFile || !targetFile) |
michael@0 | 1903 | return false; |
michael@0 | 1904 | |
michael@0 | 1905 | // Otherwise they had better match |
michael@0 | 1906 | bool filesAreEqual = false; |
michael@0 | 1907 | nsresult rv = sourceFile->Equals(targetFile, &filesAreEqual); |
michael@0 | 1908 | return NS_SUCCEEDED(rv) && filesAreEqual; |
michael@0 | 1909 | } |
michael@0 | 1910 | |
michael@0 | 1911 | // Special handling for mailnews schemes |
michael@0 | 1912 | if (targetScheme.EqualsLiteral("imap") || |
michael@0 | 1913 | targetScheme.EqualsLiteral("mailbox") || |
michael@0 | 1914 | targetScheme.EqualsLiteral("news")) |
michael@0 | 1915 | { |
michael@0 | 1916 | // Each message is a distinct trust domain; use the |
michael@0 | 1917 | // whole spec for comparison |
michael@0 | 1918 | nsAutoCString targetSpec; |
michael@0 | 1919 | nsAutoCString sourceSpec; |
michael@0 | 1920 | return ( NS_SUCCEEDED( targetBaseURI->GetSpec(targetSpec) ) && |
michael@0 | 1921 | NS_SUCCEEDED( sourceBaseURI->GetSpec(sourceSpec) ) && |
michael@0 | 1922 | targetSpec.Equals(sourceSpec) ); |
michael@0 | 1923 | } |
michael@0 | 1924 | |
michael@0 | 1925 | // Compare hosts |
michael@0 | 1926 | nsAutoCString targetHost; |
michael@0 | 1927 | nsAutoCString sourceHost; |
michael@0 | 1928 | if (NS_FAILED( targetBaseURI->GetAsciiHost(targetHost) ) || |
michael@0 | 1929 | NS_FAILED( sourceBaseURI->GetAsciiHost(sourceHost) )) |
michael@0 | 1930 | { |
michael@0 | 1931 | return false; |
michael@0 | 1932 | } |
michael@0 | 1933 | |
michael@0 | 1934 | nsCOMPtr<nsIStandardURL> targetURL(do_QueryInterface(targetBaseURI)); |
michael@0 | 1935 | nsCOMPtr<nsIStandardURL> sourceURL(do_QueryInterface(sourceBaseURI)); |
michael@0 | 1936 | if (!targetURL || !sourceURL) |
michael@0 | 1937 | { |
michael@0 | 1938 | return false; |
michael@0 | 1939 | } |
michael@0 | 1940 | |
michael@0 | 1941 | #ifdef MOZILLA_INTERNAL_API |
michael@0 | 1942 | if (!targetHost.Equals(sourceHost, nsCaseInsensitiveCStringComparator() )) |
michael@0 | 1943 | #else |
michael@0 | 1944 | if (!targetHost.Equals(sourceHost, CaseInsensitiveCompare)) |
michael@0 | 1945 | #endif |
michael@0 | 1946 | { |
michael@0 | 1947 | return false; |
michael@0 | 1948 | } |
michael@0 | 1949 | |
michael@0 | 1950 | return NS_GetRealPort(targetBaseURI) == NS_GetRealPort(sourceBaseURI); |
michael@0 | 1951 | } |
michael@0 | 1952 | |
michael@0 | 1953 | inline bool |
michael@0 | 1954 | NS_URIIsLocalFile(nsIURI *aURI) |
michael@0 | 1955 | { |
michael@0 | 1956 | nsCOMPtr<nsINetUtil> util = do_GetNetUtil(); |
michael@0 | 1957 | |
michael@0 | 1958 | bool isFile; |
michael@0 | 1959 | return util && NS_SUCCEEDED(util->ProtocolHasFlags(aURI, |
michael@0 | 1960 | nsIProtocolHandler::URI_IS_LOCAL_FILE, |
michael@0 | 1961 | &isFile)) && |
michael@0 | 1962 | isFile; |
michael@0 | 1963 | } |
michael@0 | 1964 | |
michael@0 | 1965 | // When strict file origin policy is enabled, SecurityCompareURIs will fail for |
michael@0 | 1966 | // file URIs that do not point to the same local file. This call provides an |
michael@0 | 1967 | // alternate file-specific origin check that allows target files that are |
michael@0 | 1968 | // contained in the same directory as the source. |
michael@0 | 1969 | // |
michael@0 | 1970 | // https://developer.mozilla.org/en-US/docs/Same-origin_policy_for_file:_URIs |
michael@0 | 1971 | inline bool |
michael@0 | 1972 | NS_RelaxStrictFileOriginPolicy(nsIURI *aTargetURI, |
michael@0 | 1973 | nsIURI *aSourceURI, |
michael@0 | 1974 | bool aAllowDirectoryTarget = false) |
michael@0 | 1975 | { |
michael@0 | 1976 | if (!NS_URIIsLocalFile(aTargetURI)) { |
michael@0 | 1977 | // This is probably not what the caller intended |
michael@0 | 1978 | NS_NOTREACHED("NS_RelaxStrictFileOriginPolicy called with non-file URI"); |
michael@0 | 1979 | return false; |
michael@0 | 1980 | } |
michael@0 | 1981 | |
michael@0 | 1982 | if (!NS_URIIsLocalFile(aSourceURI)) { |
michael@0 | 1983 | // If the source is not also a file: uri then forget it |
michael@0 | 1984 | // (don't want resource: principals in a file: doc) |
michael@0 | 1985 | // |
michael@0 | 1986 | // note: we're not de-nesting jar: uris here, we want to |
michael@0 | 1987 | // keep archive content bottled up in its own little island |
michael@0 | 1988 | return false; |
michael@0 | 1989 | } |
michael@0 | 1990 | |
michael@0 | 1991 | // |
michael@0 | 1992 | // pull out the internal files |
michael@0 | 1993 | // |
michael@0 | 1994 | nsCOMPtr<nsIFileURL> targetFileURL(do_QueryInterface(aTargetURI)); |
michael@0 | 1995 | nsCOMPtr<nsIFileURL> sourceFileURL(do_QueryInterface(aSourceURI)); |
michael@0 | 1996 | nsCOMPtr<nsIFile> targetFile; |
michael@0 | 1997 | nsCOMPtr<nsIFile> sourceFile; |
michael@0 | 1998 | bool targetIsDir; |
michael@0 | 1999 | |
michael@0 | 2000 | // Make sure targetFile is not a directory (bug 209234) |
michael@0 | 2001 | // and that it exists w/out unescaping (bug 395343) |
michael@0 | 2002 | if (!sourceFileURL || !targetFileURL || |
michael@0 | 2003 | NS_FAILED(targetFileURL->GetFile(getter_AddRefs(targetFile))) || |
michael@0 | 2004 | NS_FAILED(sourceFileURL->GetFile(getter_AddRefs(sourceFile))) || |
michael@0 | 2005 | !targetFile || !sourceFile || |
michael@0 | 2006 | NS_FAILED(targetFile->Normalize()) || |
michael@0 | 2007 | #ifndef MOZ_WIDGET_ANDROID |
michael@0 | 2008 | NS_FAILED(sourceFile->Normalize()) || |
michael@0 | 2009 | #endif |
michael@0 | 2010 | (!aAllowDirectoryTarget && |
michael@0 | 2011 | (NS_FAILED(targetFile->IsDirectory(&targetIsDir)) || targetIsDir))) { |
michael@0 | 2012 | return false; |
michael@0 | 2013 | } |
michael@0 | 2014 | |
michael@0 | 2015 | // |
michael@0 | 2016 | // If the file to be loaded is in a subdirectory of the source |
michael@0 | 2017 | // (or same-dir if source is not a directory) then it will |
michael@0 | 2018 | // inherit its source principal and be scriptable by that source. |
michael@0 | 2019 | // |
michael@0 | 2020 | bool sourceIsDir; |
michael@0 | 2021 | bool allowed = false; |
michael@0 | 2022 | nsresult rv = sourceFile->IsDirectory(&sourceIsDir); |
michael@0 | 2023 | if (NS_SUCCEEDED(rv) && sourceIsDir) { |
michael@0 | 2024 | rv = sourceFile->Contains(targetFile, true, &allowed); |
michael@0 | 2025 | } else { |
michael@0 | 2026 | nsCOMPtr<nsIFile> sourceParent; |
michael@0 | 2027 | rv = sourceFile->GetParent(getter_AddRefs(sourceParent)); |
michael@0 | 2028 | if (NS_SUCCEEDED(rv) && sourceParent) { |
michael@0 | 2029 | rv = sourceParent->Equals(targetFile, &allowed); |
michael@0 | 2030 | if (NS_FAILED(rv) || !allowed) { |
michael@0 | 2031 | rv = sourceParent->Contains(targetFile, true, &allowed); |
michael@0 | 2032 | } else { |
michael@0 | 2033 | MOZ_ASSERT(aAllowDirectoryTarget, |
michael@0 | 2034 | "sourceFile->Parent == targetFile, but targetFile " |
michael@0 | 2035 | "should've been disallowed if it is a directory"); |
michael@0 | 2036 | } |
michael@0 | 2037 | } |
michael@0 | 2038 | } |
michael@0 | 2039 | |
michael@0 | 2040 | if (NS_SUCCEEDED(rv) && allowed) { |
michael@0 | 2041 | return true; |
michael@0 | 2042 | } |
michael@0 | 2043 | |
michael@0 | 2044 | return false; |
michael@0 | 2045 | } |
michael@0 | 2046 | |
michael@0 | 2047 | inline bool |
michael@0 | 2048 | NS_IsInternalSameURIRedirect(nsIChannel *aOldChannel, |
michael@0 | 2049 | nsIChannel *aNewChannel, |
michael@0 | 2050 | uint32_t aFlags) |
michael@0 | 2051 | { |
michael@0 | 2052 | if (!(aFlags & nsIChannelEventSink::REDIRECT_INTERNAL)) { |
michael@0 | 2053 | return false; |
michael@0 | 2054 | } |
michael@0 | 2055 | |
michael@0 | 2056 | nsCOMPtr<nsIURI> oldURI, newURI; |
michael@0 | 2057 | aOldChannel->GetURI(getter_AddRefs(oldURI)); |
michael@0 | 2058 | aNewChannel->GetURI(getter_AddRefs(newURI)); |
michael@0 | 2059 | |
michael@0 | 2060 | if (!oldURI || !newURI) { |
michael@0 | 2061 | return false; |
michael@0 | 2062 | } |
michael@0 | 2063 | |
michael@0 | 2064 | bool res; |
michael@0 | 2065 | return NS_SUCCEEDED(oldURI->Equals(newURI, &res)) && res; |
michael@0 | 2066 | } |
michael@0 | 2067 | |
michael@0 | 2068 | inline nsresult |
michael@0 | 2069 | NS_LinkRedirectChannels(uint32_t channelId, |
michael@0 | 2070 | nsIParentChannel *parentChannel, |
michael@0 | 2071 | nsIChannel** _result) |
michael@0 | 2072 | { |
michael@0 | 2073 | nsresult rv; |
michael@0 | 2074 | |
michael@0 | 2075 | nsCOMPtr<nsIRedirectChannelRegistrar> registrar = |
michael@0 | 2076 | do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv); |
michael@0 | 2077 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 2078 | |
michael@0 | 2079 | return registrar->LinkChannels(channelId, |
michael@0 | 2080 | parentChannel, |
michael@0 | 2081 | _result); |
michael@0 | 2082 | } |
michael@0 | 2083 | |
michael@0 | 2084 | /** |
michael@0 | 2085 | * Helper function to create a random URL string that's properly formed |
michael@0 | 2086 | * but guaranteed to be invalid. |
michael@0 | 2087 | */ |
michael@0 | 2088 | #define NS_FAKE_SCHEME "http://" |
michael@0 | 2089 | #define NS_FAKE_TLD ".invalid" |
michael@0 | 2090 | inline nsresult |
michael@0 | 2091 | NS_MakeRandomInvalidURLString(nsCString& result) |
michael@0 | 2092 | { |
michael@0 | 2093 | nsresult rv; |
michael@0 | 2094 | nsCOMPtr<nsIUUIDGenerator> uuidgen = |
michael@0 | 2095 | do_GetService("@mozilla.org/uuid-generator;1", &rv); |
michael@0 | 2096 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 2097 | |
michael@0 | 2098 | nsID idee; |
michael@0 | 2099 | rv = uuidgen->GenerateUUIDInPlace(&idee); |
michael@0 | 2100 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 2101 | |
michael@0 | 2102 | char chars[NSID_LENGTH]; |
michael@0 | 2103 | idee.ToProvidedString(chars); |
michael@0 | 2104 | |
michael@0 | 2105 | result.AssignLiteral(NS_FAKE_SCHEME); |
michael@0 | 2106 | // Strip off the '{' and '}' at the beginning and end of the UUID |
michael@0 | 2107 | result.Append(chars + 1, NSID_LENGTH - 3); |
michael@0 | 2108 | result.AppendLiteral(NS_FAKE_TLD); |
michael@0 | 2109 | |
michael@0 | 2110 | return NS_OK; |
michael@0 | 2111 | } |
michael@0 | 2112 | #undef NS_FAKE_SCHEME |
michael@0 | 2113 | #undef NS_FAKE_TLD |
michael@0 | 2114 | |
michael@0 | 2115 | /** |
michael@0 | 2116 | * Helper function to determine whether urlString is Java-compatible -- |
michael@0 | 2117 | * whether it can be passed to the Java URL(String) constructor without the |
michael@0 | 2118 | * latter throwing a MalformedURLException, or without Java otherwise |
michael@0 | 2119 | * mishandling it. This function (in effect) implements a scheme whitelist |
michael@0 | 2120 | * for Java. |
michael@0 | 2121 | */ |
michael@0 | 2122 | inline nsresult |
michael@0 | 2123 | NS_CheckIsJavaCompatibleURLString(nsCString& urlString, bool *result) |
michael@0 | 2124 | { |
michael@0 | 2125 | *result = false; // Default to "no" |
michael@0 | 2126 | |
michael@0 | 2127 | nsresult rv = NS_OK; |
michael@0 | 2128 | nsCOMPtr<nsIURLParser> urlParser = |
michael@0 | 2129 | do_GetService(NS_STDURLPARSER_CONTRACTID, &rv); |
michael@0 | 2130 | if (NS_FAILED(rv) || !urlParser) |
michael@0 | 2131 | return NS_ERROR_FAILURE; |
michael@0 | 2132 | |
michael@0 | 2133 | bool compatible = true; |
michael@0 | 2134 | uint32_t schemePos = 0; |
michael@0 | 2135 | int32_t schemeLen = 0; |
michael@0 | 2136 | urlParser->ParseURL(urlString.get(), -1, &schemePos, &schemeLen, |
michael@0 | 2137 | nullptr, nullptr, nullptr, nullptr); |
michael@0 | 2138 | if (schemeLen != -1) { |
michael@0 | 2139 | nsCString scheme; |
michael@0 | 2140 | scheme.Assign(urlString.get() + schemePos, schemeLen); |
michael@0 | 2141 | // By default Java only understands a small number of URL schemes, and of |
michael@0 | 2142 | // these only some can legitimately represent a browser page's "origin" |
michael@0 | 2143 | // (and be something we can legitimately expect Java to handle ... or not |
michael@0 | 2144 | // to mishandle). |
michael@0 | 2145 | // |
michael@0 | 2146 | // Besides those listed below, the OJI plugin understands the "jar", |
michael@0 | 2147 | // "mailto", "netdoc", "javascript" and "rmi" schemes, and Java Plugin2 |
michael@0 | 2148 | // also understands the "about" scheme. We actually pass "about" URLs |
michael@0 | 2149 | // to Java ("about:blank" when processing a javascript: URL (one that |
michael@0 | 2150 | // calls Java) from the location bar of a blank page, and (in FF4 and up) |
michael@0 | 2151 | // "about:home" when processing a javascript: URL from the home page). |
michael@0 | 2152 | // And Java doesn't appear to mishandle them (for example it doesn't allow |
michael@0 | 2153 | // connections to "about" URLs). But it doesn't make any sense to do |
michael@0 | 2154 | // same-origin checks on "about" URLs, so we don't include them in our |
michael@0 | 2155 | // scheme whitelist. |
michael@0 | 2156 | // |
michael@0 | 2157 | // The OJI plugin doesn't understand "chrome" URLs (only Java Plugin2 |
michael@0 | 2158 | // does) -- so we mustn't pass them to the OJI plugin. But we do need to |
michael@0 | 2159 | // pass "chrome" URLs to Java Plugin2: Java Plugin2 grants additional |
michael@0 | 2160 | // privileges to chrome "origins", and some extensions take advantage of |
michael@0 | 2161 | // this. For more information see bug 620773. |
michael@0 | 2162 | // |
michael@0 | 2163 | // As of FF4, we no longer support the OJI plugin. |
michael@0 | 2164 | if (PL_strcasecmp(scheme.get(), "http") && |
michael@0 | 2165 | PL_strcasecmp(scheme.get(), "https") && |
michael@0 | 2166 | PL_strcasecmp(scheme.get(), "file") && |
michael@0 | 2167 | PL_strcasecmp(scheme.get(), "ftp") && |
michael@0 | 2168 | PL_strcasecmp(scheme.get(), "gopher") && |
michael@0 | 2169 | PL_strcasecmp(scheme.get(), "chrome")) |
michael@0 | 2170 | compatible = false; |
michael@0 | 2171 | } else { |
michael@0 | 2172 | compatible = false; |
michael@0 | 2173 | } |
michael@0 | 2174 | |
michael@0 | 2175 | *result = compatible; |
michael@0 | 2176 | |
michael@0 | 2177 | return NS_OK; |
michael@0 | 2178 | } |
michael@0 | 2179 | |
michael@0 | 2180 | /** Given the first (disposition) token from a Content-Disposition header, |
michael@0 | 2181 | * tell whether it indicates the content is inline or attachment |
michael@0 | 2182 | * @param aDispToken the disposition token from the content-disposition header |
michael@0 | 2183 | */ |
michael@0 | 2184 | inline uint32_t |
michael@0 | 2185 | NS_GetContentDispositionFromToken(const nsAString& aDispToken) |
michael@0 | 2186 | { |
michael@0 | 2187 | // RFC 2183, section 2.8 says that an unknown disposition |
michael@0 | 2188 | // value should be treated as "attachment" |
michael@0 | 2189 | // If all of these tests eval to false, then we have a content-disposition of |
michael@0 | 2190 | // "attachment" or unknown |
michael@0 | 2191 | if (aDispToken.IsEmpty() || |
michael@0 | 2192 | aDispToken.LowerCaseEqualsLiteral("inline") || |
michael@0 | 2193 | // Broken sites just send |
michael@0 | 2194 | // Content-Disposition: filename="file" |
michael@0 | 2195 | // without a disposition token... screen those out. |
michael@0 | 2196 | StringHead(aDispToken, 8).LowerCaseEqualsLiteral("filename")) |
michael@0 | 2197 | return nsIChannel::DISPOSITION_INLINE; |
michael@0 | 2198 | |
michael@0 | 2199 | return nsIChannel::DISPOSITION_ATTACHMENT; |
michael@0 | 2200 | } |
michael@0 | 2201 | |
michael@0 | 2202 | /** Determine the disposition (inline/attachment) of the content based on the |
michael@0 | 2203 | * Content-Disposition header |
michael@0 | 2204 | * @param aHeader the content-disposition header (full value) |
michael@0 | 2205 | * @param aChan the channel the header came from |
michael@0 | 2206 | */ |
michael@0 | 2207 | inline uint32_t |
michael@0 | 2208 | NS_GetContentDispositionFromHeader(const nsACString& aHeader, nsIChannel *aChan = nullptr) |
michael@0 | 2209 | { |
michael@0 | 2210 | nsresult rv; |
michael@0 | 2211 | nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv); |
michael@0 | 2212 | if (NS_FAILED(rv)) |
michael@0 | 2213 | return nsIChannel::DISPOSITION_ATTACHMENT; |
michael@0 | 2214 | |
michael@0 | 2215 | nsAutoCString fallbackCharset; |
michael@0 | 2216 | if (aChan) { |
michael@0 | 2217 | nsCOMPtr<nsIURI> uri; |
michael@0 | 2218 | aChan->GetURI(getter_AddRefs(uri)); |
michael@0 | 2219 | if (uri) |
michael@0 | 2220 | uri->GetOriginCharset(fallbackCharset); |
michael@0 | 2221 | } |
michael@0 | 2222 | |
michael@0 | 2223 | nsAutoString dispToken; |
michael@0 | 2224 | rv = mimehdrpar->GetParameterHTTP(aHeader, "", fallbackCharset, true, nullptr, |
michael@0 | 2225 | dispToken); |
michael@0 | 2226 | |
michael@0 | 2227 | if (NS_FAILED(rv)) { |
michael@0 | 2228 | // special case (see bug 272541): empty disposition type handled as "inline" |
michael@0 | 2229 | if (rv == NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY) |
michael@0 | 2230 | return nsIChannel::DISPOSITION_INLINE; |
michael@0 | 2231 | return nsIChannel::DISPOSITION_ATTACHMENT; |
michael@0 | 2232 | } |
michael@0 | 2233 | |
michael@0 | 2234 | return NS_GetContentDispositionFromToken(dispToken); |
michael@0 | 2235 | } |
michael@0 | 2236 | |
michael@0 | 2237 | /** Extracts the filename out of a content-disposition header |
michael@0 | 2238 | * @param aFilename [out] The filename. Can be empty on error. |
michael@0 | 2239 | * @param aDisposition Value of a Content-Disposition header |
michael@0 | 2240 | * @param aURI Optional. Will be used to get a fallback charset for the |
michael@0 | 2241 | * filename, if it is QI'able to nsIURL |
michael@0 | 2242 | */ |
michael@0 | 2243 | inline nsresult |
michael@0 | 2244 | NS_GetFilenameFromDisposition(nsAString& aFilename, |
michael@0 | 2245 | const nsACString& aDisposition, |
michael@0 | 2246 | nsIURI* aURI = nullptr) |
michael@0 | 2247 | { |
michael@0 | 2248 | aFilename.Truncate(); |
michael@0 | 2249 | |
michael@0 | 2250 | nsresult rv; |
michael@0 | 2251 | nsCOMPtr<nsIMIMEHeaderParam> mimehdrpar = |
michael@0 | 2252 | do_GetService(NS_MIMEHEADERPARAM_CONTRACTID, &rv); |
michael@0 | 2253 | if (NS_FAILED(rv)) |
michael@0 | 2254 | return rv; |
michael@0 | 2255 | |
michael@0 | 2256 | nsCOMPtr<nsIURL> url = do_QueryInterface(aURI); |
michael@0 | 2257 | |
michael@0 | 2258 | nsAutoCString fallbackCharset; |
michael@0 | 2259 | if (url) |
michael@0 | 2260 | url->GetOriginCharset(fallbackCharset); |
michael@0 | 2261 | // Get the value of 'filename' parameter |
michael@0 | 2262 | rv = mimehdrpar->GetParameterHTTP(aDisposition, "filename", |
michael@0 | 2263 | fallbackCharset, true, nullptr, |
michael@0 | 2264 | aFilename); |
michael@0 | 2265 | |
michael@0 | 2266 | if (NS_FAILED(rv)) { |
michael@0 | 2267 | aFilename.Truncate(); |
michael@0 | 2268 | return rv; |
michael@0 | 2269 | } |
michael@0 | 2270 | |
michael@0 | 2271 | if (aFilename.IsEmpty()) |
michael@0 | 2272 | return NS_ERROR_NOT_AVAILABLE; |
michael@0 | 2273 | |
michael@0 | 2274 | return NS_OK; |
michael@0 | 2275 | } |
michael@0 | 2276 | |
michael@0 | 2277 | /** |
michael@0 | 2278 | * Make sure Personal Security Manager is initialized |
michael@0 | 2279 | */ |
michael@0 | 2280 | inline void |
michael@0 | 2281 | net_EnsurePSMInit() |
michael@0 | 2282 | { |
michael@0 | 2283 | nsCOMPtr<nsISocketProviderService> spserv = |
michael@0 | 2284 | do_GetService(NS_SOCKETPROVIDERSERVICE_CONTRACTID); |
michael@0 | 2285 | if (spserv) { |
michael@0 | 2286 | nsCOMPtr<nsISocketProvider> provider; |
michael@0 | 2287 | spserv->GetSocketProvider("ssl", getter_AddRefs(provider)); |
michael@0 | 2288 | } |
michael@0 | 2289 | } |
michael@0 | 2290 | |
michael@0 | 2291 | /** |
michael@0 | 2292 | * Test whether a URI is "about:blank". |uri| must not be null |
michael@0 | 2293 | */ |
michael@0 | 2294 | inline bool |
michael@0 | 2295 | NS_IsAboutBlank(nsIURI *uri) |
michael@0 | 2296 | { |
michael@0 | 2297 | // GetSpec can be expensive for some URIs, so check the scheme first. |
michael@0 | 2298 | bool isAbout = false; |
michael@0 | 2299 | if (NS_FAILED(uri->SchemeIs("about", &isAbout)) || !isAbout) { |
michael@0 | 2300 | return false; |
michael@0 | 2301 | } |
michael@0 | 2302 | |
michael@0 | 2303 | nsAutoCString str; |
michael@0 | 2304 | uri->GetSpec(str); |
michael@0 | 2305 | return str.EqualsLiteral("about:blank"); |
michael@0 | 2306 | } |
michael@0 | 2307 | |
michael@0 | 2308 | |
michael@0 | 2309 | inline nsresult |
michael@0 | 2310 | NS_GenerateHostPort(const nsCString& host, int32_t port, |
michael@0 | 2311 | nsCString& hostLine) |
michael@0 | 2312 | { |
michael@0 | 2313 | if (strchr(host.get(), ':')) { |
michael@0 | 2314 | // host is an IPv6 address literal and must be encapsulated in []'s |
michael@0 | 2315 | hostLine.Assign('['); |
michael@0 | 2316 | // scope id is not needed for Host header. |
michael@0 | 2317 | int scopeIdPos = host.FindChar('%'); |
michael@0 | 2318 | if (scopeIdPos == -1) |
michael@0 | 2319 | hostLine.Append(host); |
michael@0 | 2320 | else if (scopeIdPos > 0) |
michael@0 | 2321 | hostLine.Append(Substring(host, 0, scopeIdPos)); |
michael@0 | 2322 | else |
michael@0 | 2323 | return NS_ERROR_MALFORMED_URI; |
michael@0 | 2324 | hostLine.Append(']'); |
michael@0 | 2325 | } |
michael@0 | 2326 | else |
michael@0 | 2327 | hostLine.Assign(host); |
michael@0 | 2328 | if (port != -1) { |
michael@0 | 2329 | hostLine.Append(':'); |
michael@0 | 2330 | hostLine.AppendInt(port); |
michael@0 | 2331 | } |
michael@0 | 2332 | return NS_OK; |
michael@0 | 2333 | } |
michael@0 | 2334 | |
michael@0 | 2335 | /** |
michael@0 | 2336 | * Sniff the content type for a given request or a given buffer. |
michael@0 | 2337 | * |
michael@0 | 2338 | * aSnifferType can be either NS_CONTENT_SNIFFER_CATEGORY or |
michael@0 | 2339 | * NS_DATA_SNIFFER_CATEGORY. The function returns the sniffed content type |
michael@0 | 2340 | * in the aSniffedType argument. This argument will not be modified if the |
michael@0 | 2341 | * content type could not be sniffed. |
michael@0 | 2342 | */ |
michael@0 | 2343 | inline void |
michael@0 | 2344 | NS_SniffContent(const char* aSnifferType, nsIRequest* aRequest, |
michael@0 | 2345 | const uint8_t* aData, uint32_t aLength, |
michael@0 | 2346 | nsACString& aSniffedType) |
michael@0 | 2347 | { |
michael@0 | 2348 | typedef nsCategoryCache<nsIContentSniffer> ContentSnifferCache; |
michael@0 | 2349 | extern NS_HIDDEN_(ContentSnifferCache*) gNetSniffers; |
michael@0 | 2350 | extern NS_HIDDEN_(ContentSnifferCache*) gDataSniffers; |
michael@0 | 2351 | ContentSnifferCache* cache = nullptr; |
michael@0 | 2352 | if (!strcmp(aSnifferType, NS_CONTENT_SNIFFER_CATEGORY)) { |
michael@0 | 2353 | if (!gNetSniffers) { |
michael@0 | 2354 | gNetSniffers = new ContentSnifferCache(NS_CONTENT_SNIFFER_CATEGORY); |
michael@0 | 2355 | } |
michael@0 | 2356 | cache = gNetSniffers; |
michael@0 | 2357 | } else if (!strcmp(aSnifferType, NS_DATA_SNIFFER_CATEGORY)) { |
michael@0 | 2358 | if (!gDataSniffers) { |
michael@0 | 2359 | gDataSniffers = new ContentSnifferCache(NS_DATA_SNIFFER_CATEGORY); |
michael@0 | 2360 | } |
michael@0 | 2361 | cache = gDataSniffers; |
michael@0 | 2362 | } else { |
michael@0 | 2363 | // Invalid content sniffer type was requested |
michael@0 | 2364 | MOZ_ASSERT(false); |
michael@0 | 2365 | return; |
michael@0 | 2366 | } |
michael@0 | 2367 | |
michael@0 | 2368 | nsCOMArray<nsIContentSniffer> sniffers; |
michael@0 | 2369 | cache->GetEntries(sniffers); |
michael@0 | 2370 | for (int32_t i = 0; i < sniffers.Count(); ++i) { |
michael@0 | 2371 | nsresult rv = sniffers[i]->GetMIMETypeFromContent(aRequest, aData, aLength, aSniffedType); |
michael@0 | 2372 | if (NS_SUCCEEDED(rv) && !aSniffedType.IsEmpty()) { |
michael@0 | 2373 | return; |
michael@0 | 2374 | } |
michael@0 | 2375 | } |
michael@0 | 2376 | |
michael@0 | 2377 | aSniffedType.Truncate(); |
michael@0 | 2378 | } |
michael@0 | 2379 | |
michael@0 | 2380 | /** |
michael@0 | 2381 | * Whether the channel was created to load a srcdoc document. |
michael@0 | 2382 | * Note that view-source:about:srcdoc is classified as a srcdoc document by |
michael@0 | 2383 | * this function, which may not be applicable everywhere. |
michael@0 | 2384 | */ |
michael@0 | 2385 | inline bool |
michael@0 | 2386 | NS_IsSrcdocChannel(nsIChannel *aChannel) |
michael@0 | 2387 | { |
michael@0 | 2388 | bool isSrcdoc; |
michael@0 | 2389 | nsCOMPtr<nsIInputStreamChannel> isr = do_QueryInterface(aChannel); |
michael@0 | 2390 | if (isr) { |
michael@0 | 2391 | isr->GetIsSrcdocChannel(&isSrcdoc); |
michael@0 | 2392 | return isSrcdoc; |
michael@0 | 2393 | } |
michael@0 | 2394 | nsCOMPtr<nsIViewSourceChannel> vsc = do_QueryInterface(aChannel); |
michael@0 | 2395 | if (vsc) { |
michael@0 | 2396 | vsc->GetIsSrcdocChannel(&isSrcdoc); |
michael@0 | 2397 | return isSrcdoc; |
michael@0 | 2398 | } |
michael@0 | 2399 | return false; |
michael@0 | 2400 | } |
michael@0 | 2401 | |
michael@0 | 2402 | #endif // !nsNetUtil_h__ |