mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-26 09:07:30 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
34
netwerk/protocol/about/moz.build
Normal file
34
netwerk/protocol/about/moz.build
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIAboutModule.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'necko_about'
|
||||
|
||||
EXPORTS += [
|
||||
'nsAboutProtocolUtils.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'nsAboutBlank.cpp',
|
||||
'nsAboutCache.cpp',
|
||||
'nsAboutCacheEntry.cpp',
|
||||
'nsAboutProtocolHandler.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/netwerk/base',
|
||||
'/netwerk/cache2',
|
||||
]
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-error=shadow']
|
||||
59
netwerk/protocol/about/nsAboutBlank.cpp
Normal file
59
netwerk/protocol/about/nsAboutBlank.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsAboutBlank.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAboutBlank, nsIAboutModule)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutBlank::NewChannel(nsIURI* aURI,
|
||||
nsILoadInfo* aLoadInfo,
|
||||
nsIChannel** result)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aURI);
|
||||
|
||||
nsCOMPtr<nsIInputStream> in;
|
||||
nsresult rv = NS_NewCStringInputStream(getter_AddRefs(in), EmptyCString());
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
rv = NS_NewInputStreamChannelInternal(getter_AddRefs(channel),
|
||||
aURI,
|
||||
in,
|
||||
NS_LITERAL_CSTRING("text/html"),
|
||||
NS_LITERAL_CSTRING("utf-8"),
|
||||
aLoadInfo);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
channel.forget(result);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutBlank::GetURIFlags(nsIURI *aURI, uint32_t *result)
|
||||
{
|
||||
*result = nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::URI_CAN_LOAD_IN_CHILD |
|
||||
nsIAboutModule::MAKE_LINKABLE |
|
||||
nsIAboutModule::HIDE_FROM_ABOUTABOUT;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAboutBlank::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
|
||||
{
|
||||
nsAboutBlank* about = new nsAboutBlank();
|
||||
if (about == nullptr)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(about);
|
||||
nsresult rv = about->QueryInterface(aIID, aResult);
|
||||
NS_RELEASE(about);
|
||||
return rv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
35
netwerk/protocol/about/nsAboutBlank.h
Normal file
35
netwerk/protocol/about/nsAboutBlank.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAboutBlank_h__
|
||||
#define nsAboutBlank_h__
|
||||
|
||||
#include "nsIAboutModule.h"
|
||||
|
||||
class nsAboutBlank : public nsIAboutModule
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
NS_DECL_NSIABOUTMODULE
|
||||
|
||||
nsAboutBlank() {}
|
||||
|
||||
static nsresult
|
||||
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
|
||||
private:
|
||||
virtual ~nsAboutBlank() {}
|
||||
};
|
||||
|
||||
#define NS_ABOUT_BLANK_MODULE_CID \
|
||||
{ /* 3decd6c8-30ef-11d3-8cd0-0060b0fc14a3 */ \
|
||||
0x3decd6c8, \
|
||||
0x30ef, \
|
||||
0x11d3, \
|
||||
{0x8c, 0xd0, 0x00, 0x60, 0xb0, 0xfc, 0x14, 0xa3} \
|
||||
}
|
||||
|
||||
#endif // nsAboutBlank_h__
|
||||
585
netwerk/protocol/about/nsAboutCache.cpp
Normal file
585
netwerk/protocol/about/nsAboutCache.cpp
Normal file
|
|
@ -0,0 +1,585 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsAboutCache.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIStorageStream.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIPipe.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsAboutProtocolUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
||||
#include "nsICacheStorageService.h"
|
||||
#include "nsICacheStorage.h"
|
||||
#include "CacheFileUtils.h"
|
||||
#include "CacheObserver.h"
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using namespace mozilla::net;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAboutCache, nsIAboutModule)
|
||||
NS_IMPL_ISUPPORTS(nsAboutCache::Channel, nsIChannel, nsIRequest, nsICacheStorageVisitor)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutCache::NewChannel(nsIURI* aURI,
|
||||
nsILoadInfo* aLoadInfo,
|
||||
nsIChannel** result)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
NS_ENSURE_ARG_POINTER(aURI);
|
||||
|
||||
RefPtr<Channel> channel = new Channel();
|
||||
rv = channel->Init(aURI, aLoadInfo);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
channel.forget(result);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAboutCache::Channel::Init(nsIURI* aURI, nsILoadInfo* aLoadInfo)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
mCancel = false;
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
rv = NS_NewPipe(getter_AddRefs(inputStream), getter_AddRefs(mStream),
|
||||
16384, (uint32_t)-1,
|
||||
true, // non-blocking input
|
||||
false // blocking output
|
||||
);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsAutoCString storageName;
|
||||
rv = ParseURI(aURI, storageName);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mOverview = storageName.IsEmpty();
|
||||
if (mOverview) {
|
||||
// ...and visit all we can
|
||||
mStorageList.AppendElement(NS_LITERAL_CSTRING("memory"));
|
||||
mStorageList.AppendElement(NS_LITERAL_CSTRING("disk"));
|
||||
mStorageList.AppendElement(NS_LITERAL_CSTRING("appcache"));
|
||||
} else {
|
||||
// ...and visit just the specified storage, entries will output too
|
||||
mStorageList.AppendElement(storageName);
|
||||
}
|
||||
|
||||
// The entries header is added on encounter of the first entry
|
||||
mEntriesHeaderAdded = false;
|
||||
|
||||
rv = NS_NewInputStreamChannelInternal(getter_AddRefs(mChannel),
|
||||
aURI,
|
||||
inputStream,
|
||||
NS_LITERAL_CSTRING("text/html"),
|
||||
NS_LITERAL_CSTRING("utf-8"),
|
||||
aLoadInfo);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mBuffer.AssignLiteral(
|
||||
"<!DOCTYPE html>\n"
|
||||
"<html>\n"
|
||||
"<head>\n"
|
||||
" <title>Network Cache Storage Information</title>\n"
|
||||
" <meta charset=\"utf-8\">\n"
|
||||
" <link rel=\"stylesheet\" href=\"chrome://global/skin/about.css\"/>\n"
|
||||
" <link rel=\"stylesheet\" href=\"chrome://global/skin/aboutCache.css\"/>\n"
|
||||
" <script src=\"chrome://global/content/aboutCache.js\"></script>"
|
||||
"</head>\n"
|
||||
"<body class=\"aboutPageWideContainer\">\n"
|
||||
"<h1>Information about the Network Cache Storage Service</h1>\n");
|
||||
|
||||
// Add the context switch controls
|
||||
mBuffer.AppendLiteral(
|
||||
"<label><input id='priv' type='checkbox'/> Private</label>\n"
|
||||
"<label><input id='anon' type='checkbox'/> Anonymous</label>\n"
|
||||
);
|
||||
|
||||
if (CacheObserver::UseNewCache()) {
|
||||
// Visit scoping by browser and appid is not implemented for
|
||||
// the old cache, simply don't add these controls.
|
||||
// The appid/inbrowser entries are already mixed in the default
|
||||
// view anyway.
|
||||
mBuffer.AppendLiteral(
|
||||
"<label><input id='appid' type='text' size='6'/> AppID</label>\n"
|
||||
"<label><input id='inbrowser' type='checkbox'/> In Browser Element</label>\n"
|
||||
);
|
||||
}
|
||||
|
||||
mBuffer.AppendLiteral(
|
||||
"<label><input id='submit' type='button' value='Update' onclick='navigate()'/></label>\n"
|
||||
);
|
||||
|
||||
if (!mOverview) {
|
||||
mBuffer.AppendLiteral("<a href=\"about:cache?storage=&context=");
|
||||
char* escapedContext = nsEscapeHTML(mContextString.get());
|
||||
mBuffer.Append(escapedContext);
|
||||
free(escapedContext);
|
||||
mBuffer.AppendLiteral("\">Back to overview</a>");
|
||||
}
|
||||
|
||||
rv = FlushBuffer();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to flush buffer");
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAboutCache::Channel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (!mChannel) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Kick the walk loop.
|
||||
rv = VisitNextStorage();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
MOZ_ASSERT(!aContext, "asyncOpen2() does not take a context argument");
|
||||
rv = NS_MaybeOpenChannelUsingAsyncOpen2(mChannel, aListener);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAboutCache::Channel::AsyncOpen2(nsIStreamListener *aListener)
|
||||
{
|
||||
return AsyncOpen(aListener, nullptr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAboutCache::Channel::Open(nsIInputStream * *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAboutCache::Channel::Open2(nsIInputStream * *_retval)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAboutCache::Channel::ParseURI(nsIURI * uri, nsACString & storage)
|
||||
{
|
||||
//
|
||||
// about:cache[?storage=<storage-name>[&context=<context-key>]]
|
||||
//
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCString path;
|
||||
rv = uri->GetPath(path);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mContextString.Truncate();
|
||||
mLoadInfo = CacheFileUtils::ParseKey(NS_LITERAL_CSTRING(""));
|
||||
storage.Truncate();
|
||||
|
||||
nsACString::const_iterator start, valueStart, end;
|
||||
path.BeginReading(start);
|
||||
path.EndReading(end);
|
||||
|
||||
valueStart = end;
|
||||
if (!FindInReadable(NS_LITERAL_CSTRING("?storage="), start, valueStart)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsACString::const_iterator storageNameBegin = valueStart;
|
||||
|
||||
start = valueStart;
|
||||
valueStart = end;
|
||||
if (!FindInReadable(NS_LITERAL_CSTRING("&context="), start, valueStart))
|
||||
start = end;
|
||||
|
||||
nsACString::const_iterator storageNameEnd = start;
|
||||
|
||||
mContextString = Substring(valueStart, end);
|
||||
mLoadInfo = CacheFileUtils::ParseKey(mContextString);
|
||||
storage.Assign(Substring(storageNameBegin, storageNameEnd));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAboutCache::Channel::VisitNextStorage()
|
||||
{
|
||||
if (!mStorageList.Length())
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
mStorageName = mStorageList[0];
|
||||
mStorageList.RemoveElementAt(0);
|
||||
|
||||
// Must re-dispatch since we cannot start another visit cycle
|
||||
// from visitor callback. The cache v1 service doesn't like it.
|
||||
// TODO - mayhemer, bug 913828, remove this dispatch and call
|
||||
// directly.
|
||||
return NS_DispatchToMainThread(mozilla::NewRunnableMethod(this, &nsAboutCache::Channel::FireVisitStorage));
|
||||
}
|
||||
|
||||
void
|
||||
nsAboutCache::Channel::FireVisitStorage()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = VisitStorage(mStorageName);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (mLoadInfo) {
|
||||
char* escaped = nsEscapeHTML(mStorageName.get());
|
||||
mBuffer.Append(
|
||||
nsPrintfCString("<p>Unrecognized storage name '%s' in about:cache URL</p>",
|
||||
escaped));
|
||||
free(escaped);
|
||||
} else {
|
||||
char* escaped = nsEscapeHTML(mContextString.get());
|
||||
mBuffer.Append(
|
||||
nsPrintfCString("<p>Unrecognized context key '%s' in about:cache URL</p>",
|
||||
escaped));
|
||||
free(escaped);
|
||||
}
|
||||
|
||||
rv = FlushBuffer();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to flush buffer");
|
||||
}
|
||||
|
||||
// Simulate finish of a visit cycle, this tries the next storage
|
||||
// or closes the output stream (i.e. the UI loader will stop spinning)
|
||||
OnCacheEntryVisitCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAboutCache::Channel::VisitStorage(nsACString const & storageName)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = GetStorage(storageName, mLoadInfo, getter_AddRefs(mStorage));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = mStorage->AsyncVisitStorage(this, !mOverview);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//static
|
||||
nsresult
|
||||
nsAboutCache::GetStorage(nsACString const & storageName,
|
||||
nsILoadContextInfo* loadInfo,
|
||||
nsICacheStorage **storage)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsICacheStorageService> cacheService =
|
||||
do_GetService("@mozilla.org/netwerk/cache-storage-service;1", &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
nsCOMPtr<nsICacheStorage> cacheStorage;
|
||||
if (storageName == "disk") {
|
||||
rv = cacheService->DiskCacheStorage(
|
||||
loadInfo, false, getter_AddRefs(cacheStorage));
|
||||
} else if (storageName == "memory") {
|
||||
rv = cacheService->MemoryCacheStorage(
|
||||
loadInfo, getter_AddRefs(cacheStorage));
|
||||
} else if (storageName == "appcache") {
|
||||
rv = cacheService->AppCacheStorage(
|
||||
loadInfo, nullptr, getter_AddRefs(cacheStorage));
|
||||
} else {
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
cacheStorage.forget(storage);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutCache::Channel::OnCacheStorageInfo(uint32_t aEntryCount, uint64_t aConsumption,
|
||||
uint64_t aCapacity, nsIFile * aDirectory)
|
||||
{
|
||||
// We need mStream for this
|
||||
if (!mStream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mBuffer.AssignLiteral("<h2>");
|
||||
mBuffer.Append(mStorageName);
|
||||
mBuffer.AppendLiteral("</h2>\n"
|
||||
"<table id=\"");
|
||||
mBuffer.AppendLiteral("\">\n");
|
||||
|
||||
// Write out cache info
|
||||
// Number of entries
|
||||
mBuffer.AppendLiteral(" <tr>\n"
|
||||
" <th>Number of entries:</th>\n"
|
||||
" <td>");
|
||||
mBuffer.AppendInt(aEntryCount);
|
||||
mBuffer.AppendLiteral("</td>\n"
|
||||
" </tr>\n");
|
||||
|
||||
// Maximum storage size
|
||||
mBuffer.AppendLiteral(" <tr>\n"
|
||||
" <th>Maximum storage size:</th>\n"
|
||||
" <td>");
|
||||
mBuffer.AppendInt(aCapacity / 1024);
|
||||
mBuffer.AppendLiteral(" KiB</td>\n"
|
||||
" </tr>\n");
|
||||
|
||||
// Storage in use
|
||||
mBuffer.AppendLiteral(" <tr>\n"
|
||||
" <th>Storage in use:</th>\n"
|
||||
" <td>");
|
||||
mBuffer.AppendInt(aConsumption / 1024);
|
||||
mBuffer.AppendLiteral(" KiB</td>\n"
|
||||
" </tr>\n");
|
||||
|
||||
// Storage disk location
|
||||
mBuffer.AppendLiteral(" <tr>\n"
|
||||
" <th>Storage disk location:</th>\n"
|
||||
" <td>");
|
||||
if (aDirectory) {
|
||||
nsAutoString path;
|
||||
aDirectory->GetPath(path);
|
||||
mBuffer.Append(NS_ConvertUTF16toUTF8(path));
|
||||
} else {
|
||||
mBuffer.AppendLiteral("none, only stored in memory");
|
||||
}
|
||||
mBuffer.AppendLiteral(" </td>\n"
|
||||
" </tr>\n");
|
||||
|
||||
if (mOverview) { // The about:cache case
|
||||
if (aEntryCount != 0) { // Add the "List Cache Entries" link
|
||||
mBuffer.AppendLiteral(" <tr>\n"
|
||||
" <th><a href=\"about:cache?storage=");
|
||||
mBuffer.Append(mStorageName);
|
||||
mBuffer.AppendLiteral("&context=");
|
||||
char* escapedContext = nsEscapeHTML(mContextString.get());
|
||||
mBuffer.Append(escapedContext);
|
||||
free(escapedContext);
|
||||
mBuffer.AppendLiteral("\">List Cache Entries</a></th>\n"
|
||||
" </tr>\n");
|
||||
}
|
||||
}
|
||||
|
||||
mBuffer.AppendLiteral("</table>\n");
|
||||
|
||||
// The entries header is added on encounter of the first entry
|
||||
mEntriesHeaderAdded = false;
|
||||
|
||||
nsresult rv = FlushBuffer();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to flush buffer");
|
||||
}
|
||||
|
||||
if (mOverview) {
|
||||
// OnCacheEntryVisitCompleted() is not called when we do not iterate
|
||||
// cache entries. Since this moves forward to the next storage in
|
||||
// the list we want to visit, artificially call it here.
|
||||
OnCacheEntryVisitCompleted();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutCache::Channel::OnCacheEntryInfo(nsIURI *aURI, const nsACString & aIdEnhance,
|
||||
int64_t aDataSize, int32_t aFetchCount,
|
||||
uint32_t aLastModified, uint32_t aExpirationTime,
|
||||
bool aPinned)
|
||||
{
|
||||
// We need mStream for this
|
||||
if (!mStream || mCancel) {
|
||||
// Returning a failure from this callback stops the iteration
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!mEntriesHeaderAdded) {
|
||||
mBuffer.AppendLiteral("<hr/>\n"
|
||||
"<table id=\"entries\">\n"
|
||||
" <colgroup>\n"
|
||||
" <col id=\"col-key\">\n"
|
||||
" <col id=\"col-dataSize\">\n"
|
||||
" <col id=\"col-fetchCount\">\n"
|
||||
" <col id=\"col-lastModified\">\n"
|
||||
" <col id=\"col-expires\">\n"
|
||||
" <col id=\"col-pinned\">\n"
|
||||
" </colgroup>\n"
|
||||
" <thead>\n"
|
||||
" <tr>\n"
|
||||
" <th>Key</th>\n"
|
||||
" <th>Data size</th>\n"
|
||||
" <th>Fetch count</th>\n"
|
||||
" <th>Last Modifed</th>\n"
|
||||
" <th>Expires</th>\n"
|
||||
" <th>Pinning</th>\n"
|
||||
" </tr>\n"
|
||||
" </thead>\n");
|
||||
mEntriesHeaderAdded = true;
|
||||
}
|
||||
|
||||
// Generate a about:cache-entry URL for this entry...
|
||||
|
||||
nsAutoCString url;
|
||||
url.AssignLiteral("about:cache-entry?storage=");
|
||||
url.Append(mStorageName);
|
||||
|
||||
url.AppendLiteral("&context=");
|
||||
char* escapedContext = nsEscapeHTML(mContextString.get());
|
||||
url += escapedContext;
|
||||
free(escapedContext);
|
||||
|
||||
url.AppendLiteral("&eid=");
|
||||
char* escapedEID = nsEscapeHTML(aIdEnhance.BeginReading());
|
||||
url += escapedEID;
|
||||
free(escapedEID);
|
||||
|
||||
nsAutoCString cacheUriSpec;
|
||||
aURI->GetAsciiSpec(cacheUriSpec);
|
||||
char* escapedCacheURI = nsEscapeHTML(cacheUriSpec.get());
|
||||
url.AppendLiteral("&uri=");
|
||||
url += escapedCacheURI;
|
||||
|
||||
// Entry start...
|
||||
mBuffer.AppendLiteral(" <tr>\n");
|
||||
|
||||
// URI
|
||||
mBuffer.AppendLiteral(" <td><a href=\"");
|
||||
mBuffer.Append(url);
|
||||
mBuffer.AppendLiteral("\">");
|
||||
if (!aIdEnhance.IsEmpty()) {
|
||||
mBuffer.Append(aIdEnhance);
|
||||
mBuffer.Append(':');
|
||||
}
|
||||
mBuffer.Append(escapedCacheURI);
|
||||
mBuffer.AppendLiteral("</a></td>\n");
|
||||
|
||||
free(escapedCacheURI);
|
||||
|
||||
// Content length
|
||||
mBuffer.AppendLiteral(" <td>");
|
||||
mBuffer.AppendInt(aDataSize);
|
||||
mBuffer.AppendLiteral(" bytes</td>\n");
|
||||
|
||||
// Number of accesses
|
||||
mBuffer.AppendLiteral(" <td>");
|
||||
mBuffer.AppendInt(aFetchCount);
|
||||
mBuffer.AppendLiteral("</td>\n");
|
||||
|
||||
// vars for reporting time
|
||||
char buf[255];
|
||||
|
||||
// Last modified time
|
||||
mBuffer.AppendLiteral(" <td>");
|
||||
if (aLastModified) {
|
||||
PrintTimeString(buf, sizeof(buf), aLastModified);
|
||||
mBuffer.Append(buf);
|
||||
} else {
|
||||
mBuffer.AppendLiteral("No last modified time");
|
||||
}
|
||||
mBuffer.AppendLiteral("</td>\n");
|
||||
|
||||
// Expires time
|
||||
mBuffer.AppendLiteral(" <td>");
|
||||
if (aExpirationTime < 0xFFFFFFFF) {
|
||||
PrintTimeString(buf, sizeof(buf), aExpirationTime);
|
||||
mBuffer.Append(buf);
|
||||
} else {
|
||||
mBuffer.AppendLiteral("No expiration time");
|
||||
}
|
||||
mBuffer.AppendLiteral("</td>\n");
|
||||
|
||||
// Pinning
|
||||
mBuffer.AppendLiteral(" <td>");
|
||||
if (aPinned) {
|
||||
mBuffer.Append(NS_LITERAL_CSTRING("Pinned"));
|
||||
} else {
|
||||
mBuffer.Append(NS_LITERAL_CSTRING(" "));
|
||||
}
|
||||
mBuffer.AppendLiteral("</td>\n");
|
||||
|
||||
// Entry is done...
|
||||
mBuffer.AppendLiteral(" </tr>\n");
|
||||
|
||||
return FlushBuffer();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutCache::Channel::OnCacheEntryVisitCompleted()
|
||||
{
|
||||
if (!mStream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mEntriesHeaderAdded) {
|
||||
mBuffer.AppendLiteral("</table>\n");
|
||||
}
|
||||
|
||||
// Kick another storage visiting (from a storage that allows us.)
|
||||
while (mStorageList.Length()) {
|
||||
nsresult rv = VisitNextStorage();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Expecting new round of OnCache* calls.
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// We are done!
|
||||
mBuffer.AppendLiteral("</body>\n"
|
||||
"</html>\n");
|
||||
nsresult rv = FlushBuffer();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Failed to flush buffer");
|
||||
}
|
||||
mStream->Close();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAboutCache::Channel::FlushBuffer()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
uint32_t bytesWritten;
|
||||
rv = mStream->Write(mBuffer.get(), mBuffer.Length(), &bytesWritten);
|
||||
mBuffer.Truncate();
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
mCancel = true;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutCache::GetURIFlags(nsIURI *aURI, uint32_t *result)
|
||||
{
|
||||
*result = nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
nsAboutCache::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
|
||||
{
|
||||
nsAboutCache* about = new nsAboutCache();
|
||||
if (about == nullptr)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(about);
|
||||
nsresult rv = about->QueryInterface(aIID, aResult);
|
||||
NS_RELEASE(about);
|
||||
return rv;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
136
netwerk/protocol/about/nsAboutCache.h
Normal file
136
netwerk/protocol/about/nsAboutCache.h
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAboutCache_h__
|
||||
#define nsAboutCache_h__
|
||||
|
||||
#include "nsIAboutModule.h"
|
||||
#include "nsICacheStorageVisitor.h"
|
||||
#include "nsICacheStorage.h"
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsILoadContextInfo.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#define NS_FORWARD_SAFE_NSICHANNEL_SUBSET(_to) \
|
||||
NS_IMETHOD GetOriginalURI(nsIURI * *aOriginalURI) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetOriginalURI(aOriginalURI); } \
|
||||
NS_IMETHOD SetOriginalURI(nsIURI *aOriginalURI) override { return !_to ? NS_ERROR_NULL_POINTER : _to->SetOriginalURI(aOriginalURI); } \
|
||||
NS_IMETHOD GetURI(nsIURI * *aURI) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetURI(aURI); } \
|
||||
NS_IMETHOD GetOwner(nsISupports * *aOwner) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetOwner(aOwner); } \
|
||||
NS_IMETHOD SetOwner(nsISupports *aOwner) override { return !_to ? NS_ERROR_NULL_POINTER : _to->SetOwner(aOwner); } \
|
||||
NS_IMETHOD GetNotificationCallbacks(nsIInterfaceRequestor * *aNotificationCallbacks) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetNotificationCallbacks(aNotificationCallbacks); } \
|
||||
NS_IMETHOD SetNotificationCallbacks(nsIInterfaceRequestor *aNotificationCallbacks) override { return !_to ? NS_ERROR_NULL_POINTER : _to->SetNotificationCallbacks(aNotificationCallbacks); } \
|
||||
NS_IMETHOD GetSecurityInfo(nsISupports * *aSecurityInfo) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetSecurityInfo(aSecurityInfo); } \
|
||||
NS_IMETHOD GetContentType(nsACString & aContentType) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetContentType(aContentType); } \
|
||||
NS_IMETHOD SetContentType(const nsACString & aContentType) override { return !_to ? NS_ERROR_NULL_POINTER : _to->SetContentType(aContentType); } \
|
||||
NS_IMETHOD GetContentCharset(nsACString & aContentCharset) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetContentCharset(aContentCharset); } \
|
||||
NS_IMETHOD SetContentCharset(const nsACString & aContentCharset) override { return !_to ? NS_ERROR_NULL_POINTER : _to->SetContentCharset(aContentCharset); } \
|
||||
NS_IMETHOD GetContentLength(int64_t *aContentLength) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetContentLength(aContentLength); } \
|
||||
NS_IMETHOD SetContentLength(int64_t aContentLength) override { return !_to ? NS_ERROR_NULL_POINTER : _to->SetContentLength(aContentLength); } \
|
||||
NS_IMETHOD GetContentDisposition(uint32_t *aContentDisposition) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetContentDisposition(aContentDisposition); } \
|
||||
NS_IMETHOD SetContentDisposition(uint32_t aContentDisposition) override { return !_to ? NS_ERROR_NULL_POINTER : _to->SetContentDisposition(aContentDisposition); } \
|
||||
NS_IMETHOD GetContentDispositionFilename(nsAString & aContentDispositionFilename) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetContentDispositionFilename(aContentDispositionFilename); } \
|
||||
NS_IMETHOD SetContentDispositionFilename(const nsAString & aContentDispositionFilename) override { return !_to ? NS_ERROR_NULL_POINTER : _to->SetContentDispositionFilename(aContentDispositionFilename); } \
|
||||
NS_IMETHOD GetContentDispositionHeader(nsACString & aContentDispositionHeader) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetContentDispositionHeader(aContentDispositionHeader); } \
|
||||
NS_IMETHOD GetLoadInfo(nsILoadInfo * *aLoadInfo) override { return !_to ? NS_ERROR_NULL_POINTER : _to->GetLoadInfo(aLoadInfo); } \
|
||||
NS_IMETHOD SetLoadInfo(nsILoadInfo *aLoadInfo) override { return !_to ? NS_ERROR_NULL_POINTER : _to->SetLoadInfo(aLoadInfo); } \
|
||||
|
||||
class nsAboutCache final : public nsIAboutModule
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIABOUTMODULE
|
||||
|
||||
nsAboutCache() {}
|
||||
|
||||
static MOZ_MUST_USE nsresult
|
||||
Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
|
||||
|
||||
static MOZ_MUST_USE nsresult
|
||||
GetStorage(nsACString const & storageName, nsILoadContextInfo* loadInfo,
|
||||
nsICacheStorage **storage);
|
||||
|
||||
protected:
|
||||
virtual ~nsAboutCache() {}
|
||||
|
||||
class Channel final : public nsIChannel
|
||||
, public nsICacheStorageVisitor
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICACHESTORAGEVISITOR
|
||||
NS_FORWARD_SAFE_NSIREQUEST(mChannel)
|
||||
NS_FORWARD_SAFE_NSICHANNEL_SUBSET(mChannel)
|
||||
NS_IMETHOD AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext) override;
|
||||
NS_IMETHOD AsyncOpen2(nsIStreamListener *aListener) override;
|
||||
NS_IMETHOD Open(nsIInputStream * *_retval) override;
|
||||
NS_IMETHOD Open2(nsIInputStream * *_retval) override;
|
||||
|
||||
private:
|
||||
virtual ~Channel() {}
|
||||
|
||||
public:
|
||||
MOZ_MUST_USE nsresult Init(nsIURI* aURI, nsILoadInfo* aLoadInfo);
|
||||
MOZ_MUST_USE nsresult ParseURI(nsIURI * uri, nsACString & storage);
|
||||
|
||||
// Finds a next storage we wish to visit (we use this method
|
||||
// even there is a specified storage name, which is the only
|
||||
// one in the list then.) Posts FireVisitStorage() when found.
|
||||
MOZ_MUST_USE nsresult VisitNextStorage();
|
||||
// Helper method that calls VisitStorage() for the current storage.
|
||||
// When it fails, OnCacheEntryVisitCompleted is simulated to close
|
||||
// the output stream and thus the about:cache channel.
|
||||
void FireVisitStorage();
|
||||
// Kiks the visit cycle for the given storage, names can be:
|
||||
// "disk", "memory", "appcache"
|
||||
// Note: any newly added storage type has to be manually handled here.
|
||||
MOZ_MUST_USE nsresult VisitStorage(nsACString const & storageName);
|
||||
|
||||
// Writes content of mBuffer to mStream and truncates
|
||||
// the buffer. It may fail when the input stream is closed by canceling
|
||||
// the input stream channel. It can be used to stop the cache iteration
|
||||
// process.
|
||||
MOZ_MUST_USE nsresult FlushBuffer();
|
||||
|
||||
// Whether we are showing overview status of all available
|
||||
// storages.
|
||||
bool mOverview;
|
||||
|
||||
// Flag initially false, that indicates the entries header has
|
||||
// been added to the output HTML.
|
||||
bool mEntriesHeaderAdded;
|
||||
|
||||
// Cancelation flag
|
||||
bool mCancel;
|
||||
|
||||
// The context we are working with.
|
||||
nsCOMPtr<nsILoadContextInfo> mLoadInfo;
|
||||
nsCString mContextString;
|
||||
|
||||
// The list of all storage names we want to visit
|
||||
nsTArray<nsCString> mStorageList;
|
||||
nsCString mStorageName;
|
||||
nsCOMPtr<nsICacheStorage> mStorage;
|
||||
|
||||
// Output data buffering and streaming output
|
||||
nsCString mBuffer;
|
||||
nsCOMPtr<nsIOutputStream> mStream;
|
||||
|
||||
// The input stream channel, the one that actually does the job
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
};
|
||||
};
|
||||
|
||||
#define NS_ABOUT_CACHE_MODULE_CID \
|
||||
{ /* 9158c470-86e4-11d4-9be2-00e09872a416 */ \
|
||||
0x9158c470, \
|
||||
0x86e4, \
|
||||
0x11d4, \
|
||||
{0x9b, 0xe2, 0x00, 0xe0, 0x98, 0x72, 0xa4, 0x16} \
|
||||
}
|
||||
|
||||
#endif // nsAboutCache_h__
|
||||
603
netwerk/protocol/about/nsAboutCacheEntry.cpp
Normal file
603
netwerk/protocol/about/nsAboutCacheEntry.cpp
Normal file
|
|
@ -0,0 +1,603 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsAboutCacheEntry.h"
|
||||
|
||||
#include "mozilla/Sprintf.h"
|
||||
|
||||
#include "nsAboutCache.h"
|
||||
#include "nsICacheStorage.h"
|
||||
#include "CacheObserver.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
#include "nsAboutProtocolUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsInputStreamPump.h"
|
||||
#include "CacheFileUtils.h"
|
||||
#include <algorithm>
|
||||
#include "nsIPipe.h"
|
||||
|
||||
using namespace mozilla::net;
|
||||
|
||||
#define HEXDUMP_MAX_ROWS 16
|
||||
|
||||
static void
|
||||
HexDump(uint32_t *state, const char *buf, int32_t n, nsCString &result)
|
||||
{
|
||||
char temp[16];
|
||||
|
||||
const unsigned char *p;
|
||||
while (n) {
|
||||
SprintfLiteral(temp, "%08x: ", *state);
|
||||
result.Append(temp);
|
||||
*state += HEXDUMP_MAX_ROWS;
|
||||
|
||||
p = (const unsigned char *) buf;
|
||||
|
||||
int32_t i, row_max = std::min(HEXDUMP_MAX_ROWS, n);
|
||||
|
||||
// print hex codes:
|
||||
for (i = 0; i < row_max; ++i) {
|
||||
SprintfLiteral(temp, "%02x ", *p++);
|
||||
result.Append(temp);
|
||||
}
|
||||
for (i = row_max; i < HEXDUMP_MAX_ROWS; ++i) {
|
||||
result.AppendLiteral(" ");
|
||||
}
|
||||
|
||||
// print ASCII glyphs if possible:
|
||||
p = (const unsigned char *) buf;
|
||||
for (i = 0; i < row_max; ++i, ++p) {
|
||||
switch (*p) {
|
||||
case '<':
|
||||
result.AppendLiteral("<");
|
||||
break;
|
||||
case '>':
|
||||
result.AppendLiteral(">");
|
||||
break;
|
||||
case '&':
|
||||
result.AppendLiteral("&");
|
||||
break;
|
||||
default:
|
||||
if (*p < 0x7F && *p > 0x1F) {
|
||||
result.Append(*p);
|
||||
} else {
|
||||
result.Append('.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.Append('\n');
|
||||
|
||||
buf += row_max;
|
||||
n -= row_max;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsAboutCacheEntry::nsISupports
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAboutCacheEntry,
|
||||
nsIAboutModule)
|
||||
NS_IMPL_ISUPPORTS(nsAboutCacheEntry::Channel,
|
||||
nsICacheEntryOpenCallback,
|
||||
nsICacheEntryMetaDataVisitor,
|
||||
nsIStreamListener,
|
||||
nsIChannel)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsAboutCacheEntry::nsIAboutModule
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutCacheEntry::NewChannel(nsIURI* uri,
|
||||
nsILoadInfo* aLoadInfo,
|
||||
nsIChannel** result)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(uri);
|
||||
nsresult rv;
|
||||
|
||||
RefPtr<Channel> channel = new Channel();
|
||||
rv = channel->Init(uri, aLoadInfo);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
channel.forget(result);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutCacheEntry::GetURIFlags(nsIURI *aURI, uint32_t *result)
|
||||
{
|
||||
*result = nsIAboutModule::HIDE_FROM_ABOUTABOUT |
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsAboutCacheEntry::Channel
|
||||
|
||||
nsresult
|
||||
nsAboutCacheEntry::Channel::Init(nsIURI* uri, nsILoadInfo* aLoadInfo)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
rv = GetContentStream(uri, getter_AddRefs(stream));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = NS_NewInputStreamChannelInternal(getter_AddRefs(mChannel),
|
||||
uri,
|
||||
stream,
|
||||
NS_LITERAL_CSTRING("text/html"),
|
||||
NS_LITERAL_CSTRING("utf-8"),
|
||||
aLoadInfo);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAboutCacheEntry::Channel::GetContentStream(nsIURI *uri, nsIInputStream **result)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Init: (block size, maximum length)
|
||||
nsCOMPtr<nsIAsyncInputStream> inputStream;
|
||||
rv = NS_NewPipe2(getter_AddRefs(inputStream),
|
||||
getter_AddRefs(mOutputStream),
|
||||
true, false,
|
||||
256, UINT32_MAX);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(
|
||||
buffer,
|
||||
"<!DOCTYPE html>\n"
|
||||
"<html>\n"
|
||||
"<head>\n"
|
||||
" <title>Cache entry information</title>\n"
|
||||
" <link rel=\"stylesheet\" "
|
||||
"href=\"chrome://global/skin/about.css\" type=\"text/css\"/>\n"
|
||||
" <link rel=\"stylesheet\" "
|
||||
"href=\"chrome://global/skin/aboutCacheEntry.css\" type=\"text/css\"/>\n"
|
||||
"</head>\n"
|
||||
"<body>\n"
|
||||
"<h1>Cache entry information</h1>\n");
|
||||
uint32_t n;
|
||||
rv = mOutputStream->Write(buffer.get(), buffer.Length(), &n);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
if (n != buffer.Length()) return NS_ERROR_UNEXPECTED;
|
||||
|
||||
rv = OpenCacheEntry(uri);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
inputStream.forget(result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAboutCacheEntry::Channel::OpenCacheEntry(nsIURI *uri)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
rv = ParseURI(uri, mStorageName, getter_AddRefs(mLoadInfo),
|
||||
mEnhanceId, getter_AddRefs(mCacheURI));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (!CacheObserver::UseNewCache() &&
|
||||
mLoadInfo->IsPrivate() &&
|
||||
mStorageName.EqualsLiteral("disk")) {
|
||||
// The cache v1 is storing all private entries in the memory-only
|
||||
// cache, so it would not be found in the v1 disk cache.
|
||||
mStorageName = NS_LITERAL_CSTRING("memory");
|
||||
}
|
||||
|
||||
return OpenCacheEntry();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAboutCacheEntry::Channel::OpenCacheEntry()
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsICacheStorage> storage;
|
||||
rv = nsAboutCache::GetStorage(mStorageName, mLoadInfo, getter_AddRefs(storage));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Invokes OnCacheEntryAvailable()
|
||||
rv = storage->AsyncOpenURI(mCacheURI, mEnhanceId,
|
||||
nsICacheStorage::OPEN_READONLY |
|
||||
nsICacheStorage::OPEN_SECRETLY,
|
||||
this);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAboutCacheEntry::Channel::ParseURI(nsIURI *uri,
|
||||
nsACString &storageName,
|
||||
nsILoadContextInfo **loadInfo,
|
||||
nsCString &enahnceID,
|
||||
nsIURI **cacheUri)
|
||||
{
|
||||
//
|
||||
// about:cache-entry?storage=[string]&contenxt=[string]&eid=[string]&uri=[string]
|
||||
//
|
||||
nsresult rv;
|
||||
|
||||
nsAutoCString path;
|
||||
rv = uri->GetPath(path);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
nsACString::const_iterator keyBegin, keyEnd, valBegin, begin, end;
|
||||
path.BeginReading(begin);
|
||||
path.EndReading(end);
|
||||
|
||||
keyBegin = begin; keyEnd = end;
|
||||
if (!FindInReadable(NS_LITERAL_CSTRING("?storage="), keyBegin, keyEnd))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
valBegin = keyEnd; // the value of the storage key starts after the key
|
||||
|
||||
keyBegin = keyEnd; keyEnd = end;
|
||||
if (!FindInReadable(NS_LITERAL_CSTRING("&context="), keyBegin, keyEnd))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
storageName.Assign(Substring(valBegin, keyBegin));
|
||||
valBegin = keyEnd; // the value of the context key starts after the key
|
||||
|
||||
keyBegin = keyEnd; keyEnd = end;
|
||||
if (!FindInReadable(NS_LITERAL_CSTRING("&eid="), keyBegin, keyEnd))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsAutoCString contextKey(Substring(valBegin, keyBegin));
|
||||
valBegin = keyEnd; // the value of the eid key starts after the key
|
||||
|
||||
keyBegin = keyEnd; keyEnd = end;
|
||||
if (!FindInReadable(NS_LITERAL_CSTRING("&uri="), keyBegin, keyEnd))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
enahnceID.Assign(Substring(valBegin, keyBegin));
|
||||
|
||||
valBegin = keyEnd; // the value of the uri key starts after the key
|
||||
nsAutoCString uriSpec(Substring(valBegin, end)); // uri is the last one
|
||||
|
||||
// Uf... parsing done, now get some objects from it...
|
||||
|
||||
nsCOMPtr<nsILoadContextInfo> info =
|
||||
CacheFileUtils::ParseKey(contextKey);
|
||||
if (!info)
|
||||
return NS_ERROR_FAILURE;
|
||||
info.forget(loadInfo);
|
||||
|
||||
rv = NS_NewURI(cacheUri, uriSpec);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsICacheEntryOpenCallback implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutCacheEntry::Channel::OnCacheEntryCheck(nsICacheEntry *aEntry,
|
||||
nsIApplicationCache *aApplicationCache,
|
||||
uint32_t *result)
|
||||
{
|
||||
*result = nsICacheEntryOpenCallback::ENTRY_WANTED;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutCacheEntry::Channel::OnCacheEntryAvailable(nsICacheEntry *entry,
|
||||
bool isNew,
|
||||
nsIApplicationCache *aApplicationCache,
|
||||
nsresult status)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
mWaitingForData = false;
|
||||
if (entry) {
|
||||
rv = WriteCacheEntryDescription(entry);
|
||||
} else if (!CacheObserver::UseNewCache() &&
|
||||
!mLoadInfo->IsPrivate() &&
|
||||
mStorageName.EqualsLiteral("memory")) {
|
||||
// If we were not able to find the entry in the memory storage
|
||||
// try again in the disk storage.
|
||||
// This is a workaround for cache v1: when an originally disk
|
||||
// cache entry is recreated as memory-only, it's clientID doesn't
|
||||
// change and we cannot find it in "HTTP-memory-only" session.
|
||||
// "Disk" cache storage looks at "HTTP".
|
||||
mStorageName = NS_LITERAL_CSTRING("disk");
|
||||
rv = OpenCacheEntry();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
rv = WriteCacheEntryUnavailable();
|
||||
}
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
||||
if (!mWaitingForData) {
|
||||
// Data is not expected, close the output of content now.
|
||||
CloseContent();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Print-out helper methods
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define APPEND_ROW(label, value) \
|
||||
PR_BEGIN_MACRO \
|
||||
buffer.AppendLiteral(" <tr>\n" \
|
||||
" <th>"); \
|
||||
buffer.AppendLiteral(label); \
|
||||
buffer.AppendLiteral(":</th>\n" \
|
||||
" <td>"); \
|
||||
buffer.Append(value); \
|
||||
buffer.AppendLiteral("</td>\n" \
|
||||
" </tr>\n"); \
|
||||
PR_END_MACRO
|
||||
|
||||
nsresult
|
||||
nsAboutCacheEntry::Channel::WriteCacheEntryDescription(nsICacheEntry *entry)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCString buffer;
|
||||
uint32_t n;
|
||||
|
||||
nsAutoCString str;
|
||||
|
||||
rv = entry->GetKey(str);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
buffer.SetCapacity(4096);
|
||||
buffer.AssignLiteral("<table>\n"
|
||||
" <tr>\n"
|
||||
" <th>key:</th>\n"
|
||||
" <td id=\"td-key\">");
|
||||
|
||||
// Test if the key is actually a URI
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
bool isJS = false;
|
||||
bool isData = false;
|
||||
|
||||
rv = NS_NewURI(getter_AddRefs(uri), str);
|
||||
// javascript: and data: URLs should not be linkified
|
||||
// since clicking them can cause scripts to run - bug 162584
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
uri->SchemeIs("javascript", &isJS);
|
||||
uri->SchemeIs("data", &isData);
|
||||
}
|
||||
char* escapedStr = nsEscapeHTML(str.get());
|
||||
if (NS_SUCCEEDED(rv) && !(isJS || isData)) {
|
||||
buffer.AppendLiteral("<a href=\"");
|
||||
buffer.Append(escapedStr);
|
||||
buffer.AppendLiteral("\">");
|
||||
buffer.Append(escapedStr);
|
||||
buffer.AppendLiteral("</a>");
|
||||
uri = nullptr;
|
||||
} else {
|
||||
buffer.Append(escapedStr);
|
||||
}
|
||||
free(escapedStr);
|
||||
buffer.AppendLiteral("</td>\n"
|
||||
" </tr>\n");
|
||||
|
||||
// temp vars for reporting
|
||||
char timeBuf[255];
|
||||
uint32_t u = 0;
|
||||
int32_t i = 0;
|
||||
nsAutoCString s;
|
||||
|
||||
// Fetch Count
|
||||
s.Truncate();
|
||||
entry->GetFetchCount(&i);
|
||||
s.AppendInt(i);
|
||||
APPEND_ROW("fetch count", s);
|
||||
|
||||
// Last Fetched
|
||||
entry->GetLastFetched(&u);
|
||||
if (u) {
|
||||
PrintTimeString(timeBuf, sizeof(timeBuf), u);
|
||||
APPEND_ROW("last fetched", timeBuf);
|
||||
} else {
|
||||
APPEND_ROW("last fetched", "No last fetch time (bug 1000338)");
|
||||
}
|
||||
|
||||
// Last Modified
|
||||
entry->GetLastModified(&u);
|
||||
if (u) {
|
||||
PrintTimeString(timeBuf, sizeof(timeBuf), u);
|
||||
APPEND_ROW("last modified", timeBuf);
|
||||
} else {
|
||||
APPEND_ROW("last modified", "No last modified time (bug 1000338)");
|
||||
}
|
||||
|
||||
// Expiration Time
|
||||
entry->GetExpirationTime(&u);
|
||||
if (u < 0xFFFFFFFF) {
|
||||
PrintTimeString(timeBuf, sizeof(timeBuf), u);
|
||||
APPEND_ROW("expires", timeBuf);
|
||||
} else {
|
||||
APPEND_ROW("expires", "No expiration time");
|
||||
}
|
||||
|
||||
// Data Size
|
||||
s.Truncate();
|
||||
uint32_t dataSize;
|
||||
if (NS_FAILED(entry->GetStorageDataSize(&dataSize)))
|
||||
dataSize = 0;
|
||||
s.AppendInt((int32_t)dataSize); // XXX nsICacheEntryInfo interfaces should be fixed.
|
||||
s.AppendLiteral(" B");
|
||||
APPEND_ROW("Data size", s);
|
||||
|
||||
// TODO - mayhemer
|
||||
// Here used to be a link to the disk file (in the old cache for entries that
|
||||
// did not fit any of the block files, in the new cache every time).
|
||||
// I'd rather have a small set of buttons here to action on the entry:
|
||||
// 1. save the content
|
||||
// 2. save as a complete HTTP response (response head, headers, content)
|
||||
// 3. doom the entry
|
||||
// A new bug(s) should be filed here.
|
||||
|
||||
// Security Info
|
||||
nsCOMPtr<nsISupports> securityInfo;
|
||||
entry->GetSecurityInfo(getter_AddRefs(securityInfo));
|
||||
if (securityInfo) {
|
||||
APPEND_ROW("Security", "This is a secure document.");
|
||||
} else {
|
||||
APPEND_ROW("Security",
|
||||
"This document does not have any security info associated with it.");
|
||||
}
|
||||
|
||||
buffer.AppendLiteral("</table>\n"
|
||||
"<hr/>\n"
|
||||
"<table>\n");
|
||||
|
||||
mBuffer = &buffer; // make it available for OnMetaDataElement().
|
||||
entry->VisitMetaData(this);
|
||||
mBuffer = nullptr;
|
||||
|
||||
buffer.AppendLiteral("</table>\n");
|
||||
mOutputStream->Write(buffer.get(), buffer.Length(), &n);
|
||||
buffer.Truncate();
|
||||
|
||||
// Provide a hexdump of the data
|
||||
if (!dataSize) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
entry->OpenInputStream(0, getter_AddRefs(stream));
|
||||
if (!stream) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<nsInputStreamPump> pump;
|
||||
rv = nsInputStreamPump::Create(getter_AddRefs(pump), stream);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_OK; // just ignore
|
||||
}
|
||||
|
||||
rv = pump->AsyncRead(this, nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_OK; // just ignore
|
||||
}
|
||||
|
||||
mWaitingForData = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsAboutCacheEntry::Channel::WriteCacheEntryUnavailable()
|
||||
{
|
||||
uint32_t n;
|
||||
NS_NAMED_LITERAL_CSTRING(buffer,
|
||||
"The cache entry you selected is not available.");
|
||||
mOutputStream->Write(buffer.get(), buffer.Length(), &n);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsICacheEntryMetaDataVisitor implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutCacheEntry::Channel::OnMetaDataElement(char const * key, char const * value)
|
||||
{
|
||||
mBuffer->AppendLiteral(" <tr>\n"
|
||||
" <th>");
|
||||
mBuffer->Append(key);
|
||||
mBuffer->AppendLiteral(":</th>\n"
|
||||
" <td>");
|
||||
char* escapedValue = nsEscapeHTML(value);
|
||||
mBuffer->Append(escapedValue);
|
||||
free(escapedValue);
|
||||
mBuffer->AppendLiteral("</td>\n"
|
||||
" </tr>\n");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIStreamListener implementation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutCacheEntry::Channel::OnStartRequest(nsIRequest *request, nsISupports *ctx)
|
||||
{
|
||||
mHexDumpState = 0;
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(buffer, "<hr/>\n<pre>");
|
||||
uint32_t n;
|
||||
return mOutputStream->Write(buffer.get(), buffer.Length(), &n);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutCacheEntry::Channel::OnDataAvailable(nsIRequest *request, nsISupports *ctx,
|
||||
nsIInputStream *aInputStream,
|
||||
uint64_t aOffset,
|
||||
uint32_t aCount)
|
||||
{
|
||||
uint32_t n;
|
||||
return aInputStream->ReadSegments(
|
||||
&nsAboutCacheEntry::Channel::PrintCacheData, this, aCount, &n);
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
nsAboutCacheEntry::Channel::PrintCacheData(nsIInputStream *aInStream,
|
||||
void *aClosure,
|
||||
const char *aFromSegment,
|
||||
uint32_t aToOffset,
|
||||
uint32_t aCount,
|
||||
uint32_t *aWriteCount)
|
||||
{
|
||||
nsAboutCacheEntry::Channel *a =
|
||||
static_cast<nsAboutCacheEntry::Channel*>(aClosure);
|
||||
|
||||
nsCString buffer;
|
||||
HexDump(&a->mHexDumpState, aFromSegment, aCount, buffer);
|
||||
|
||||
uint32_t n;
|
||||
a->mOutputStream->Write(buffer.get(), buffer.Length(), &n);
|
||||
|
||||
*aWriteCount = aCount;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutCacheEntry::Channel::OnStopRequest(nsIRequest *request, nsISupports *ctx,
|
||||
nsresult result)
|
||||
{
|
||||
NS_NAMED_LITERAL_CSTRING(buffer, "</pre>\n");
|
||||
uint32_t n;
|
||||
mOutputStream->Write(buffer.get(), buffer.Length(), &n);
|
||||
|
||||
CloseContent();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsAboutCacheEntry::Channel::CloseContent()
|
||||
{
|
||||
NS_NAMED_LITERAL_CSTRING(buffer, "</body>\n</html>\n");
|
||||
uint32_t n;
|
||||
mOutputStream->Write(buffer.get(), buffer.Length(), &n);
|
||||
|
||||
mOutputStream->Close();
|
||||
mOutputStream = nullptr;
|
||||
}
|
||||
98
netwerk/protocol/about/nsAboutCacheEntry.h
Normal file
98
netwerk/protocol/about/nsAboutCacheEntry.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAboutCacheEntry_h__
|
||||
#define nsAboutCacheEntry_h__
|
||||
|
||||
#include "nsIAboutModule.h"
|
||||
#include "nsICacheEntryOpenCallback.h"
|
||||
#include "nsICacheEntry.h"
|
||||
#include "nsIStreamListener.h"
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
class nsIAsyncOutputStream;
|
||||
class nsIInputStream;
|
||||
class nsILoadContextInfo;
|
||||
class nsIURI;
|
||||
class nsCString;
|
||||
|
||||
class nsAboutCacheEntry final : public nsIAboutModule
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIABOUTMODULE
|
||||
|
||||
private:
|
||||
virtual ~nsAboutCacheEntry() {}
|
||||
|
||||
class Channel final : public nsICacheEntryOpenCallback
|
||||
, public nsICacheEntryMetaDataVisitor
|
||||
, public nsIStreamListener
|
||||
, public nsIChannel
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICACHEENTRYOPENCALLBACK
|
||||
NS_DECL_NSICACHEENTRYMETADATAVISITOR
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_FORWARD_SAFE_NSICHANNEL(mChannel)
|
||||
NS_FORWARD_SAFE_NSIREQUEST(mChannel)
|
||||
|
||||
Channel()
|
||||
: mBuffer(nullptr)
|
||||
, mWaitingForData(false)
|
||||
, mHexDumpState(0)
|
||||
{}
|
||||
|
||||
private:
|
||||
virtual ~Channel() {}
|
||||
|
||||
public:
|
||||
MOZ_MUST_USE nsresult Init(nsIURI* uri, nsILoadInfo* aLoadInfo);
|
||||
|
||||
MOZ_MUST_USE nsresult GetContentStream(nsIURI *, nsIInputStream **);
|
||||
MOZ_MUST_USE nsresult OpenCacheEntry(nsIURI *);
|
||||
MOZ_MUST_USE nsresult OpenCacheEntry();
|
||||
MOZ_MUST_USE nsresult WriteCacheEntryDescription(nsICacheEntry *);
|
||||
MOZ_MUST_USE nsresult WriteCacheEntryUnavailable();
|
||||
MOZ_MUST_USE nsresult ParseURI(nsIURI *uri, nsACString &storageName,
|
||||
nsILoadContextInfo **loadInfo,
|
||||
nsCString &enahnceID,
|
||||
nsIURI **cacheUri);
|
||||
void CloseContent();
|
||||
|
||||
static MOZ_MUST_USE nsresult
|
||||
PrintCacheData(nsIInputStream *aInStream,
|
||||
void *aClosure,
|
||||
const char *aFromSegment,
|
||||
uint32_t aToOffset,
|
||||
uint32_t aCount,
|
||||
uint32_t *aWriteCount);
|
||||
|
||||
private:
|
||||
nsCString mStorageName, mEnhanceId;
|
||||
nsCOMPtr<nsILoadContextInfo> mLoadInfo;
|
||||
nsCOMPtr<nsIURI> mCacheURI;
|
||||
|
||||
nsCString *mBuffer;
|
||||
nsCOMPtr<nsIAsyncOutputStream> mOutputStream;
|
||||
bool mWaitingForData;
|
||||
uint32_t mHexDumpState;
|
||||
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
};
|
||||
};
|
||||
|
||||
#define NS_ABOUT_CACHE_ENTRY_MODULE_CID \
|
||||
{ /* 7fa5237d-b0eb-438f-9e50-ca0166e63788 */ \
|
||||
0x7fa5237d, \
|
||||
0xb0eb, \
|
||||
0x438f, \
|
||||
{0x9e, 0x50, 0xca, 0x01, 0x66, 0xe6, 0x37, 0x88} \
|
||||
}
|
||||
|
||||
#endif // nsAboutCacheEntry_h__
|
||||
439
netwerk/protocol/about/nsAboutProtocolHandler.cpp
Normal file
439
netwerk/protocol/about/nsAboutProtocolHandler.cpp
Normal file
|
|
@ -0,0 +1,439 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
|
||||
#include "nsAboutProtocolHandler.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIAboutModule.h"
|
||||
#include "nsString.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsAboutProtocolUtils.h"
|
||||
#include "nsError.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsIObjectInputStream.h"
|
||||
#include "nsIObjectOutputStream.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIWritablePropertyBag2.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsIScriptError.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
static NS_DEFINE_CID(kSimpleURICID, NS_SIMPLEURI_CID);
|
||||
static NS_DEFINE_CID(kNestedAboutURICID, NS_NESTEDABOUTURI_CID);
|
||||
|
||||
static bool IsSafeForUntrustedContent(nsIAboutModule *aModule, nsIURI *aURI) {
|
||||
uint32_t flags;
|
||||
nsresult rv = aModule->GetURIFlags(aURI, &flags);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return (flags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) != 0;
|
||||
}
|
||||
|
||||
static bool IsSafeToLinkForUntrustedContent(nsIAboutModule *aModule, nsIURI *aURI) {
|
||||
uint32_t flags;
|
||||
nsresult rv = aModule->GetURIFlags(aURI, &flags);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return (flags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) && (flags & nsIAboutModule::MAKE_LINKABLE);
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsAboutProtocolHandler, nsIProtocolHandler,
|
||||
nsIProtocolHandlerWithDynamicFlags, nsISupportsWeakReference)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// nsIProtocolHandler methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutProtocolHandler::GetScheme(nsACString &result)
|
||||
{
|
||||
result.AssignLiteral("about");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutProtocolHandler::GetDefaultPort(int32_t *result)
|
||||
{
|
||||
*result = -1; // no port for about: URLs
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutProtocolHandler::GetProtocolFlags(uint32_t *result)
|
||||
{
|
||||
*result = URI_NORELATIVE | URI_NOAUTH | URI_DANGEROUS_TO_LOAD | URI_SCHEME_NOT_SELF_LINKABLE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutProtocolHandler::GetFlagsForURI(nsIURI* aURI, uint32_t* aFlags)
|
||||
{
|
||||
// First use the default (which is "unsafe for content"):
|
||||
GetProtocolFlags(aFlags);
|
||||
|
||||
// Now try to see if this URI overrides the default:
|
||||
nsCOMPtr<nsIAboutModule> aboutMod;
|
||||
nsresult rv = NS_GetAboutModule(aURI, getter_AddRefs(aboutMod));
|
||||
if (NS_FAILED(rv)) {
|
||||
// Swallow this and just tell the consumer the default:
|
||||
return NS_OK;
|
||||
}
|
||||
uint32_t aboutModuleFlags = 0;
|
||||
rv = aboutMod->GetURIFlags(aURI, &aboutModuleFlags);
|
||||
// This should never happen, so pass back the error:
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Secure (https) pages can load safe about pages without becoming
|
||||
// mixed content.
|
||||
if (aboutModuleFlags & nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT) {
|
||||
*aFlags |= URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
|
||||
// about: pages can only be loaded by unprivileged principals
|
||||
// if they are marked as LINKABLE
|
||||
if (aboutModuleFlags & nsIAboutModule::MAKE_LINKABLE) {
|
||||
// Replace URI_DANGEROUS_TO_LOAD with URI_LOADABLE_BY_ANYONE.
|
||||
*aFlags &= ~URI_DANGEROUS_TO_LOAD;
|
||||
*aFlags |= URI_LOADABLE_BY_ANYONE;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutProtocolHandler::NewURI(const nsACString &aSpec,
|
||||
const char *aCharset, // ignore charset info
|
||||
nsIURI *aBaseURI,
|
||||
nsIURI **result)
|
||||
{
|
||||
*result = nullptr;
|
||||
nsresult rv;
|
||||
|
||||
// Use a simple URI to parse out some stuff first
|
||||
nsCOMPtr<nsIURI> url = do_CreateInstance(kSimpleURICID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = url->SetSpec(aSpec);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Unfortunately, people create random about: URIs that don't correspond to
|
||||
// about: modules... Since those URIs will never open a channel, might as
|
||||
// well consider them unsafe for better perf, and just in case.
|
||||
bool isSafe = false;
|
||||
|
||||
nsCOMPtr<nsIAboutModule> aboutMod;
|
||||
rv = NS_GetAboutModule(url, getter_AddRefs(aboutMod));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
isSafe = IsSafeToLinkForUntrustedContent(aboutMod, url);
|
||||
}
|
||||
|
||||
if (isSafe) {
|
||||
// We need to indicate that this baby is safe. Use an inner URI that
|
||||
// no one but the security manager will see. Make sure to preserve our
|
||||
// path, in case someone decides to hardcode checks for particular
|
||||
// about: URIs somewhere.
|
||||
nsAutoCString spec;
|
||||
rv = url->GetPath(spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
spec.Insert("moz-safe-about:", 0);
|
||||
|
||||
nsCOMPtr<nsIURI> inner;
|
||||
rv = NS_NewURI(getter_AddRefs(inner), spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsSimpleNestedURI* outer = new nsNestedAboutURI(inner, aBaseURI);
|
||||
NS_ENSURE_TRUE(outer, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
// Take a ref to it in the COMPtr we plan to return
|
||||
url = outer;
|
||||
|
||||
rv = outer->SetSpec(aSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// We don't want to allow mutation, since it would allow safe and
|
||||
// unsafe URIs to change into each other...
|
||||
NS_TryToSetImmutable(url);
|
||||
url.swap(*result);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutProtocolHandler::NewChannel2(nsIURI* uri,
|
||||
nsILoadInfo* aLoadInfo,
|
||||
nsIChannel** result)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(uri);
|
||||
|
||||
// about:what you ask?
|
||||
nsCOMPtr<nsIAboutModule> aboutMod;
|
||||
nsresult rv = NS_GetAboutModule(uri, getter_AddRefs(aboutMod));
|
||||
|
||||
nsAutoCString path;
|
||||
nsresult rv2 = NS_GetAboutModuleName(uri, path);
|
||||
if (NS_SUCCEEDED(rv2) && path.EqualsLiteral("srcdoc")) {
|
||||
// about:srcdoc is meant to be unresolvable, yet is included in the
|
||||
// about lookup tables so that it can pass security checks when used in
|
||||
// a srcdoc iframe. To ensure that it stays unresolvable, we pretend
|
||||
// that it doesn't exist.
|
||||
rv = NS_ERROR_FACTORY_NOT_REGISTERED;
|
||||
}
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// The standard return case:
|
||||
rv = aboutMod->NewChannel(uri, aLoadInfo, result);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// Not all implementations of nsIAboutModule::NewChannel()
|
||||
// set the LoadInfo on the newly created channel yet, as
|
||||
// an interim solution we set the LoadInfo here if not
|
||||
// available on the channel. Bug 1087720
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = (*result)->GetLoadInfo();
|
||||
if (aLoadInfo != loadInfo) {
|
||||
if (loadInfo) {
|
||||
NS_ASSERTION(false,
|
||||
"nsIAboutModule->newChannel(aURI, aLoadInfo) needs to set LoadInfo");
|
||||
const char16_t* params[] = {
|
||||
u"nsIAboutModule->newChannel(aURI)",
|
||||
u"nsIAboutModule->newChannel(aURI, aLoadInfo)"
|
||||
};
|
||||
nsContentUtils::ReportToConsole(
|
||||
nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("Security by Default"),
|
||||
nullptr, // aDocument
|
||||
nsContentUtils::eNECKO_PROPERTIES,
|
||||
"APIDeprecationWarning",
|
||||
params, mozilla::ArrayLength(params));
|
||||
}
|
||||
(*result)->SetLoadInfo(aLoadInfo);
|
||||
}
|
||||
|
||||
// If this URI is safe for untrusted content, enforce that its
|
||||
// principal be based on the channel's originalURI by setting the
|
||||
// owner to null.
|
||||
// Note: this relies on aboutMod's newChannel implementation
|
||||
// having set the proper originalURI, which probably isn't ideal.
|
||||
if (IsSafeForUntrustedContent(aboutMod, uri)) {
|
||||
(*result)->SetOwner(nullptr);
|
||||
}
|
||||
|
||||
RefPtr<nsNestedAboutURI> aboutURI;
|
||||
nsresult rv2 = uri->QueryInterface(kNestedAboutURICID,
|
||||
getter_AddRefs(aboutURI));
|
||||
if (NS_SUCCEEDED(rv2) && aboutURI->GetBaseURI()) {
|
||||
nsCOMPtr<nsIWritablePropertyBag2> writableBag =
|
||||
do_QueryInterface(*result);
|
||||
if (writableBag) {
|
||||
writableBag->
|
||||
SetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
|
||||
aboutURI->GetBaseURI());
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// mumble...
|
||||
|
||||
if (rv == NS_ERROR_FACTORY_NOT_REGISTERED) {
|
||||
// This looks like an about: we don't know about. Convert
|
||||
// this to an invalid URI error.
|
||||
rv = NS_ERROR_MALFORMED_URI;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
|
||||
{
|
||||
return NewChannel2(uri, nullptr, result);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsAboutProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
|
||||
{
|
||||
// don't override anything.
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Safe about protocol handler impl
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSafeAboutProtocolHandler, nsIProtocolHandler, nsISupportsWeakReference)
|
||||
|
||||
// nsIProtocolHandler methods:
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSafeAboutProtocolHandler::GetScheme(nsACString &result)
|
||||
{
|
||||
result.AssignLiteral("moz-safe-about");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSafeAboutProtocolHandler::GetDefaultPort(int32_t *result)
|
||||
{
|
||||
*result = -1; // no port for moz-safe-about: URLs
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSafeAboutProtocolHandler::GetProtocolFlags(uint32_t *result)
|
||||
{
|
||||
*result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE | URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSafeAboutProtocolHandler::NewURI(const nsACString &aSpec,
|
||||
const char *aCharset, // ignore charset info
|
||||
nsIURI *aBaseURI,
|
||||
nsIURI **result)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
nsCOMPtr<nsIURI> url = do_CreateInstance(kSimpleURICID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = url->SetSpec(aSpec);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_TryToSetImmutable(url);
|
||||
|
||||
*result = nullptr;
|
||||
url.swap(*result);
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSafeAboutProtocolHandler::NewChannel2(nsIURI* uri,
|
||||
nsILoadInfo* aLoadInfo,
|
||||
nsIChannel** result)
|
||||
{
|
||||
*result = nullptr;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSafeAboutProtocolHandler::NewChannel(nsIURI* uri, nsIChannel* *result)
|
||||
{
|
||||
*result = nullptr;
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSafeAboutProtocolHandler::AllowPort(int32_t port, const char *scheme, bool *_retval)
|
||||
{
|
||||
// don't override anything.
|
||||
*_retval = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// nsNestedAboutURI implementation
|
||||
NS_INTERFACE_MAP_BEGIN(nsNestedAboutURI)
|
||||
if (aIID.Equals(kNestedAboutURICID))
|
||||
foundInterface = static_cast<nsIURI*>(this);
|
||||
else
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsSimpleNestedURI)
|
||||
|
||||
// nsISerializable
|
||||
NS_IMETHODIMP
|
||||
nsNestedAboutURI::Read(nsIObjectInputStream* aStream)
|
||||
{
|
||||
nsresult rv = nsSimpleNestedURI::Read(aStream);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
bool haveBase;
|
||||
rv = aStream->ReadBoolean(&haveBase);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (haveBase) {
|
||||
nsCOMPtr<nsISupports> supports;
|
||||
rv = aStream->ReadObject(true, getter_AddRefs(supports));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mBaseURI = do_QueryInterface(supports, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNestedAboutURI::Write(nsIObjectOutputStream* aStream)
|
||||
{
|
||||
nsresult rv = nsSimpleNestedURI::Write(aStream);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = aStream->WriteBoolean(mBaseURI != nullptr);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (mBaseURI) {
|
||||
// A previous iteration of this code wrote out mBaseURI as nsISupports
|
||||
// and then read it in as nsIURI, which is non-kosher when mBaseURI
|
||||
// implements more than just a single line of interfaces and the
|
||||
// canonical nsISupports* isn't the one a static_cast<> of mBaseURI
|
||||
// would produce. For backwards compatibility with existing
|
||||
// serializations we continue to write mBaseURI as nsISupports but
|
||||
// switch to reading it as nsISupports, with a post-read QI to get to
|
||||
// nsIURI.
|
||||
rv = aStream->WriteCompoundObject(mBaseURI, NS_GET_IID(nsISupports),
|
||||
true);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsSimpleURI
|
||||
/* virtual */ nsSimpleURI*
|
||||
nsNestedAboutURI::StartClone(nsSimpleURI::RefHandlingEnum aRefHandlingMode,
|
||||
const nsACString& aNewRef)
|
||||
{
|
||||
// Sadly, we can't make use of nsSimpleNestedURI::StartClone here.
|
||||
// However, this function is expected to exactly match that function,
|
||||
// aside from the "new ns***URI()" call.
|
||||
NS_ENSURE_TRUE(mInnerURI, nullptr);
|
||||
|
||||
nsCOMPtr<nsIURI> innerClone;
|
||||
nsresult rv;
|
||||
if (aRefHandlingMode == eHonorRef) {
|
||||
rv = mInnerURI->Clone(getter_AddRefs(innerClone));
|
||||
} else if (aRefHandlingMode == eReplaceRef) {
|
||||
rv = mInnerURI->CloneWithNewRef(aNewRef, getter_AddRefs(innerClone));
|
||||
} else {
|
||||
rv = mInnerURI->CloneIgnoringRef(getter_AddRefs(innerClone));
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsNestedAboutURI* url = new nsNestedAboutURI(innerClone, mBaseURI);
|
||||
SetRefOnClone(url, aRefHandlingMode, aNewRef);
|
||||
url->SetMutable(false);
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
// nsIClassInfo
|
||||
NS_IMETHODIMP
|
||||
nsNestedAboutURI::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
|
||||
{
|
||||
*aClassIDNoAlloc = kNestedAboutURICID;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
90
netwerk/protocol/about/nsAboutProtocolHandler.h
Normal file
90
netwerk/protocol/about/nsAboutProtocolHandler.h
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAboutProtocolHandler_h___
|
||||
#define nsAboutProtocolHandler_h___
|
||||
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsSimpleNestedURI.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class nsAboutProtocolHandler : public nsIProtocolHandlerWithDynamicFlags
|
||||
, public nsIProtocolHandler
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIProtocolHandler methods:
|
||||
NS_DECL_NSIPROTOCOLHANDLER
|
||||
NS_DECL_NSIPROTOCOLHANDLERWITHDYNAMICFLAGS
|
||||
|
||||
// nsAboutProtocolHandler methods:
|
||||
nsAboutProtocolHandler() {}
|
||||
|
||||
private:
|
||||
virtual ~nsAboutProtocolHandler() {}
|
||||
};
|
||||
|
||||
class nsSafeAboutProtocolHandler final : public nsIProtocolHandler
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIProtocolHandler methods:
|
||||
NS_DECL_NSIPROTOCOLHANDLER
|
||||
|
||||
// nsSafeAboutProtocolHandler methods:
|
||||
nsSafeAboutProtocolHandler() {}
|
||||
|
||||
private:
|
||||
~nsSafeAboutProtocolHandler() {}
|
||||
};
|
||||
|
||||
|
||||
// Class to allow us to propagate the base URI to about:blank correctly
|
||||
class nsNestedAboutURI : public nsSimpleNestedURI {
|
||||
public:
|
||||
nsNestedAboutURI(nsIURI* aInnerURI, nsIURI* aBaseURI)
|
||||
: nsSimpleNestedURI(aInnerURI)
|
||||
, mBaseURI(aBaseURI)
|
||||
{}
|
||||
|
||||
// For use only from deserialization
|
||||
nsNestedAboutURI() : nsSimpleNestedURI() {}
|
||||
|
||||
virtual ~nsNestedAboutURI() {}
|
||||
|
||||
// Override QI so we can QI to our CID as needed
|
||||
NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
|
||||
|
||||
// Override StartClone(), the nsISerializable methods, and
|
||||
// GetClassIDNoAlloc; this last is needed to make our nsISerializable impl
|
||||
// work right.
|
||||
virtual nsSimpleURI* StartClone(RefHandlingEnum aRefHandlingMode,
|
||||
const nsACString& newRef);
|
||||
NS_IMETHOD Read(nsIObjectInputStream* aStream);
|
||||
NS_IMETHOD Write(nsIObjectOutputStream* aStream);
|
||||
NS_IMETHOD GetClassIDNoAlloc(nsCID *aClassIDNoAlloc);
|
||||
|
||||
nsIURI* GetBaseURI() const {
|
||||
return mBaseURI;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIURI> mBaseURI;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* nsAboutProtocolHandler_h___ */
|
||||
71
netwerk/protocol/about/nsAboutProtocolUtils.h
Normal file
71
netwerk/protocol/about/nsAboutProtocolUtils.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsAboutProtocolUtils_h
|
||||
#define nsAboutProtocolUtils_h
|
||||
|
||||
#include "nsIURI.h"
|
||||
#include "nsString.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsIAboutModule.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "prtime.h"
|
||||
|
||||
inline MOZ_MUST_USE nsresult
|
||||
NS_GetAboutModuleName(nsIURI *aAboutURI, nsCString& aModule)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
{
|
||||
bool isAbout;
|
||||
NS_ASSERTION(NS_SUCCEEDED(aAboutURI->SchemeIs("about", &isAbout)) &&
|
||||
isAbout,
|
||||
"should be used only on about: URIs");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult rv = aAboutURI->GetPath(aModule);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
int32_t f = aModule.FindCharInSet(NS_LITERAL_CSTRING("#?"));
|
||||
if (f != kNotFound) {
|
||||
aModule.Truncate(f);
|
||||
}
|
||||
|
||||
// convert to lowercase, as all about: modules are lowercase
|
||||
ToLowerCase(aModule);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
inline nsresult
|
||||
NS_GetAboutModule(nsIURI *aAboutURI, nsIAboutModule** aModule)
|
||||
{
|
||||
NS_PRECONDITION(aAboutURI, "Must have URI");
|
||||
|
||||
nsAutoCString contractID;
|
||||
nsresult rv = NS_GetAboutModuleName(aAboutURI, contractID);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// look up a handler to deal with "what"
|
||||
contractID.Insert(NS_LITERAL_CSTRING(NS_ABOUT_MODULE_CONTRACTID_PREFIX), 0);
|
||||
|
||||
return CallGetService(contractID.get(), aModule);
|
||||
}
|
||||
|
||||
inline PRTime SecondsToPRTime(uint32_t t_sec)
|
||||
{
|
||||
PRTime t_usec, usec_per_sec;
|
||||
t_usec = t_sec;
|
||||
usec_per_sec = PR_USEC_PER_SEC;
|
||||
return t_usec *= usec_per_sec;
|
||||
}
|
||||
inline void PrintTimeString(char *buf, uint32_t bufsize, uint32_t t_sec)
|
||||
{
|
||||
PRExplodedTime et;
|
||||
PRTime t_usec = SecondsToPRTime(t_sec);
|
||||
PR_ExplodeTime(t_usec, PR_LocalTimeParameters, &et);
|
||||
PR_FormatTime(buf, bufsize, "%Y-%m-%d %H:%M:%S", &et);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
88
netwerk/protocol/about/nsIAboutModule.idl
Normal file
88
netwerk/protocol/about/nsIAboutModule.idl
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIURI;
|
||||
interface nsIChannel;
|
||||
interface nsILoadInfo;
|
||||
|
||||
[scriptable, uuid(c0c19db9-1b5a-4ac5-b656-ed6f8149fa48)]
|
||||
interface nsIAboutModule : nsISupports
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructs a new channel for the about protocol module.
|
||||
*
|
||||
* @param aURI the uri of the new channel
|
||||
* @param aLoadInfo the loadinfo of the new channel
|
||||
*/
|
||||
nsIChannel newChannel(in nsIURI aURI,
|
||||
in nsILoadInfo aLoadInfo);
|
||||
|
||||
/**
|
||||
* A flag that indicates whether a URI should be run with content
|
||||
* privileges. If it is, the about: protocol handler will enforce that
|
||||
* the principal of channels created for it be based on their
|
||||
* originalURI or URI (depending on the channel flags), by setting
|
||||
* their "owner" to null.
|
||||
* If content needs to be able to link to this URI, specify
|
||||
* URI_CONTENT_LINKABLE as well.
|
||||
*/
|
||||
const unsigned long URI_SAFE_FOR_UNTRUSTED_CONTENT = (1 << 0);
|
||||
|
||||
/**
|
||||
* A flag that indicates whether script should be enabled for the
|
||||
* given about: URI even if it's disabled in general.
|
||||
*/
|
||||
const unsigned long ALLOW_SCRIPT = (1 << 1);
|
||||
|
||||
/**
|
||||
* A flag that indicates whether this about: URI doesn't want to be listed
|
||||
* in about:about, especially if it's not useful without a query string.
|
||||
*/
|
||||
const unsigned long HIDE_FROM_ABOUTABOUT = (1 << 2);
|
||||
|
||||
/**
|
||||
* A flag that indicates whether this about: URI wants Indexed DB enabled.
|
||||
*/
|
||||
const unsigned long ENABLE_INDEXED_DB = (1 << 3);
|
||||
|
||||
/**
|
||||
* A flag that indicates that this URI can be loaded in a child process
|
||||
*/
|
||||
const unsigned long URI_CAN_LOAD_IN_CHILD = (1 << 4);
|
||||
|
||||
/**
|
||||
* A flag that indicates that this URI must be loaded in a child process
|
||||
*/
|
||||
const unsigned long URI_MUST_LOAD_IN_CHILD = (1 << 5);
|
||||
|
||||
/**
|
||||
* Obsolete. This flag no longer has any effect and will be removed in future.
|
||||
*/
|
||||
const unsigned long MAKE_UNLINKABLE = (1 << 6);
|
||||
|
||||
/**
|
||||
* A flag that indicates that this URI should be linkable from content.
|
||||
* Ignored unless URI_SAFE_FOR_UNTRUSTED_CONTENT is also specified.
|
||||
*/
|
||||
const unsigned long MAKE_LINKABLE = (1 << 7);
|
||||
|
||||
/**
|
||||
* A method to get the flags that apply to a given about: URI. The URI
|
||||
* passed in is guaranteed to be one of the URIs that this module
|
||||
* registered to deal with.
|
||||
*/
|
||||
unsigned long getURIFlags(in nsIURI aURI);
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
||||
#define NS_ABOUT_MODULE_CONTRACTID "@mozilla.org/network/protocol/about;1"
|
||||
#define NS_ABOUT_MODULE_CONTRACTID_PREFIX NS_ABOUT_MODULE_CONTRACTID "?what="
|
||||
#define NS_ABOUT_MODULE_CONTRACTID_LENGTH 49 // strlen(NS_ABOUT_MODULE_CONTRACTID_PREFIX)
|
||||
|
||||
%}
|
||||
Loading…
Add table
Add a link
Reference in a new issue