mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge again
This commit is contained in:
commit
681b648ee2
@ -919,6 +919,10 @@ pref("network.websocket.max-connections", 200);
|
||||
// (i.e. wss://) websockets.
|
||||
pref("network.websocket.allowInsecureFromHTTPS", false);
|
||||
|
||||
// by default we delay websocket reconnects to same host/port if previous
|
||||
// connection failed, per RFC 6455 section 7.2.3
|
||||
pref("network.websocket.delay-failed-reconnects", true);
|
||||
|
||||
// </ws>
|
||||
|
||||
// Server-Sent Events
|
||||
|
@ -2,75 +2,74 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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 mozilla_net_AutoClose_h
|
||||
#define mozilla_net_AutoClose_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
// Like an nsAutoPtr for XPCOM streams (e.g. nsIAsyncInputStream) and other
|
||||
// refcounted classes that need to have the Close() method called explicitly
|
||||
// before they are destroyed.
|
||||
template <typename T>
|
||||
class AutoClose
|
||||
{
|
||||
public:
|
||||
AutoClose() { }
|
||||
~AutoClose(){
|
||||
Close();
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
already_AddRefed<T> forget()
|
||||
{
|
||||
return mPtr.forget();
|
||||
}
|
||||
|
||||
void takeOver(AutoClose<T> & rhs)
|
||||
{
|
||||
Close();
|
||||
mPtr = rhs.mPtr.forget();
|
||||
}
|
||||
|
||||
// assign from |do_QueryInterface(expr, &rv)|
|
||||
void operator=(const nsQueryInterfaceWithError rhs)
|
||||
{
|
||||
Close();
|
||||
mPtr = rhs;
|
||||
}
|
||||
|
||||
void CloseAndRelease()
|
||||
{
|
||||
Close();
|
||||
mPtr = nsnull;
|
||||
}
|
||||
|
||||
T* operator->() const
|
||||
{
|
||||
return mPtr.operator->();
|
||||
}
|
||||
|
||||
private:
|
||||
void Close()
|
||||
{
|
||||
if (mPtr) {
|
||||
mPtr->Close();
|
||||
}
|
||||
}
|
||||
|
||||
void operator=(const AutoClose<T> &) MOZ_DELETE;
|
||||
AutoClose(const AutoClose<T> &) MOZ_DELETE;
|
||||
|
||||
nsCOMPtr<T> mPtr;
|
||||
};
|
||||
|
||||
} } // namespace mozilla::net
|
||||
|
||||
#endif // mozilla_net_AutoClose_h
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_AutoClose_h
|
||||
#define mozilla_net_AutoClose_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
namespace mozilla { namespace net {
|
||||
|
||||
// Like an nsAutoPtr for XPCOM streams (e.g. nsIAsyncInputStream) and other
|
||||
// refcounted classes that need to have the Close() method called explicitly
|
||||
// before they are destroyed.
|
||||
template <typename T>
|
||||
class AutoClose
|
||||
{
|
||||
public:
|
||||
AutoClose() { }
|
||||
~AutoClose(){
|
||||
Close();
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return mPtr;
|
||||
}
|
||||
|
||||
already_AddRefed<T> forget()
|
||||
{
|
||||
return mPtr.forget();
|
||||
}
|
||||
|
||||
void takeOver(nsCOMPtr<T> & rhs)
|
||||
{
|
||||
Close();
|
||||
mPtr = rhs.forget();
|
||||
}
|
||||
|
||||
void takeOver(AutoClose<T> & rhs)
|
||||
{
|
||||
Close();
|
||||
mPtr = rhs.mPtr.forget();
|
||||
}
|
||||
|
||||
void CloseAndRelease()
|
||||
{
|
||||
Close();
|
||||
mPtr = nsnull;
|
||||
}
|
||||
|
||||
T* operator->() const
|
||||
{
|
||||
return mPtr.operator->();
|
||||
}
|
||||
|
||||
private:
|
||||
void Close()
|
||||
{
|
||||
if (mPtr) {
|
||||
mPtr->Close();
|
||||
}
|
||||
}
|
||||
|
||||
void operator=(const AutoClose<T> &) MOZ_DELETE;
|
||||
AutoClose(const AutoClose<T> &) MOZ_DELETE;
|
||||
|
||||
nsCOMPtr<T> mPtr;
|
||||
};
|
||||
|
||||
} } // namespace mozilla::net
|
||||
|
||||
#endif // mozilla_net_AutoClose_h
|
||||
|
@ -239,7 +239,7 @@ private:
|
||||
bool ResponseWouldVary() const;
|
||||
bool MustValidateBasedOnQueryUrl() const;
|
||||
nsresult SetupByteRangeRequest(PRUint32 partialLen);
|
||||
nsresult StartBufferingCachedEntity();
|
||||
nsresult OpenCacheInputStream(bool startBuffering);
|
||||
|
||||
nsCOMPtr<nsICacheListener> mChannel;
|
||||
const bool mHasQueryString;
|
||||
@ -266,7 +266,7 @@ private:
|
||||
friend class nsHttpChannel;
|
||||
/*in/out*/ nsHttpRequestHead mRequestHead;
|
||||
/*in/out*/ nsAutoPtr<nsTArray<nsCString> > mRedirectedCachekeys;
|
||||
/*out*/ AutoClose<nsIAsyncInputStream> mCacheAsyncInputStream;
|
||||
/*out*/ AutoClose<nsIInputStream> mCacheInputStream;
|
||||
/*out*/ nsAutoPtr<nsHttpResponseHead> mCachedResponseHead;
|
||||
/*out*/ nsCOMPtr<nsISupports> mCachedSecurityInfo;
|
||||
/*out*/ bool mCachedContentIsValid;
|
||||
@ -290,6 +290,8 @@ nsHttpChannel::nsHttpChannel()
|
||||
, mPostID(0)
|
||||
, mRequestTime(0)
|
||||
, mOnCacheEntryAvailableCallback(nsnull)
|
||||
, mOfflineCacheAccess(0)
|
||||
, mOfflineCacheLastModifiedTime(0)
|
||||
, mCachedContentIsValid(false)
|
||||
, mCachedContentIsPartial(false)
|
||||
, mTransactionReplaced(false)
|
||||
@ -973,9 +975,12 @@ nsHttpChannel::CallOnStartRequest()
|
||||
LOG(("writing to the offline cache"));
|
||||
rv = InitOfflineCacheEntry();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = InstallOfflineCacheListener();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// InitOfflineCacheEntry may have closed mOfflineCacheEntry
|
||||
if (mOfflineCacheEntry) {
|
||||
rv = InstallOfflineCacheListener();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
} else if (mCacheForOfflineUse) {
|
||||
LOG(("offline cache is up to date, not updating"));
|
||||
CloseOfflineCacheEntry();
|
||||
@ -1176,7 +1181,7 @@ nsHttpChannel::ProcessResponse()
|
||||
|
||||
MOZ_ASSERT(!mCachedContentIsValid);
|
||||
if (httpStatus != 304 && httpStatus != 206) {
|
||||
mCacheAsyncInputStream.CloseAndRelease();
|
||||
mCacheInputStream.CloseAndRelease();
|
||||
}
|
||||
|
||||
// notify "http-on-examine-response" observers
|
||||
@ -1225,7 +1230,7 @@ nsHttpChannel::ProcessResponse()
|
||||
if (mCachedContentIsPartial) // an internal byte range request...
|
||||
rv = ProcessPartialContent();
|
||||
else {
|
||||
mCacheAsyncInputStream.CloseAndRelease();
|
||||
mCacheInputStream.CloseAndRelease();
|
||||
rv = ProcessNormal();
|
||||
}
|
||||
break;
|
||||
@ -1260,7 +1265,7 @@ nsHttpChannel::ProcessResponse()
|
||||
rv = ProcessNotModified();
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("ProcessNotModified failed [rv=%x]\n", rv));
|
||||
mCacheAsyncInputStream.CloseAndRelease();
|
||||
mCacheInputStream.CloseAndRelease();
|
||||
rv = ProcessNormal();
|
||||
}
|
||||
else {
|
||||
@ -2135,8 +2140,15 @@ nsHttpChannel::ProcessNotModified()
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(mCachedResponseHead, NS_ERROR_NOT_INITIALIZED);
|
||||
NS_ENSURE_TRUE(mCacheEntry, NS_ERROR_NOT_INITIALIZED);
|
||||
if (!mDidReval) {
|
||||
LOG(("Server returned a 304 response even though we did not send a "
|
||||
"conditional request"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mCachedResponseHead);
|
||||
MOZ_ASSERT(mCacheEntry);
|
||||
NS_ENSURE_TRUE(mCachedResponseHead && mCacheEntry, NS_ERROR_UNEXPECTED);
|
||||
|
||||
// If the 304 response contains a Last-Modified different than the
|
||||
// one in our cache that is pretty suspicious and is, in at least the
|
||||
@ -2655,6 +2667,9 @@ nsHttpChannel::OnOfflineCacheEntryForWritingAvailable(
|
||||
if (NS_SUCCEEDED(aEntryStatus)) {
|
||||
mOfflineCacheEntry = aEntry;
|
||||
mOfflineCacheAccess = aAccess;
|
||||
if (NS_FAILED(aEntry->GetLastModified(&mOfflineCacheLastModifiedTime))) {
|
||||
mOfflineCacheLastModifiedTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (aEntryStatus == NS_ERROR_CACHE_WAIT_FOR_VALIDATION) {
|
||||
@ -2907,7 +2922,16 @@ HttpCacheQuery::CheckCache()
|
||||
|
||||
LOG(("HttpCacheQuery::CheckCache enter [channel=%p entry=%p access=%d]",
|
||||
mChannel.get(), mCacheEntry.get(), mCacheAccess));
|
||||
|
||||
|
||||
// Remember the request is a custom conditional request so that we can
|
||||
// process any 304 response correctly.
|
||||
mCustomConditionalRequest =
|
||||
mRequestHead.PeekHeader(nsHttp::If_Modified_Since) ||
|
||||
mRequestHead.PeekHeader(nsHttp::If_None_Match) ||
|
||||
mRequestHead.PeekHeader(nsHttp::If_Unmodified_Since) ||
|
||||
mRequestHead.PeekHeader(nsHttp::If_Match) ||
|
||||
mRequestHead.PeekHeader(nsHttp::If_Range);
|
||||
|
||||
// Be pessimistic: assume the cache entry has no useful data.
|
||||
mCachedContentIsValid = false;
|
||||
|
||||
@ -2966,7 +2990,7 @@ HttpCacheQuery::CheckCache()
|
||||
(mCacheAccess == nsICache::ACCESS_READ &&
|
||||
!(mLoadFlags & nsIRequest::INHIBIT_CACHING)) ||
|
||||
mFallbackChannel)) {
|
||||
rv = StartBufferingCachedEntity();
|
||||
rv = OpenCacheInputStream(true);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mCachedContentIsValid = true;
|
||||
// XXX: Isn't the cache entry already valid?
|
||||
@ -2975,13 +2999,6 @@ HttpCacheQuery::CheckCache()
|
||||
return rv;
|
||||
}
|
||||
|
||||
mCustomConditionalRequest =
|
||||
mRequestHead.PeekHeader(nsHttp::If_Modified_Since) ||
|
||||
mRequestHead.PeekHeader(nsHttp::If_None_Match) ||
|
||||
mRequestHead.PeekHeader(nsHttp::If_Unmodified_Since) ||
|
||||
mRequestHead.PeekHeader(nsHttp::If_Match) ||
|
||||
mRequestHead.PeekHeader(nsHttp::If_Range);
|
||||
|
||||
if (method != nsHttp::Head && !isCachedRedirect) {
|
||||
// If the cached content-length is set and it does not match the data
|
||||
// size of the cached content, then the cached response is partial...
|
||||
@ -3015,7 +3032,7 @@ HttpCacheQuery::CheckCache()
|
||||
rv = SetupByteRangeRequest(size);
|
||||
mCachedContentIsPartial = NS_SUCCEEDED(rv);
|
||||
if (mCachedContentIsPartial) {
|
||||
rv = StartBufferingCachedEntity();
|
||||
rv = OpenCacheInputStream(false);
|
||||
} else {
|
||||
// Make the request unconditional again.
|
||||
mRequestHead.ClearHeader(nsHttp::Range);
|
||||
@ -3193,13 +3210,8 @@ HttpCacheQuery::CheckCache()
|
||||
}
|
||||
}
|
||||
|
||||
// If there's any possibility that we may use the cached response's entity
|
||||
// then start reading it into memory now. If we have to revalidate the
|
||||
// entry and the revalidation fails, this will be a wasted effort, but
|
||||
// it is much more likely that either we don't need to revalidate the entry
|
||||
// or the entry will successfully revalidate.
|
||||
if (mCachedContentIsValid || mDidReval) {
|
||||
rv = StartBufferingCachedEntity();
|
||||
rv = OpenCacheInputStream(mCachedContentIsValid);
|
||||
if (NS_FAILED(rv)) {
|
||||
// If we can't get the entity then we have to act as though we
|
||||
// don't have the cache entry.
|
||||
@ -3287,13 +3299,11 @@ nsHttpChannel::ShouldUpdateOfflineCacheEntry()
|
||||
return true;
|
||||
}
|
||||
|
||||
PRUint32 offlineLastModifiedTime;
|
||||
rv = mOfflineCacheEntry->GetLastModified(&offlineLastModifiedTime);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (mOfflineCacheLastModifiedTime == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (docLastModifiedTime > offlineLastModifiedTime) {
|
||||
if (docLastModifiedTime > mOfflineCacheLastModifiedTime) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -3301,7 +3311,7 @@ nsHttpChannel::ShouldUpdateOfflineCacheEntry()
|
||||
}
|
||||
|
||||
nsresult
|
||||
HttpCacheQuery::StartBufferingCachedEntity()
|
||||
HttpCacheQuery::OpenCacheInputStream(bool startBuffering)
|
||||
{
|
||||
AssertOnCacheThread();
|
||||
|
||||
@ -3354,22 +3364,39 @@ HttpCacheQuery::StartBufferingCachedEntity()
|
||||
"load flag\n"));
|
||||
}
|
||||
|
||||
// Open an input stream for the entity, but DO NOT create/connect
|
||||
// mCachePump; that is done only when we decide to actually read the
|
||||
// cached entity. By opening the input stream here, we allow the stream
|
||||
// transport service to start reading the entity on one of its
|
||||
// background threads while we do validation (if any).
|
||||
|
||||
nsCOMPtr<nsIInputStream> wrapper;
|
||||
|
||||
// Open an input stream for the entity, so that the call to OpenInputStream
|
||||
// happens off the main thread.
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(stream));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("Failed to open cache input stream [channel=%p, "
|
||||
"mCacheEntry=%p]", mChannel.get(), mCacheEntry.get()));
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!startBuffering) {
|
||||
// We do not connect the stream to the stream transport service if we
|
||||
// have to validate the entry with the server. If we did, we would get
|
||||
// into a race condition between the stream transport service reading
|
||||
// the existing contents and the opening of the cache entry's output
|
||||
// stream to write the new contents in the case where we get a non-304
|
||||
// response.
|
||||
LOG(("Opened cache input stream without buffering [channel=%p, "
|
||||
"mCacheEntry=%p, stream=%p]", mChannel.get(),
|
||||
mCacheEntry.get(), stream.get()));
|
||||
mCacheInputStream.takeOver(stream);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Have the stream transport service start reading the entity on one of its
|
||||
// background threads.
|
||||
|
||||
nsCOMPtr<nsITransport> transport;
|
||||
nsCOMPtr<nsIInputStream> wrapper;
|
||||
|
||||
nsCOMPtr<nsIStreamTransportService> sts =
|
||||
do_GetService(kStreamTransportServiceCID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mCacheEntry->OpenInputStream(0, getter_AddRefs(stream));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = sts->CreateInputTransport(stream, PRInt64(-1), PRInt64(-1),
|
||||
true, getter_AddRefs(transport));
|
||||
@ -3377,9 +3404,6 @@ HttpCacheQuery::StartBufferingCachedEntity()
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = transport->OpenInputStream(0, 0, 0, getter_AddRefs(wrapper));
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
mCacheAsyncInputStream = do_QueryInterface(wrapper, &rv);
|
||||
}
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
LOG(("Opened cache input stream [channel=%p, wrapper=%p, "
|
||||
"transport=%p, stream=%p]", this, wrapper.get(),
|
||||
@ -3388,14 +3412,14 @@ HttpCacheQuery::StartBufferingCachedEntity()
|
||||
LOG(("Failed to open cache input stream [channel=%p, "
|
||||
"wrapper=%p, transport=%p, stream=%p]", this,
|
||||
wrapper.get(), transport.get(), stream.get()));
|
||||
|
||||
if (wrapper)
|
||||
wrapper->Close();
|
||||
if (stream)
|
||||
stream->Close();
|
||||
|
||||
stream->Close();
|
||||
return rv;
|
||||
}
|
||||
|
||||
return rv;
|
||||
mCacheInputStream.takeOver(wrapper);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Actually process the cached response that we started to handle in CheckCache
|
||||
@ -3439,7 +3463,7 @@ nsHttpChannel::ReadFromCache(bool alreadyMarkedValid)
|
||||
if (WillRedirect(mResponseHead)) {
|
||||
// TODO: Bug 759040 - We should call HandleAsyncRedirect directly here,
|
||||
// to avoid event dispatching latency.
|
||||
MOZ_ASSERT(!mCacheAsyncInputStream);
|
||||
MOZ_ASSERT(!mCacheInputStream);
|
||||
LOG(("Skipping skip read of cached redirect entity\n"));
|
||||
return AsyncCall(&nsHttpChannel::HandleAsyncRedirect);
|
||||
}
|
||||
@ -3448,7 +3472,7 @@ nsHttpChannel::ReadFromCache(bool alreadyMarkedValid)
|
||||
if (!mCacheForOfflineUse) {
|
||||
LOG(("Skipping read from cache based on LOAD_ONLY_IF_MODIFIED "
|
||||
"load flag\n"));
|
||||
MOZ_ASSERT(!mCacheAsyncInputStream);
|
||||
MOZ_ASSERT(!mCacheInputStream);
|
||||
// TODO: Bug 759040 - We should call HandleAsyncNotModified directly
|
||||
// here, to avoid event dispatching latency.
|
||||
return AsyncCall(&nsHttpChannel::HandleAsyncNotModified);
|
||||
@ -3457,22 +3481,22 @@ nsHttpChannel::ReadFromCache(bool alreadyMarkedValid)
|
||||
if (!ShouldUpdateOfflineCacheEntry()) {
|
||||
LOG(("Skipping read from cache based on LOAD_ONLY_IF_MODIFIED "
|
||||
"load flag (mCacheForOfflineUse case)\n"));
|
||||
mCacheAsyncInputStream.CloseAndRelease();
|
||||
mCacheInputStream.CloseAndRelease();
|
||||
// TODO: Bug 759040 - We should call HandleAsyncNotModified directly
|
||||
// here, to avoid event dispatching latency.
|
||||
return AsyncCall(&nsHttpChannel::HandleAsyncNotModified);
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mCacheAsyncInputStream);
|
||||
if (!mCacheAsyncInputStream) {
|
||||
NS_ERROR("mCacheAsyncInputStream is null but we're expecting to "
|
||||
MOZ_ASSERT(mCacheInputStream);
|
||||
if (!mCacheInputStream) {
|
||||
NS_ERROR("mCacheInputStream is null but we're expecting to "
|
||||
"be able to read from it.");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> inputStream = mCacheAsyncInputStream.forget();
|
||||
nsCOMPtr<nsIInputStream> inputStream = mCacheInputStream.forget();
|
||||
|
||||
rv = nsInputStreamPump::Create(getter_AddRefs(mCachePump), inputStream,
|
||||
PRInt64(-1), PRInt64(-1), 0, 0, true);
|
||||
@ -3498,7 +3522,7 @@ void
|
||||
nsHttpChannel::CloseCacheEntry(bool doomOnFailure)
|
||||
{
|
||||
mCacheQuery = nsnull;
|
||||
mCacheAsyncInputStream.CloseAndRelease();
|
||||
mCacheInputStream.CloseAndRelease();
|
||||
|
||||
if (!mCacheEntry)
|
||||
return;
|
||||
@ -4247,7 +4271,7 @@ nsHttpChannel::Cancel(nsresult status)
|
||||
if (mTransactionPump)
|
||||
mTransactionPump->Cancel(status);
|
||||
mCacheQuery = nsnull;
|
||||
mCacheAsyncInputStream.CloseAndRelease();
|
||||
mCacheInputStream.CloseAndRelease();
|
||||
if (mCachePump)
|
||||
mCachePump->Cancel(status);
|
||||
if (mAuthProvider)
|
||||
@ -5436,7 +5460,7 @@ nsHttpChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry,
|
||||
if (mCacheQuery) {
|
||||
mRequestHead = mCacheQuery->mRequestHead;
|
||||
mRedirectedCachekeys = mCacheQuery->mRedirectedCachekeys.forget();
|
||||
mCacheAsyncInputStream.takeOver(mCacheQuery->mCacheAsyncInputStream);
|
||||
mCacheInputStream.takeOver(mCacheQuery->mCacheInputStream);
|
||||
mCachedResponseHead = mCacheQuery->mCachedResponseHead.forget();
|
||||
mCachedSecurityInfo = mCacheQuery->mCachedSecurityInfo.forget();
|
||||
mCachedContentIsValid = mCacheQuery->mCachedContentIsValid;
|
||||
@ -5450,7 +5474,7 @@ nsHttpChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry,
|
||||
// if the channel's already fired onStopRequest, then we should ignore
|
||||
// this event.
|
||||
if (!mIsPending) {
|
||||
mCacheAsyncInputStream.CloseAndRelease();
|
||||
mCacheInputStream.CloseAndRelease();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -223,7 +223,6 @@ private:
|
||||
nsresult UpdateExpirationTime();
|
||||
nsresult CheckCache();
|
||||
bool ShouldUpdateOfflineCacheEntry();
|
||||
nsresult StartBufferingCachedEntity(bool usingSSL);
|
||||
nsresult ReadFromCache(bool alreadyMarkedValid);
|
||||
void CloseCacheEntry(bool doomOnFailure);
|
||||
void CloseOfflineCacheEntry();
|
||||
@ -294,8 +293,8 @@ private:
|
||||
// cache specific data
|
||||
nsRefPtr<HttpCacheQuery> mCacheQuery;
|
||||
nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
|
||||
// We must close mCacheAsyncInputStream explicitly to avoid leaks.
|
||||
AutoClose<nsIAsyncInputStream> mCacheAsyncInputStream;
|
||||
// We must close mCacheInputStream explicitly to avoid leaks.
|
||||
AutoClose<nsIInputStream> mCacheInputStream;
|
||||
nsRefPtr<nsInputStreamPump> mCachePump;
|
||||
nsAutoPtr<nsHttpResponseHead> mCachedResponseHead;
|
||||
nsCOMPtr<nsISupports> mCachedSecurityInfo;
|
||||
@ -310,6 +309,7 @@ private:
|
||||
|
||||
nsCOMPtr<nsICacheEntryDescriptor> mOfflineCacheEntry;
|
||||
nsCacheAccessMode mOfflineCacheAccess;
|
||||
PRUint32 mOfflineCacheLastModifiedTime;
|
||||
nsCString mOfflineCacheClientID;
|
||||
|
||||
nsCOMPtr<nsIFile> mProfileDirectory;
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "nsProxyRelease.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "TimeStamp.h"
|
||||
|
||||
#include "plbase64.h"
|
||||
#include "prmem.h"
|
||||
@ -41,8 +42,14 @@
|
||||
#include "prbit.h"
|
||||
#include "zlib.h"
|
||||
|
||||
// rather than slurp up all of nsIWebSocket.idl, which lives outside necko, just
|
||||
// dupe one constant we need from it
|
||||
#define CLOSE_GOING_AWAY 1001
|
||||
|
||||
extern PRThread *gSocketThread;
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
@ -77,6 +84,403 @@ NS_IMPL_THREADSAFE_ISUPPORTS11(WebSocketChannel,
|
||||
|
||||
// some helper classes
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FailDelayManager
|
||||
//
|
||||
// Stores entries (searchable by {host, port}) of connections that have recently
|
||||
// failed, so we can do delay of reconnects per RFC 6455 Section 7.2.3
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// Initial reconnect delay is randomly chosen between 200-400 ms.
|
||||
// This is a gentler backoff than the 0-5 seconds the spec offhandedly suggests.
|
||||
const PRUint32 kWSReconnectInitialBaseDelay = 200;
|
||||
const PRUint32 kWSReconnectInitialRandomDelay = 200;
|
||||
|
||||
// Base lifetime (in ms) of a FailDelay: kept longer if more failures occur
|
||||
const PRUint32 kWSReconnectBaseLifeTime = 60 * 1000;
|
||||
// Maximum reconnect delay (in ms)
|
||||
const PRUint32 kWSReconnectMaxDelay = 60 * 1000;
|
||||
|
||||
// hold record of failed connections, and calculates needed delay for reconnects
|
||||
// to same host/port.
|
||||
class FailDelay
|
||||
{
|
||||
public:
|
||||
FailDelay(nsCString address, PRInt32 port)
|
||||
: mAddress(address), mPort(port)
|
||||
{
|
||||
mLastFailure = TimeStamp::Now();
|
||||
mNextDelay = kWSReconnectInitialBaseDelay +
|
||||
(rand() % kWSReconnectInitialRandomDelay);
|
||||
}
|
||||
|
||||
// Called to update settings when connection fails again.
|
||||
void FailedAgain()
|
||||
{
|
||||
mLastFailure = TimeStamp::Now();
|
||||
// We use a truncated exponential backoff as suggested by RFC 6455,
|
||||
// but multiply by 1.5 instead of 2 to be more gradual.
|
||||
mNextDelay = PR_MIN(kWSReconnectMaxDelay, mNextDelay * 1.5);
|
||||
LOG(("WebSocket: FailedAgain: host=%s, port=%d: incremented delay to %lu",
|
||||
mAddress.get(), mPort, mNextDelay));
|
||||
}
|
||||
|
||||
// returns 0 if there is no need to delay (i.e. delay interval is over)
|
||||
PRUint32 RemainingDelay(TimeStamp rightNow)
|
||||
{
|
||||
TimeDuration dur = rightNow - mLastFailure;
|
||||
PRUint32 sinceFail = (PRUint32) dur.ToMilliseconds();
|
||||
if (sinceFail > mNextDelay)
|
||||
return 0;
|
||||
|
||||
return mNextDelay - sinceFail;
|
||||
}
|
||||
|
||||
bool IsExpired(TimeStamp rightNow)
|
||||
{
|
||||
return (mLastFailure +
|
||||
TimeDuration::FromMilliseconds(kWSReconnectBaseLifeTime + mNextDelay))
|
||||
<= rightNow;
|
||||
}
|
||||
|
||||
nsCString mAddress; // IP address (or hostname if using proxy)
|
||||
PRInt32 mPort;
|
||||
|
||||
private:
|
||||
TimeStamp mLastFailure; // Time of last failed attempt
|
||||
// mLastFailure + mNextDelay is the soonest we'll allow a reconnect
|
||||
PRUint32 mNextDelay; // milliseconds
|
||||
};
|
||||
|
||||
class FailDelayManager
|
||||
{
|
||||
public:
|
||||
FailDelayManager()
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsWSAdmissionManager);
|
||||
|
||||
mDelaysDisabled = false;
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefService =
|
||||
do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
bool boolpref = true;
|
||||
nsresult rv;
|
||||
rv = prefService->GetBoolPref("network.websocket.delay-failed-reconnects",
|
||||
&boolpref);
|
||||
if (NS_SUCCEEDED(rv) && !boolpref) {
|
||||
mDelaysDisabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
~FailDelayManager()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsWSAdmissionManager);
|
||||
for (PRUint32 i = 0; i < mEntries.Length(); i++) {
|
||||
delete mEntries[i];
|
||||
}
|
||||
}
|
||||
|
||||
void Add(nsCString &address, PRInt32 port)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
||||
|
||||
if (mDelaysDisabled)
|
||||
return;
|
||||
|
||||
FailDelay *record = new FailDelay(address, port);
|
||||
mEntries.AppendElement(record);
|
||||
}
|
||||
|
||||
// Element returned may not be valid after next main thread event: don't keep
|
||||
// pointer to it around
|
||||
FailDelay* Lookup(nsCString &address, PRInt32 port,
|
||||
PRUint32 *outIndex = nsnull)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
||||
|
||||
if (mDelaysDisabled)
|
||||
return nsnull;
|
||||
|
||||
FailDelay *result = nsnull;
|
||||
TimeStamp rightNow = TimeStamp::Now();
|
||||
|
||||
// We also remove expired entries during search: iterate from end to make
|
||||
// indexing simpler
|
||||
for (PRInt32 i = mEntries.Length() - 1; i >= 0; --i) {
|
||||
FailDelay *fail = mEntries[i];
|
||||
if (fail->mAddress.Equals(address) && fail->mPort == port) {
|
||||
if (outIndex)
|
||||
*outIndex = i;
|
||||
result = fail;
|
||||
} else if (fail->IsExpired(rightNow)) {
|
||||
mEntries.RemoveElementAt(i);
|
||||
delete fail;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// returns true if channel connects immediately, or false if it's delayed
|
||||
bool DelayOrBegin(WebSocketChannel *ws)
|
||||
{
|
||||
if (!mDelaysDisabled) {
|
||||
PRUint32 failIndex = 0;
|
||||
FailDelay *fail = Lookup(ws->mAddress, ws->mPort, &failIndex);
|
||||
|
||||
if (fail) {
|
||||
TimeStamp rightNow = TimeStamp::Now();
|
||||
|
||||
PRUint32 remainingDelay = fail->RemainingDelay(rightNow);
|
||||
if (remainingDelay) {
|
||||
// reconnecting within delay interval: delay by remaining time
|
||||
nsresult rv;
|
||||
ws->mReconnectDelayTimer =
|
||||
do_CreateInstance("@mozilla.org/timer;1", &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = ws->mReconnectDelayTimer->InitWithCallback(
|
||||
ws, remainingDelay, nsITimer::TYPE_ONE_SHOT);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
LOG(("WebSocket: delaying websocket [this=%p] by %lu ms",
|
||||
ws, (unsigned long)remainingDelay));
|
||||
ws->mConnecting = CONNECTING_DELAYED;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// if timer fails (which is very unlikely), drop down to BeginOpen call
|
||||
} else if (fail->IsExpired(rightNow)) {
|
||||
mEntries.RemoveElementAt(failIndex);
|
||||
delete fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delays disabled, or no previous failure, or we're reconnecting after scheduled
|
||||
// delay interval has passed: connect.
|
||||
//
|
||||
ws->mConnecting = CONNECTING_IN_PROGRESS;
|
||||
// If BeginOpen fails, it calls AbortSession, which calls OnStopSession,
|
||||
// which will ensure any remaining queued connection(s) are scheduled
|
||||
return ws->BeginOpen();
|
||||
}
|
||||
|
||||
// Remove() also deletes all expired entries as it iterates: better for
|
||||
// battery life than using a periodic timer.
|
||||
void Remove(nsCString &address, PRInt32 port)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
||||
|
||||
TimeStamp rightNow = TimeStamp::Now();
|
||||
|
||||
// iterate from end, to make deletion indexing easier
|
||||
for (PRInt32 i = mEntries.Length() - 1; i >= 0; --i) {
|
||||
FailDelay *entry = mEntries[i];
|
||||
if ((entry->mAddress.Equals(address) && entry->mPort == port) ||
|
||||
entry->IsExpired(rightNow)) {
|
||||
mEntries.RemoveElementAt(i);
|
||||
delete entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsTArray<FailDelay *> mEntries;
|
||||
bool mDelaysDisabled;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsWSAdmissionManager
|
||||
//
|
||||
// 1) Ensures that only one websocket at a time is CONNECTING to a given IP
|
||||
// address (or hostname, if using proxy), per RFC 6455 Section 4.1.
|
||||
// 2) Delays reconnects to IP/host after connection failure, per Section 7.2.3
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class nsWSAdmissionManager
|
||||
{
|
||||
public:
|
||||
nsWSAdmissionManager() : mSessionCount(0)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsWSAdmissionManager);
|
||||
}
|
||||
|
||||
class nsOpenConn
|
||||
{
|
||||
public:
|
||||
nsOpenConn(nsCString &addr, WebSocketChannel *channel)
|
||||
: mAddress(addr), mChannel(channel) { MOZ_COUNT_CTOR(nsOpenConn); }
|
||||
~nsOpenConn() { MOZ_COUNT_DTOR(nsOpenConn); }
|
||||
|
||||
nsCString mAddress;
|
||||
WebSocketChannel *mChannel;
|
||||
};
|
||||
|
||||
~nsWSAdmissionManager()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsWSAdmissionManager);
|
||||
for (PRUint32 i = 0; i < mQueue.Length(); i++)
|
||||
delete mQueue[i];
|
||||
}
|
||||
|
||||
// Determine if we will open connection immediately (returns true), or
|
||||
// delay/queue the connection (returns false)
|
||||
bool ConditionallyConnect(WebSocketChannel *ws)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
||||
NS_ABORT_IF_FALSE(ws->mConnecting == NOT_CONNECTING, "opening state");
|
||||
|
||||
// If there is already another WS channel connecting to this IP address,
|
||||
// defer BeginOpen and mark as waiting in queue.
|
||||
bool found = (IndexOf(ws->mAddress) >= 0);
|
||||
|
||||
// Always add ourselves to queue, even if we'll connect immediately
|
||||
nsOpenConn *newdata = new nsOpenConn(ws->mAddress, ws);
|
||||
mQueue.AppendElement(newdata);
|
||||
|
||||
if (found) {
|
||||
ws->mConnecting = CONNECTING_QUEUED;
|
||||
return false;
|
||||
}
|
||||
|
||||
return mFailures.DelayOrBegin(ws);
|
||||
}
|
||||
|
||||
bool OnConnected(WebSocketChannel *aChannel)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
||||
NS_ABORT_IF_FALSE(aChannel->mConnecting == CONNECTING_IN_PROGRESS,
|
||||
"Channel completed connect, but not connecting?");
|
||||
|
||||
aChannel->mConnecting = NOT_CONNECTING;
|
||||
|
||||
// Remove from queue
|
||||
RemoveFromQueue(aChannel);
|
||||
|
||||
// Connection succeeded, so stop keeping track of any previous failures
|
||||
mFailures.Remove(aChannel->mAddress, aChannel->mPort);
|
||||
|
||||
// Check for queued connections to same host.
|
||||
// Note: still need to check for failures, since next websocket with same
|
||||
// host may have different port
|
||||
return ConnectNext(aChannel->mAddress);
|
||||
}
|
||||
|
||||
// Called every time a websocket channel ends its session (including going away
|
||||
// w/o ever successfully creating a connection)
|
||||
bool OnStopSession(WebSocketChannel *aChannel, nsresult aReason)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
||||
|
||||
if (NS_FAILED(aReason)) {
|
||||
// Have we seen this failure before?
|
||||
FailDelay *knownFailure = mFailures.Lookup(aChannel->mAddress,
|
||||
aChannel->mPort);
|
||||
if (knownFailure) {
|
||||
// repeated failure to connect: increase delay for next connection
|
||||
knownFailure->FailedAgain();
|
||||
} else {
|
||||
// new connection failure: record it.
|
||||
LOG(("WebSocket: connection to %s, %d failed: [this=%p]",
|
||||
aChannel->mAddress.get(), (int)aChannel->mPort, aChannel));
|
||||
mFailures.Add(aChannel->mAddress, aChannel->mPort);
|
||||
}
|
||||
}
|
||||
|
||||
if (aChannel->mConnecting) {
|
||||
// Only way a connecting channel may get here w/o failing is if it was
|
||||
// closed with GOING_AWAY (1001) because of navigation, tab close, etc.
|
||||
NS_ABORT_IF_FALSE(NS_FAILED(aReason) ||
|
||||
aChannel->mScriptCloseCode == CLOSE_GOING_AWAY,
|
||||
"websocket closed while connecting w/o failing?");
|
||||
|
||||
RemoveFromQueue(aChannel);
|
||||
|
||||
bool wasNotQueued = (aChannel->mConnecting != CONNECTING_QUEUED);
|
||||
aChannel->mConnecting = NOT_CONNECTING;
|
||||
if (wasNotQueued)
|
||||
return ConnectNext(aChannel->mAddress);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConnectNext(nsCString &hostName)
|
||||
{
|
||||
PRInt32 index = IndexOf(hostName);
|
||||
if (index >= 0) {
|
||||
WebSocketChannel *chan = mQueue[index]->mChannel;
|
||||
|
||||
NS_ABORT_IF_FALSE(chan->mConnecting == CONNECTING_QUEUED,
|
||||
"transaction not queued but in queue");
|
||||
LOG(("WebSocket: ConnectNext: found channel [this=%p] in queue", chan));
|
||||
|
||||
return mFailures.DelayOrBegin(chan);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void IncrementSessionCount()
|
||||
{
|
||||
PR_ATOMIC_INCREMENT(&mSessionCount);
|
||||
}
|
||||
|
||||
void DecrementSessionCount()
|
||||
{
|
||||
PR_ATOMIC_DECREMENT(&mSessionCount);
|
||||
}
|
||||
|
||||
PRInt32 SessionCount()
|
||||
{
|
||||
return mSessionCount;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void RemoveFromQueue(WebSocketChannel *aChannel)
|
||||
{
|
||||
PRInt32 index = IndexOf(aChannel);
|
||||
NS_ABORT_IF_FALSE(index >= 0, "connection to remove not in queue");
|
||||
if (index >= 0) {
|
||||
nsOpenConn *olddata = mQueue[index];
|
||||
mQueue.RemoveElementAt(index);
|
||||
delete olddata;
|
||||
}
|
||||
}
|
||||
|
||||
PRInt32 IndexOf(nsCString &aStr)
|
||||
{
|
||||
for (PRUint32 i = 0; i < mQueue.Length(); i++)
|
||||
if (aStr == (mQueue[i])->mAddress)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PRInt32 IndexOf(WebSocketChannel *aChannel)
|
||||
{
|
||||
for (PRUint32 i = 0; i < mQueue.Length(); i++)
|
||||
if (aChannel == (mQueue[i])->mChannel)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// SessionCount might be decremented from the main or the socket
|
||||
// thread, so manage it with atomic counters
|
||||
PRInt32 mSessionCount;
|
||||
|
||||
// Queue for websockets that have not completed connecting yet.
|
||||
// The first nsOpenConn with a given address will be either be
|
||||
// CONNECTING_IN_PROGRESS or CONNECTING_DELAYED. Later ones with the same
|
||||
// hostname must be CONNECTING_QUEUED.
|
||||
//
|
||||
// We could hash hostnames instead of using a single big vector here, but the
|
||||
// dataset is expected to be small.
|
||||
nsTArray<nsOpenConn *> mQueue;
|
||||
|
||||
FailDelayManager mFailures;
|
||||
};
|
||||
|
||||
static nsWSAdmissionManager *sWebSocketAdmissions = nsnull;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CallOnMessageAvailable
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -121,14 +525,18 @@ public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
CallOnStop(WebSocketChannel *aChannel,
|
||||
nsresult aData)
|
||||
nsresult aReason)
|
||||
: mChannel(aChannel),
|
||||
mData(aData) {}
|
||||
mReason(aReason) {}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
||||
mChannel->mListener->OnStop(mChannel->mContext, mData);
|
||||
|
||||
sWebSocketAdmissions->OnStopSession(mChannel, mReason);
|
||||
|
||||
if (mChannel->mListener)
|
||||
mChannel->mListener->OnStop(mChannel->mContext, mReason);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -136,7 +544,7 @@ private:
|
||||
~CallOnStop() {}
|
||||
|
||||
nsRefPtr<WebSocketChannel> mChannel;
|
||||
nsresult mData;
|
||||
nsresult mReason;
|
||||
};
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(CallOnStop, nsIRunnable)
|
||||
|
||||
@ -370,176 +778,6 @@ private:
|
||||
};
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(OutboundEnqueuer, nsIRunnable)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsWSAdmissionManager
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Section 4.1 requires that only a single websocket at a time can be CONNECTING
|
||||
// to any given IP address (or hostname, if proxy doing DNS for us). This class
|
||||
// ensures that we delay connecting until any pending connection for the same
|
||||
// IP/addr is complete (i.e. until before the 101 upgrade complete response
|
||||
// comes back and an 'open' javascript event is created)
|
||||
|
||||
class nsWSAdmissionManager
|
||||
{
|
||||
public:
|
||||
nsWSAdmissionManager() : mSessionCount(0)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsWSAdmissionManager);
|
||||
}
|
||||
|
||||
class nsOpenConn
|
||||
{
|
||||
public:
|
||||
nsOpenConn(nsCString &addr, WebSocketChannel *channel)
|
||||
: mAddress(addr), mChannel(channel) { MOZ_COUNT_CTOR(nsOpenConn); }
|
||||
~nsOpenConn() { MOZ_COUNT_DTOR(nsOpenConn); }
|
||||
|
||||
nsCString mAddress;
|
||||
WebSocketChannel *mChannel;
|
||||
};
|
||||
|
||||
~nsWSAdmissionManager()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsWSAdmissionManager);
|
||||
for (PRUint32 i = 0; i < mData.Length(); i++)
|
||||
delete mData[i];
|
||||
}
|
||||
|
||||
bool ConditionallyConnect(nsCString &aStr, WebSocketChannel *ws)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
||||
|
||||
// if aStr is not in mData then we return true, else false.
|
||||
// in either case aStr is then added to mData - meaning
|
||||
// there will be duplicates when this function has been
|
||||
// called with the same parameter multiple times.
|
||||
|
||||
// we could hash this, but the dataset is expected to be
|
||||
// small
|
||||
|
||||
// There may already be another WS channel connecting to this IP address, in
|
||||
// which case we'll still create a new nsOpenConn but defer BeginOpen until
|
||||
// that channel completes connecting.
|
||||
bool found = (IndexOf(aStr) >= 0);
|
||||
nsOpenConn *newdata = new nsOpenConn(aStr, ws);
|
||||
mData.AppendElement(newdata);
|
||||
|
||||
NS_ABORT_IF_FALSE (!ws->mOpenRunning && !ws->mOpenBlocked,
|
||||
"opening state");
|
||||
|
||||
if (!found) {
|
||||
ws->mOpenRunning = 1;
|
||||
ws->BeginOpen();
|
||||
} else {
|
||||
ws->mOpenBlocked = 1;
|
||||
}
|
||||
|
||||
return !found;
|
||||
}
|
||||
|
||||
bool Complete(WebSocketChannel *aChannel)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
||||
NS_ABORT_IF_FALSE(!aChannel->mOpenBlocked,
|
||||
"blocked, but complete nsOpenConn");
|
||||
|
||||
// It is possible this has already been canceled
|
||||
if (!aChannel->mOpenRunning)
|
||||
return false;
|
||||
|
||||
PRInt32 index = IndexOf(aChannel);
|
||||
NS_ABORT_IF_FALSE(index >= 0, "completed connection not in open list");
|
||||
|
||||
aChannel->mOpenRunning = 0;
|
||||
nsOpenConn *olddata = mData[index];
|
||||
mData.RemoveElementAt(index);
|
||||
delete olddata;
|
||||
|
||||
// are there more of the same address pending dispatch?
|
||||
return ConnectNext(aChannel->mAddress);
|
||||
}
|
||||
|
||||
bool Cancel(WebSocketChannel *aChannel)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
||||
PRInt32 index = IndexOf(aChannel);
|
||||
NS_ABORT_IF_FALSE(index >= 0, "Cancelled connection not in open list");
|
||||
NS_ABORT_IF_FALSE(aChannel->mOpenRunning ^ aChannel->mOpenBlocked,
|
||||
"cancel without running xor blocked");
|
||||
|
||||
bool wasRunning = aChannel->mOpenRunning;
|
||||
aChannel->mOpenRunning = 0;
|
||||
aChannel->mOpenBlocked = 0;
|
||||
nsOpenConn *olddata = mData[index];
|
||||
mData.RemoveElementAt(index);
|
||||
delete olddata;
|
||||
|
||||
// if we are running we can run another one
|
||||
if (wasRunning)
|
||||
return ConnectNext(aChannel->mAddress);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConnectNext(nsCString &hostName)
|
||||
{
|
||||
PRInt32 index = IndexOf(hostName);
|
||||
if (index >= 0) {
|
||||
WebSocketChannel *chan = mData[index]->mChannel;
|
||||
|
||||
NS_ABORT_IF_FALSE(chan->mOpenBlocked,
|
||||
"transaction not blocked but in queue");
|
||||
NS_ABORT_IF_FALSE(!chan->mOpenRunning, "transaction already running");
|
||||
|
||||
chan->mOpenBlocked = 0;
|
||||
chan->mOpenRunning = 1;
|
||||
chan->BeginOpen();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void IncrementSessionCount()
|
||||
{
|
||||
PR_ATOMIC_INCREMENT(&mSessionCount);
|
||||
}
|
||||
|
||||
void DecrementSessionCount()
|
||||
{
|
||||
PR_ATOMIC_DECREMENT(&mSessionCount);
|
||||
}
|
||||
|
||||
PRInt32 SessionCount()
|
||||
{
|
||||
return mSessionCount;
|
||||
}
|
||||
|
||||
private:
|
||||
nsTArray<nsOpenConn *> mData;
|
||||
|
||||
PRInt32 IndexOf(nsCString &aStr)
|
||||
{
|
||||
for (PRUint32 i = 0; i < mData.Length(); i++)
|
||||
if (aStr == (mData[i])->mAddress)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PRInt32 IndexOf(WebSocketChannel *aChannel)
|
||||
{
|
||||
for (PRUint32 i = 0; i < mData.Length(); i++)
|
||||
if (aChannel == (mData[i])->mChannel)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// SessionCount might be decremented from the main or the socket
|
||||
// thread, so manage it with atomic counters
|
||||
PRInt32 mSessionCount;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsWSCompression
|
||||
//
|
||||
@ -667,15 +905,15 @@ private:
|
||||
PRUint8 mBuffer[kBufferLen];
|
||||
};
|
||||
|
||||
static nsWSAdmissionManager *sWebSocketAdmissions = nsnull;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// WebSocketChannel
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
WebSocketChannel::WebSocketChannel() :
|
||||
mPort(0),
|
||||
mCloseTimeout(20000),
|
||||
mOpenTimeout(20000),
|
||||
mConnecting(NOT_CONNECTING),
|
||||
mPingTimeout(0),
|
||||
mPingResponseTimeout(10000),
|
||||
mMaxConcurrentConnections(200),
|
||||
@ -691,8 +929,6 @@ WebSocketChannel::WebSocketChannel() :
|
||||
mAutoFollowRedirects(0),
|
||||
mReleaseOnTransmit(0),
|
||||
mTCPClosed(0),
|
||||
mOpenBlocked(0),
|
||||
mOpenRunning(0),
|
||||
mChannelWasOpened(0),
|
||||
mDataStarted(0),
|
||||
mIncrementedSessionCount(0),
|
||||
@ -727,7 +963,7 @@ WebSocketChannel::~WebSocketChannel()
|
||||
|
||||
// this stop is a nop if the normal connect/close is followed
|
||||
StopSession(NS_ERROR_UNEXPECTED);
|
||||
NS_ABORT_IF_FALSE(!mOpenRunning && !mOpenBlocked, "op");
|
||||
NS_ABORT_IF_FALSE(mConnecting == NOT_CONNECTING, "op");
|
||||
|
||||
moz_free(mBuffer);
|
||||
moz_free(mDynamicOutput);
|
||||
@ -781,7 +1017,7 @@ WebSocketChannel::Shutdown()
|
||||
sWebSocketAdmissions = nsnull;
|
||||
}
|
||||
|
||||
nsresult
|
||||
bool
|
||||
WebSocketChannel::BeginOpen()
|
||||
{
|
||||
LOG(("WebSocketChannel::BeginOpen() %p\n", this));
|
||||
@ -793,29 +1029,40 @@ WebSocketChannel::BeginOpen()
|
||||
LOG(("WebSocketChannel::BeginOpen: Resuming Redirect\n"));
|
||||
rv = mRedirectCallback->OnRedirectVerifyCallback(NS_OK);
|
||||
mRedirectCallback = nsnull;
|
||||
return rv;
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> localChannel = do_QueryInterface(mChannel, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("WebSocketChannel::BeginOpen: cannot async open\n"));
|
||||
AbortSession(NS_ERROR_UNEXPECTED);
|
||||
return rv;
|
||||
return false;
|
||||
}
|
||||
|
||||
rv = localChannel->AsyncOpen(this, mHttpChannel);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("WebSocketChannel::BeginOpen: cannot async open\n"));
|
||||
AbortSession(NS_ERROR_CONNECTION_REFUSED);
|
||||
return rv;
|
||||
return false;
|
||||
}
|
||||
mChannelWasOpened = 1;
|
||||
|
||||
mOpenTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mOpenTimer->InitWithCallback(this, mOpenTimeout, nsITimer::TYPE_ONE_SHOT);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("WebSocketChannel::BeginOpen: cannot create open timer\n"));
|
||||
AbortSession(NS_ERROR_UNEXPECTED);
|
||||
return false;
|
||||
}
|
||||
|
||||
return rv;
|
||||
rv = mOpenTimer->InitWithCallback(this, mOpenTimeout,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("WebSocketChannel::BeginOpen: cannot initialize open timer\n"));
|
||||
AbortSession(NS_ERROR_UNEXPECTED);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1578,9 +1825,6 @@ WebSocketChannel::StopSession(nsresult reason)
|
||||
mCallbacks = nsnull;
|
||||
}
|
||||
|
||||
if (mOpenRunning || mOpenBlocked)
|
||||
sWebSocketAdmissions->Cancel(this);
|
||||
|
||||
if (mCloseTimer) {
|
||||
mCloseTimer->Cancel();
|
||||
mCloseTimer = nsnull;
|
||||
@ -1591,6 +1835,11 @@ WebSocketChannel::StopSession(nsresult reason)
|
||||
mOpenTimer = nsnull;
|
||||
}
|
||||
|
||||
if (mReconnectDelayTimer) {
|
||||
mReconnectDelayTimer->Cancel();
|
||||
mReconnectDelayTimer = nsnull;
|
||||
}
|
||||
|
||||
if (mPingTimer) {
|
||||
mPingTimer->Cancel();
|
||||
mPingTimer = nsnull;
|
||||
@ -1657,8 +1906,7 @@ WebSocketChannel::StopSession(nsresult reason)
|
||||
|
||||
if (!mCalledOnStop) {
|
||||
mCalledOnStop = 1;
|
||||
if (mListener)
|
||||
NS_DispatchToMainThread(new CallOnStop(this, reason));
|
||||
NS_DispatchToMainThread(new CallOnStop(this, reason));
|
||||
}
|
||||
|
||||
return;
|
||||
@ -1893,6 +2141,10 @@ WebSocketChannel::ApplyForAdmission()
|
||||
rv = mURI->GetHost(hostName);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mAddress = hostName;
|
||||
rv = mURI->GetPort(&mPort);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (mPort == -1)
|
||||
mPort = (mEncrypted ? kDefaultWSSPort : kDefaultWSPort);
|
||||
|
||||
// expect the callback in ::OnLookupComplete
|
||||
LOG(("WebSocketChannel::ApplyForAdmission: checking for concurrent open\n"));
|
||||
@ -1913,7 +2165,12 @@ WebSocketChannel::StartWebsocketData()
|
||||
LOG(("WebSocketChannel::StartWebsocketData() %p", this));
|
||||
NS_ABORT_IF_FALSE(!mDataStarted, "StartWebsocketData twice");
|
||||
mDataStarted = 1;
|
||||
|
||||
|
||||
// We're now done CONNECTING, which means we can now open another,
|
||||
// perhaps parallel, connection to the same host if one
|
||||
// is pending
|
||||
sWebSocketAdmissions->OnConnected(this);
|
||||
|
||||
LOG(("WebSocketChannel::StartWebsocketData Notifying Listener %p\n",
|
||||
mListener.get()));
|
||||
|
||||
@ -1953,7 +2210,7 @@ WebSocketChannel::OnLookupComplete(nsICancelable *aRequest,
|
||||
LOG(("WebSocketChannel::OnLookupComplete: Failed GetNextAddr\n"));
|
||||
}
|
||||
|
||||
if (sWebSocketAdmissions->ConditionallyConnect(mAddress, this)) {
|
||||
if (sWebSocketAdmissions->ConditionallyConnect(this)) {
|
||||
LOG(("WebSocketChannel::OnLookupComplete: Proceeding with Open\n"));
|
||||
} else {
|
||||
LOG(("WebSocketChannel::OnLookupComplete: Deferring Open\n"));
|
||||
@ -2077,17 +2334,19 @@ WebSocketChannel::AsyncOnChannelRedirect(
|
||||
return rv;
|
||||
}
|
||||
|
||||
// We cannot just tell the callback OK right now due to the 1 connect at a
|
||||
// time policy. First we need to complete the old location and then start the
|
||||
// lookup chain for the new location - once that is complete and we have been
|
||||
// admitted, OnRedirectVerifyCallback(NS_OK) will be called out of BeginOpen()
|
||||
|
||||
sWebSocketAdmissions->Complete(this);
|
||||
mAddress.Truncate();
|
||||
// Redirected-to URI may need to be delayed by 1-connecting-per-host and
|
||||
// delay-after-fail algorithms. So hold off calling OnRedirectVerifyCallback
|
||||
// until BeginOpen, when we know it's OK to proceed with new channel.
|
||||
mRedirectCallback = callback;
|
||||
|
||||
mChannelWasOpened = 0;
|
||||
// Mark old channel as successfully connected so we'll clear any FailDelay
|
||||
// associated with the old URI. Note: no need to also call OnStopSession:
|
||||
// it's a no-op for successful, already-connected channels.
|
||||
sWebSocketAdmissions->OnConnected(this);
|
||||
|
||||
// ApplyForAdmission as if we were starting from fresh...
|
||||
mAddress.Truncate();
|
||||
mChannelWasOpened = 0;
|
||||
rv = ApplyForAdmission();
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("WebSocketChannel: Redirect failed due to DNS failure\n"));
|
||||
@ -2127,6 +2386,16 @@ WebSocketChannel::Notify(nsITimer *timer)
|
||||
return NS_OK;
|
||||
|
||||
AbortSession(NS_ERROR_NET_TIMEOUT);
|
||||
} else if (timer == mReconnectDelayTimer) {
|
||||
NS_ABORT_IF_FALSE(mConnecting == CONNECTING_DELAYED,
|
||||
"woke up from delay w/o being delayed?");
|
||||
|
||||
mReconnectDelayTimer = nsnull;
|
||||
LOG(("WebSocketChannel: connecting [this=%p] after reconnect delay", this));
|
||||
// - if BeginOpen fails, it calls AbortSession, which calls OnStopSession,
|
||||
// which will ensure any remaining queued connection(s) are scheduled
|
||||
mConnecting = CONNECTING_IN_PROGRESS;
|
||||
this->BeginOpen();
|
||||
} else if (timer == mPingTimer) {
|
||||
NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread,
|
||||
"not socket thread");
|
||||
@ -2351,12 +2620,6 @@ WebSocketChannel::Close(PRUint16 code, const nsACString & reason)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mTransport) {
|
||||
LOG(("WebSocketChannel::Close() without transport - aborting."));
|
||||
AbortSession(NS_ERROR_NOT_CONNECTED);
|
||||
return NS_ERROR_NOT_CONNECTED;
|
||||
}
|
||||
|
||||
// The API requires the UTF-8 string to be 123 or less bytes
|
||||
if (reason.Length() > 123)
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
@ -2365,6 +2628,20 @@ WebSocketChannel::Close(PRUint16 code, const nsACString & reason)
|
||||
mScriptCloseReason = reason;
|
||||
mScriptCloseCode = code;
|
||||
|
||||
if (!mTransport) {
|
||||
nsresult rv;
|
||||
if (code == CLOSE_GOING_AWAY) {
|
||||
// Not an error: for example, tab has closed or navigated away
|
||||
LOG(("WebSocketChannel::Close() GOING_AWAY without transport."));
|
||||
rv = NS_OK;
|
||||
} else {
|
||||
LOG(("WebSocketChannel::Close() without transport - error."));
|
||||
rv = NS_ERROR_NOT_CONNECTED;
|
||||
}
|
||||
StopSession(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return mSocketThread->Dispatch(
|
||||
new OutboundEnqueuer(this, new OutboundMessage(kMsgTypeFin, nsnull)),
|
||||
nsIEventTarget::DISPATCH_NORMAL);
|
||||
@ -2470,16 +2747,6 @@ WebSocketChannel::OnStartRequest(nsIRequest *aRequest,
|
||||
NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
|
||||
NS_ABORT_IF_FALSE(!mRecvdHttpOnStartRequest, "OTA duplicated");
|
||||
|
||||
// Generating the onStart event will take us out of the
|
||||
// CONNECTING state which means we can now open another,
|
||||
// perhaps parallel, connection to the same host if one
|
||||
// is pending
|
||||
|
||||
if (sWebSocketAdmissions->Complete(this))
|
||||
LOG(("WebSocketChannel::OnStartRequest: Starting Pending Open\n"));
|
||||
else
|
||||
LOG(("WebSocketChannel::OnStartRequest: No More Pending Opens\n"));
|
||||
|
||||
if (mOpenTimer) {
|
||||
mOpenTimer->Cancel();
|
||||
mOpenTimer = nsnull;
|
||||
|
@ -42,6 +42,14 @@ class CallOnStop;
|
||||
class CallOnServerClose;
|
||||
class CallAcknowledge;
|
||||
|
||||
// Used to enforce "1 connecting websocket per host" rule, and reconnect delays
|
||||
enum wsConnectingState {
|
||||
NOT_CONNECTING = 0, // Not yet (or no longer) trying to open connection
|
||||
CONNECTING_QUEUED, // Waiting for other ws to same host to finish opening
|
||||
CONNECTING_DELAYED, // Delayed by "reconnect after failure" algorithm
|
||||
CONNECTING_IN_PROGRESS // Started connection: waiting for result
|
||||
};
|
||||
|
||||
class WebSocketChannel : public BaseWebSocketChannel,
|
||||
public nsIHttpUpgradeListener,
|
||||
public nsIStreamListener,
|
||||
@ -101,6 +109,7 @@ protected:
|
||||
private:
|
||||
friend class OutboundEnqueuer;
|
||||
friend class nsWSAdmissionManager;
|
||||
friend class FailDelayManager;
|
||||
friend class CallOnMessageAvailable;
|
||||
friend class CallOnStop;
|
||||
friend class CallOnServerClose;
|
||||
@ -117,7 +126,7 @@ private:
|
||||
void GeneratePong(PRUint8 *payload, PRUint32 len);
|
||||
void GeneratePing();
|
||||
|
||||
nsresult BeginOpen();
|
||||
bool BeginOpen();
|
||||
nsresult HandleExtensions();
|
||||
nsresult SetupRequest();
|
||||
nsresult ApplyForAdmission();
|
||||
@ -149,7 +158,11 @@ private:
|
||||
nsCOMPtr<nsIRandomGenerator> mRandomGenerator;
|
||||
|
||||
nsCString mHashedSecret;
|
||||
|
||||
// Used as key for connection managment: Initially set to hostname from URI,
|
||||
// then to IP address (unless we're leaving DNS resolution to a proxy server)
|
||||
nsCString mAddress;
|
||||
PRInt32 mPort; // WS server port
|
||||
|
||||
nsCOMPtr<nsISocketTransport> mTransport;
|
||||
nsCOMPtr<nsIAsyncInputStream> mSocketIn;
|
||||
@ -160,6 +173,8 @@ private:
|
||||
|
||||
nsCOMPtr<nsITimer> mOpenTimer;
|
||||
PRUint32 mOpenTimeout; /* milliseconds */
|
||||
wsConnectingState mConnecting; /* 0 if not connecting */
|
||||
nsCOMPtr<nsITimer> mReconnectDelayTimer;
|
||||
|
||||
nsCOMPtr<nsITimer> mPingTimer;
|
||||
PRUint32 mPingTimeout; /* milliseconds */
|
||||
@ -183,8 +198,6 @@ private:
|
||||
PRUint32 mAutoFollowRedirects : 1;
|
||||
PRUint32 mReleaseOnTransmit : 1;
|
||||
PRUint32 mTCPClosed : 1;
|
||||
PRUint32 mOpenBlocked : 1;
|
||||
PRUint32 mOpenRunning : 1;
|
||||
PRUint32 mChannelWasOpened : 1;
|
||||
PRUint32 mDataStarted : 1;
|
||||
PRUint32 mIncrementedSessionCount : 1;
|
||||
|
46
netwerk/test/unit/head_cache.js
Normal file
46
netwerk/test/unit/head_cache.js
Normal file
@ -0,0 +1,46 @@
|
||||
var _CSvc;
|
||||
function get_cache_service() {
|
||||
if (_CSvc)
|
||||
return _CSvc;
|
||||
|
||||
return _CSvc = Components.classes["@mozilla.org/network/cache-service;1"]
|
||||
.getService(Components.interfaces.nsICacheService);
|
||||
}
|
||||
|
||||
function evict_cache_entries(where)
|
||||
{
|
||||
if (where == null)
|
||||
where = Components.interfaces.nsICache.STORE_ANYWHERE;
|
||||
|
||||
get_cache_service().evictEntries(where);
|
||||
}
|
||||
|
||||
function asyncOpenCacheEntry(key, sessionName, storagePolicy, access, callback)
|
||||
{
|
||||
function CacheListener() { }
|
||||
CacheListener.prototype = {
|
||||
QueryInterface: function (iid) {
|
||||
if (iid.equals(Components.interfaces.nsICacheListener) ||
|
||||
iid.equals(Components.interfaces.nsISupports))
|
||||
return this;
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
onCacheEntryAvailable: function (entry, access, status) {
|
||||
callback(status, entry);
|
||||
},
|
||||
|
||||
run: function () {
|
||||
var cache = get_cache_service();
|
||||
var session = cache.createSession(
|
||||
sessionName,
|
||||
storagePolicy,
|
||||
Components.interfaces.nsICache.STREAM_BASED);
|
||||
var cacheEntry = session.asyncOpenCacheEntry(key, access, this);
|
||||
}
|
||||
};
|
||||
|
||||
(new CacheListener()).run();
|
||||
}
|
||||
|
||||
|
86
netwerk/test/unit/test_304_responses.js
Normal file
86
netwerk/test/unit/test_304_responses.js
Normal file
@ -0,0 +1,86 @@
|
||||
"use strict";
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=761228
|
||||
|
||||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
const testFileName = "test_customConditionalRequest_304";
|
||||
const basePath = "/" + testFileName + "/";
|
||||
const baseURI = "http://localhost:4444" + basePath;
|
||||
const unexpected304 = "unexpected304";
|
||||
const existingCached304 = "existingCached304";
|
||||
|
||||
function make_uri(url) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newURI(url, null, null);
|
||||
}
|
||||
|
||||
function make_channel(url) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
var chan = ios.newChannel(url, null, null).QueryInterface(Ci.nsIHttpChannel);
|
||||
return chan;
|
||||
}
|
||||
|
||||
function clearCache() {
|
||||
var service = Components.classes["@mozilla.org/network/cache-service;1"]
|
||||
.getService(Ci.nsICacheService);
|
||||
service.evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||
}
|
||||
|
||||
function alwaysReturn304Handler(metadata, response) {
|
||||
response.setStatusLine(metadata.httpVersion, 304, "Not Modified");
|
||||
response.setHeader("Returned-From-Handler", "1");
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
evict_cache_entries();
|
||||
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler(basePath + unexpected304,
|
||||
alwaysReturn304Handler);
|
||||
httpServer.registerPathHandler(basePath + existingCached304,
|
||||
alwaysReturn304Handler);
|
||||
httpServer.start(4444);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function finish_test(request, buffer) {
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function consume304(request, buffer) {
|
||||
do_check_eq(request.responseStatus, 304);
|
||||
do_check_eq(request.getResponseHeader("Returned-From-Handler"), "1");
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
// Test that we return a 304 response to the caller when we are not expecting
|
||||
// a 304 response (i.e. when the server shouldn't have sent us one).
|
||||
add_test(function test_unexpected_304() {
|
||||
var chan = make_channel(baseURI + unexpected304);
|
||||
chan.asyncOpen(new ChannelListener(consume304, null), null);
|
||||
});
|
||||
|
||||
// Test that we can cope with a 304 response that was (erroneously) stored in
|
||||
// the cache.
|
||||
add_test(function test_304_stored_in_cache() {
|
||||
asyncOpenCacheEntry(
|
||||
baseURI + existingCached304, "HTTP",
|
||||
Ci.nsICache.STORE_ANYWHERE, Ci.nsICache.ACCESS_READ_WRITE,
|
||||
function (entryStatus, cacheEntry) {
|
||||
cacheEntry.setMetaDataElement("request-method", "GET");
|
||||
cacheEntry.setMetaDataElement("response-head",
|
||||
"HTTP/1.1 304 Not Modified\r\n" +
|
||||
"\r\n");
|
||||
cacheEntry.close();
|
||||
|
||||
var chan = make_channel(baseURI + existingCached304);
|
||||
|
||||
// make it a custom conditional request
|
||||
chan.QueryInterface(Components.interfaces.nsIHttpChannel);
|
||||
chan.setRequestHeader("If-None-Match", '"foo"', false);
|
||||
|
||||
chan.asyncOpen(new ChannelListener(consume304, null), null);
|
||||
});
|
||||
});
|
@ -75,12 +75,6 @@ var tests = [
|
||||
|
||||
];
|
||||
|
||||
function getCacheService()
|
||||
{
|
||||
return Components.classes["@mozilla.org/network/cache-service;1"].
|
||||
getService(Components.interfaces.nsICacheService);
|
||||
}
|
||||
|
||||
function logit(i, data, ctx) {
|
||||
dump("requested [" + tests[i].server + "] " +
|
||||
"got [" + data + "] " +
|
||||
@ -135,8 +129,8 @@ function run_test() {
|
||||
httpserver.start(4444);
|
||||
|
||||
// clear cache
|
||||
getCacheService().
|
||||
evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
triggerNextTest();
|
||||
do_test_pending();
|
||||
}
|
||||
|
@ -12,18 +12,15 @@ const kMemoryDevice = "memory";
|
||||
const kOfflineDevice = "offline";
|
||||
const kPrivate = "private";
|
||||
|
||||
const kCacheA = "cache-A";
|
||||
const kCacheA2 = "cache-A2";
|
||||
const kCacheB = "cache-B";
|
||||
const kCacheC = "cache-C";
|
||||
const kTestContent = "test content";
|
||||
|
||||
// the name for our cache session
|
||||
const kPrivateBrowsing = "PrivateBrowsing";
|
||||
|
||||
var _CSvc;
|
||||
function get_cache_service() {
|
||||
if (_CSvc)
|
||||
return _CSvc;
|
||||
|
||||
return _CSvc = Cc["@mozilla.org/network/cache-service;1"].
|
||||
getService(Ci.nsICacheService);
|
||||
}
|
||||
|
||||
function check_devices_available(devices) {
|
||||
var cs = get_cache_service();
|
||||
var found_devices = [];
|
||||
@ -77,32 +74,6 @@ function get_device_entry_count(device) {
|
||||
return entry_count;
|
||||
}
|
||||
|
||||
function store_in_cache(aKey, aContent, aWhere) {
|
||||
var storageFlag, streaming = true;
|
||||
if (aWhere == kDiskDevice)
|
||||
storageFlag = Ci.nsICache.STORE_ON_DISK;
|
||||
else if (aWhere == kOfflineDevice)
|
||||
storageFlag = Ci.nsICache.STORE_OFFLINE;
|
||||
else if (aWhere == kMemoryDevice || aWhere == kPrivate)
|
||||
storageFlag = Ci.nsICache.STORE_IN_MEMORY;
|
||||
|
||||
var cache = get_cache_service();
|
||||
var session = cache.createSession(kPrivateBrowsing, storageFlag, streaming);
|
||||
session.isPrivate = aWhere == kPrivate;
|
||||
var cacheEntry = session.openCacheEntry(aKey, Ci.nsICache.ACCESS_WRITE, true);
|
||||
|
||||
var oStream = cacheEntry.openOutputStream(0);
|
||||
|
||||
var written = oStream.write(aContent, aContent.length);
|
||||
if (written != aContent.length) {
|
||||
do_throw("oStream.write has not written all data!\n" +
|
||||
" Expected: " + aContent.length + "\n" +
|
||||
" Actual: " + written + "\n");
|
||||
}
|
||||
oStream.close();
|
||||
cacheEntry.close();
|
||||
}
|
||||
|
||||
function make_input_stream_scriptable(input) {
|
||||
var wrapper = Cc["@mozilla.org/scriptableinputstream;1"].
|
||||
createInstance(Ci.nsIScriptableInputStream);
|
||||
@ -110,85 +81,153 @@ function make_input_stream_scriptable(input) {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
function retrieve_from_cache(aKey, aWhere) {
|
||||
var storageFlag, streaming = true;
|
||||
if (aWhere == kDiskDevice)
|
||||
storageFlag = Ci.nsICache.STORE_ANYWHERE;
|
||||
else if (aWhere == kOfflineDevice)
|
||||
storageFlag = Ci.nsICache.STORE_OFFLINE;
|
||||
else if (aWhere == kMemoryDevice || aWhere == kPrivate)
|
||||
storageFlag = Ci.nsICache.STORE_ANYWHERE;
|
||||
|
||||
var cache = get_cache_service();
|
||||
var session = cache.createSession(kPrivateBrowsing, storageFlag, streaming);
|
||||
session.isPrivate = aWhere == kPrivate;
|
||||
try {
|
||||
var cacheEntry = session.openCacheEntry(aKey, Ci.nsICache.ACCESS_READ, true);
|
||||
} catch (e) {
|
||||
if (e.result == Cr.NS_ERROR_CACHE_KEY_NOT_FOUND ||
|
||||
e.result == Cr.NS_ERROR_FAILURE)
|
||||
// a key not found error is expected here, so we will simply return null
|
||||
// to let the caller know that no data was retrieved. We also expect
|
||||
// a generic failure error in case of the offline cache.
|
||||
return null;
|
||||
const entries = [
|
||||
// key content device should exist after leaving PB
|
||||
[kCacheA, kTestContent, kMemoryDevice, true],
|
||||
[kCacheA2, kTestContent, kPrivate, false],
|
||||
[kCacheB, kTestContent, kDiskDevice, true],
|
||||
[kCacheC, kTestContent, kOfflineDevice, true]
|
||||
]
|
||||
|
||||
// Throw the textual error description.
|
||||
do_throw(e);
|
||||
function get_storage_policy(device)
|
||||
{
|
||||
switch (device) {
|
||||
case kDiskDevice:
|
||||
return Ci.nsICache.STORE_ON_DISK;
|
||||
case kOfflineDevice:
|
||||
return Ci.nsICache.STORE_OFFLINE;
|
||||
case kMemoryDevice:
|
||||
case kPrivate:
|
||||
return Ci.nsICache.STORE_IN_MEMORY;
|
||||
}
|
||||
|
||||
var iStream = make_input_stream_scriptable(cacheEntry.openInputStream(0));
|
||||
|
||||
var read = iStream.read(iStream.available());
|
||||
iStream.close();
|
||||
cacheEntry.close();
|
||||
|
||||
return read;
|
||||
do_throw("unknown device");
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
const kCacheA = "cache-A",
|
||||
kCacheA2 = "cache-A2",
|
||||
kCacheB = "cache-B",
|
||||
kCacheC = "cache-C",
|
||||
kTestContent = "test content";
|
||||
var store_idx;
|
||||
var store_cb = null;
|
||||
function store_entries(cb)
|
||||
{
|
||||
if (cb) {
|
||||
store_cb = cb;
|
||||
store_idx = 0;
|
||||
}
|
||||
|
||||
if (store_idx == entries.length) {
|
||||
do_execute_soon(store_cb);
|
||||
return;
|
||||
}
|
||||
|
||||
var cache = get_cache_service();
|
||||
var session = cache.createSession(kPrivateBrowsing,
|
||||
get_storage_policy(entries[store_idx][2]),
|
||||
Ci.nsICache.STREAM_BASED);
|
||||
if (entries[store_idx][2] == kPrivate) {
|
||||
session.isPrivate = true;
|
||||
}
|
||||
|
||||
var cacheEntry = session.asyncOpenCacheEntry(entries[store_idx][0],
|
||||
Ci.nsICache.ACCESS_WRITE,
|
||||
store_data);
|
||||
}
|
||||
|
||||
var store_data = {
|
||||
onCacheEntryAvailable: function oCEA(entry, access, status) {
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
var os = entry.openOutputStream(0);
|
||||
|
||||
var written = os.write(entries[store_idx][1], entries[store_idx][1].length);
|
||||
if (written != entries[store_idx][1].length) {
|
||||
do_throw("os.write has not written all data!\n" +
|
||||
" Expected: " + entries[store_idx][1].length + "\n" +
|
||||
" Actual: " + written + "\n");
|
||||
}
|
||||
os.close();
|
||||
entry.close();
|
||||
store_idx++;
|
||||
do_execute_soon(store_entries);
|
||||
}
|
||||
};
|
||||
|
||||
var check_idx;
|
||||
var check_cb = null;
|
||||
var check_pb_exited;
|
||||
function check_entries(cb, pbExited)
|
||||
{
|
||||
if (cb) {
|
||||
check_cb = cb;
|
||||
check_idx = 0;
|
||||
check_pb_exited = pbExited;
|
||||
}
|
||||
|
||||
if (check_idx == entries.length) {
|
||||
do_execute_soon(check_cb);
|
||||
return;
|
||||
}
|
||||
|
||||
var cache = get_cache_service();
|
||||
var session = cache.createSession(kPrivateBrowsing,
|
||||
get_storage_policy(entries[check_idx][2]),
|
||||
Ci.nsICache.STREAM_BASED);
|
||||
if (entries[check_idx][2] == kPrivate) {
|
||||
session.isPrivate = true;
|
||||
}
|
||||
|
||||
var cacheEntry = session.asyncOpenCacheEntry(entries[check_idx][0],
|
||||
Ci.nsICache.ACCESS_READ,
|
||||
check_data);
|
||||
}
|
||||
|
||||
var check_data = {
|
||||
onCacheEntryAvailable: function oCEA(entry, access, status) {
|
||||
if (!check_pb_exited || entries[check_idx][3]) {
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
var is = make_input_stream_scriptable(entry.openInputStream(0));
|
||||
var read = is.read(is.available());
|
||||
is.close();
|
||||
entry.close();
|
||||
do_check_eq(read, entries[check_idx][1]);
|
||||
} else {
|
||||
do_check_eq(status, Cr.NS_ERROR_CACHE_KEY_NOT_FOUND);
|
||||
}
|
||||
|
||||
check_idx++;
|
||||
do_execute_soon(check_entries);
|
||||
}
|
||||
};
|
||||
|
||||
function run_test() {
|
||||
// Simulate a profile dir for xpcshell
|
||||
do_get_profile();
|
||||
|
||||
var cs = get_cache_service();
|
||||
|
||||
// Start off with an empty cache
|
||||
cs.evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
// Store cache-A, cache-A2, cache-B and cache-C
|
||||
store_in_cache(kCacheA, kTestContent, kMemoryDevice);
|
||||
store_in_cache(kCacheA2, kTestContent, kPrivate);
|
||||
store_in_cache(kCacheB, kTestContent, kDiskDevice);
|
||||
store_in_cache(kCacheC, kTestContent, kOfflineDevice);
|
||||
store_entries(run_test2);
|
||||
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function run_test2() {
|
||||
// Make sure all three cache devices are available initially
|
||||
check_devices_available([kMemoryDevice, kDiskDevice, kOfflineDevice]);
|
||||
|
||||
// Check if cache-A, cache-A2, cache-B and cache-C are avilable
|
||||
do_check_eq(retrieve_from_cache(kCacheA, kMemoryDevice), kTestContent);
|
||||
do_check_eq(retrieve_from_cache(kCacheA2, kPrivate), kTestContent);
|
||||
do_check_eq(retrieve_from_cache(kCacheB, kDiskDevice), kTestContent);
|
||||
do_check_eq(retrieve_from_cache(kCacheC, kOfflineDevice), kTestContent);
|
||||
// Check if cache-A, cache-A2, cache-B and cache-C are available
|
||||
check_entries(run_test3, false);
|
||||
}
|
||||
|
||||
function run_test3() {
|
||||
// Simulate all private browsing instances being closed
|
||||
var obsvc = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
obsvc.notifyObservers(null, "last-pb-context-exited", null);
|
||||
|
||||
|
||||
// Make sure all three cache devices are still available
|
||||
check_devices_available([kMemoryDevice, kDiskDevice, kOfflineDevice]);
|
||||
|
||||
// Make sure the memory device is not empty
|
||||
do_check_eq(get_device_entry_count(kMemoryDevice), 1);
|
||||
|
||||
// Check if cache-A is gone, and cache-B and cache-C are still avilable
|
||||
do_check_eq(retrieve_from_cache(kCacheA, kMemoryDevice), kTestContent);
|
||||
do_check_eq(retrieve_from_cache(kCacheA2, kPrivate), null);
|
||||
do_check_eq(retrieve_from_cache(kCacheB, kDiskDevice), kTestContent);
|
||||
do_check_eq(retrieve_from_cache(kCacheC, kOfflineDevice), kTestContent);
|
||||
// Check if cache-A is gone, and cache-B and cache-C are still available
|
||||
check_entries(do_test_finished, true);
|
||||
}
|
||||
|
@ -1,116 +1,103 @@
|
||||
function getURLContent(aURL) {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
const URL = "ftp://localhost/bug365133/";
|
||||
|
||||
var uri = ios.newURI(aURL, null, null);
|
||||
var chan = ios.newChannelFromURI(uri);
|
||||
var inp = chan.open();
|
||||
var scinp = Components.classes["@mozilla.org/scriptableinputstream;1"].
|
||||
createInstance(Components.interfaces.nsIScriptableInputStream);
|
||||
scinp.init(inp);
|
||||
var result = "";
|
||||
var avail = scinp.available();
|
||||
while (avail) {
|
||||
result += scinp.read(avail);
|
||||
avail = scinp.available();
|
||||
}
|
||||
return result;
|
||||
const tests = [
|
||||
[ /* Unix style listing, space at the end of filename */
|
||||
"drwxrwxr-x 2 500 500 4096 Jan 01 2000 a \r\n"
|
||||
,
|
||||
"300: " + URL + "\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"a%20\" 0 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 DIRECTORY \n"
|
||||
],
|
||||
[ /* Unix style listing, space at the end of link name */
|
||||
"lrwxrwxrwx 1 500 500 2 Jan 01 2000 l -> a \r\n"
|
||||
,
|
||||
"300: " + URL + "\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"l%20\" 2 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 SYMBOLIC-LINK \n"
|
||||
],
|
||||
[ /* Unix style listing, regular file with " -> " in name */
|
||||
"-rw-rw-r-- 1 500 500 0 Jan 01 2000 arrow -> in name \r\n"
|
||||
,
|
||||
"300: " + URL + "\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"arrow%20-%3E%20in%20name%20\" 0 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n"
|
||||
],
|
||||
[ /* Unix style listing, tab at the end of filename */
|
||||
"drwxrwxrwx 2 500 500 4096 Jan 01 2000 t \r\n"
|
||||
,
|
||||
"300: " + URL + "\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"t%09\" 0 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 DIRECTORY \n"
|
||||
],
|
||||
[ /* Unix style listing, multiple " -> " in filename */
|
||||
"lrwxrwxrwx 1 500 500 26 Jan 01 2000 symlink with arrow -> in name -> file with arrow -> in name\r\n"
|
||||
,
|
||||
"300: " + URL + "\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"symlink%20with%20arrow%20-%3E%20in%20name\" 26 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 SYMBOLIC-LINK \n"
|
||||
],
|
||||
[ /* Unix style listing, multiple " -> " in filename, incorrect filesize */
|
||||
"lrwxrwxrwx 1 500 500 0 Jan 01 2000 symlink with arrow -> in name -> file with arrow -> in name\r\n"
|
||||
,
|
||||
"300: " + URL + "\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"symlink%20with%20arrow%20-%3E%20in%20name%20-%3E%20file%20with%20arrow\" 0 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 SYMBOLIC-LINK \n"
|
||||
],
|
||||
[ /* DOS style listing, space at the end of filename, year 1999 */
|
||||
"01-01-99 01:00AM 1024 file \r\n"
|
||||
,
|
||||
"300: " + URL + "\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"file%20\" 1024 Sun%2C%2001%20Jan%201999%2001%3A00%3A00 FILE \n"
|
||||
],
|
||||
[ /* DOS style listing, tab at the end of filename, year 2000 */
|
||||
"01-01-00 01:00AM 1024 file \r\n"
|
||||
,
|
||||
"300: " + URL + "\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"file%09\" 1024 Sun%2C%2001%20Jan%202000%2001%3A00%3A00 FILE \n"
|
||||
]
|
||||
]
|
||||
|
||||
function checkData(request, data, ctx) {
|
||||
do_check_eq(tests[0][1], data);
|
||||
tests.shift();
|
||||
next_test();
|
||||
}
|
||||
|
||||
function storeCache(aURL, aContent) {
|
||||
const nsICache = Components.interfaces.nsICache;
|
||||
function storeData(status, entry) {
|
||||
do_check_eq(status, Components.results.NS_OK);
|
||||
entry.setMetaDataElement("servertype", "0");
|
||||
var os = entry.openOutputStream(0);
|
||||
|
||||
var cache = Components.classes["@mozilla.org/network/cache-service;1"].
|
||||
getService(Components.interfaces.nsICacheService);
|
||||
|
||||
var session = cache.createSession("FTP", nsICache.STORE_ANYWHERE, nsICache.STREAM_BASED);
|
||||
|
||||
var cacheEntry = session.openCacheEntry(aURL, nsICache.ACCESS_READ_WRITE, false);
|
||||
|
||||
cacheEntry.setMetaDataElement("servertype", "0");
|
||||
var oStream = cacheEntry.openOutputStream(0);
|
||||
|
||||
var written = oStream.write(aContent, aContent.length);
|
||||
if (written != aContent.length) {
|
||||
do_throw("oStream.write have not written all data!\n" +
|
||||
var written = os.write(tests[0][0], tests[0][0].length);
|
||||
if (written != tests[0][0].length) {
|
||||
do_throw("os.write has not written all data!\n" +
|
||||
" Expected: " + written + "\n" +
|
||||
" Actual: " + aContent.length + "\n");
|
||||
" Actual: " + tests[0][0].length + "\n");
|
||||
}
|
||||
os.close();
|
||||
entry.close();
|
||||
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
var channel = ios.newChannel(URL, "", null);
|
||||
channel.asyncOpen(new ChannelListener(checkData, null, CL_ALLOW_UNKNOWN_CL), null);
|
||||
}
|
||||
|
||||
function next_test() {
|
||||
if (tests.length == 0)
|
||||
do_test_finished();
|
||||
else {
|
||||
asyncOpenCacheEntry(URL,
|
||||
"FTP",
|
||||
Components.interfaces.nsICache.STORE_ANYWHERE,
|
||||
Components.interfaces.nsICache.ACCESS_READ_WRITE,
|
||||
storeData);
|
||||
}
|
||||
oStream.close();
|
||||
cacheEntry.close();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
/* Unix style listing, space at the end of filename */
|
||||
var rawData = "drwxrwxr-x 2 500 500 4096 Jan 01 2000 a \r\n";
|
||||
storeCache("ftp://localhost/bug365133/", rawData);
|
||||
var parsedData = getURLContent("ftp://localhost/bug365133/");
|
||||
do_check_eq(parsedData,
|
||||
"300: ftp://localhost/bug365133/\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"a%20\" 0 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 DIRECTORY \n");
|
||||
|
||||
/* Unix style listing, space at the end of link name */
|
||||
rawData = "lrwxrwxrwx 1 500 500 2 Jan 01 2000 l -> a \r\n";
|
||||
storeCache("ftp://localhost/bug365133/", rawData);
|
||||
parsedData = getURLContent("ftp://localhost/bug365133/");
|
||||
do_check_eq(parsedData,
|
||||
"300: ftp://localhost/bug365133/\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"l%20\" 2 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 SYMBOLIC-LINK \n");
|
||||
|
||||
/* Unix style listing, regular file with " -> " in name */
|
||||
rawData = "-rw-rw-r-- 1 500 500 0 Jan 01 2000 arrow -> in name \r\n";
|
||||
storeCache("ftp://localhost/bug365133/", rawData);
|
||||
parsedData = getURLContent("ftp://localhost/bug365133/");
|
||||
do_check_eq(parsedData,
|
||||
"300: ftp://localhost/bug365133/\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"arrow%20-%3E%20in%20name%20\" 0 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 FILE \n");
|
||||
|
||||
/* Unix style listing, tab at the end of filename */
|
||||
rawData = "drwxrwxrwx 2 500 500 4096 Jan 01 2000 t \r\n";
|
||||
storeCache("ftp://localhost/bug365133/", rawData);
|
||||
parsedData = getURLContent("ftp://localhost/bug365133/");
|
||||
do_check_eq(parsedData,
|
||||
"300: ftp://localhost/bug365133/\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"t%09\" 0 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 DIRECTORY \n");
|
||||
|
||||
/* Unix style listing, multiple " -> " in filename */
|
||||
rawData = "lrwxrwxrwx 1 500 500 26 Jan 01 2000 symlink with arrow -> in name -> file with arrow -> in name\r\n";
|
||||
storeCache("ftp://localhost/bug365133/", rawData);
|
||||
parsedData = getURLContent("ftp://localhost/bug365133/");
|
||||
do_check_eq(parsedData,
|
||||
"300: ftp://localhost/bug365133/\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"symlink%20with%20arrow%20-%3E%20in%20name\" 26 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 SYMBOLIC-LINK \n");
|
||||
|
||||
/* Unix style listing, multiple " -> " in filename, incorrect filesize */
|
||||
rawData = "lrwxrwxrwx 1 500 500 0 Jan 01 2000 symlink with arrow -> in name -> file with arrow -> in name\r\n";
|
||||
storeCache("ftp://localhost/bug365133/", rawData);
|
||||
parsedData = getURLContent("ftp://localhost/bug365133/");
|
||||
do_check_eq(parsedData,
|
||||
"300: ftp://localhost/bug365133/\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"symlink%20with%20arrow%20-%3E%20in%20name%20-%3E%20file%20with%20arrow\" 0 Sun%2C%2001%20Jan%202000%2000%3A00%3A00 SYMBOLIC-LINK \n");
|
||||
|
||||
/* DOS style listing, space at the end of filename, year 1999 */
|
||||
rawData = "01-01-99 01:00AM 1024 file \r\n";
|
||||
storeCache("ftp://localhost/bug365133/", rawData);
|
||||
parsedData = getURLContent("ftp://localhost/bug365133/");
|
||||
do_check_eq(parsedData,
|
||||
"300: ftp://localhost/bug365133/\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"file%20\" 1024 Sun%2C%2001%20Jan%201999%2001%3A00%3A00 FILE \n");
|
||||
|
||||
/* DOS style listing, tab at the end of filename, year 2000 */
|
||||
rawData = "01-01-00 01:00AM 1024 file \r\n";
|
||||
storeCache("ftp://localhost/bug365133/", rawData);
|
||||
parsedData = getURLContent("ftp://localhost/bug365133/");
|
||||
do_check_eq(parsedData,
|
||||
"300: ftp://localhost/bug365133/\n" +
|
||||
"200: filename content-length last-modified file-type\n" +
|
||||
"201: \"file%09\" 1024 Sun%2C%2001%20Jan%202000%2001%3A00%3A00 FILE \n");
|
||||
|
||||
do_execute_soon(next_test);
|
||||
do_test_pending();
|
||||
}
|
||||
|
@ -32,11 +32,6 @@ var tests = [
|
||||
|
||||
];
|
||||
|
||||
function getCacheService() {
|
||||
return Components.classes["@mozilla.org/network/cache-service;1"]
|
||||
.getService(Components.interfaces.nsICacheService);
|
||||
}
|
||||
|
||||
function setupChannel(suffix, value, cookie) {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
@ -72,8 +67,7 @@ function run_test() {
|
||||
httpserver.start(4444);
|
||||
|
||||
// Clear cache and trigger the first test
|
||||
getCacheService().evictEntries(
|
||||
Components.interfaces.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
triggerNextTest();
|
||||
|
||||
do_test_pending();
|
||||
|
@ -46,12 +46,6 @@ var tests = [
|
||||
{url: "/freshness", server: "99", expected: "0"}, // cached
|
||||
];
|
||||
|
||||
function getCacheService()
|
||||
{
|
||||
return Components.classes["@mozilla.org/network/cache-service;1"].
|
||||
getService(Components.interfaces.nsICacheService);
|
||||
}
|
||||
|
||||
function logit(i, data) {
|
||||
dump(tests[i].url + "\t requested [" + tests[i].server + "]" +
|
||||
" got [" + data + "] expected [" + tests[i].expected + "]");
|
||||
@ -92,8 +86,7 @@ function run_test() {
|
||||
httpserver.start(4444);
|
||||
|
||||
// clear cache
|
||||
getCacheService().
|
||||
evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
triggerNextTest();
|
||||
|
||||
do_test_pending();
|
||||
|
@ -83,17 +83,12 @@ function makeChan(url) {
|
||||
return chan;
|
||||
}
|
||||
|
||||
function storeCache(aURL, aResponseHeads, aContent) {
|
||||
var cache = Cc["@mozilla.org/network/cache-service;1"].
|
||||
getService(Ci.nsICacheService);
|
||||
function storeCache(aCacheEntry, aResponseHeads, aContent) {
|
||||
aCacheEntry.setMetaDataElement("request-method", "GET");
|
||||
aCacheEntry.setMetaDataElement("response-head", aResponseHeads);
|
||||
aCacheEntry.setMetaDataElement("charset", "ISO-8859-1");
|
||||
|
||||
var session = cache.createSession("HTTP", Ci.nsICache.STORE_ANYWHERE, Ci.nsICache.STREAM_BASED);
|
||||
var cacheEntry = session.openCacheEntry(aURL, Ci.nsICache.ACCESS_READ_WRITE, false);
|
||||
cacheEntry.setMetaDataElement("request-method", "GET");
|
||||
cacheEntry.setMetaDataElement("response-head", aResponseHeads);
|
||||
cacheEntry.setMetaDataElement("charset", "ISO-8859-1");
|
||||
|
||||
var oStream = cacheEntry.openOutputStream(0);
|
||||
var oStream = aCacheEntry.openOutputStream(0);
|
||||
var written = oStream.write(aContent, aContent.length);
|
||||
if (written != aContent.length) {
|
||||
do_throw("oStream.write has not written all data!\n" +
|
||||
@ -101,7 +96,7 @@ function storeCache(aURL, aResponseHeads, aContent) {
|
||||
" Actual: " + aContent.length + "\n");
|
||||
}
|
||||
oStream.close();
|
||||
cacheEntry.close();
|
||||
aCacheEntry.close();
|
||||
}
|
||||
|
||||
function test_nocache() {
|
||||
@ -112,7 +107,16 @@ function test_nocache() {
|
||||
}
|
||||
|
||||
function test_partial() {
|
||||
storeCache("http://localhost:4444/bug482601/partial",
|
||||
asyncOpenCacheEntry("http://localhost:4444/bug482601/partial",
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ANYWHERE,
|
||||
Ci.nsICache.ACCESS_READ_WRITE,
|
||||
test_partial2);
|
||||
}
|
||||
|
||||
function test_partial2(status, entry) {
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
storeCache(entry,
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Date: Thu, 1 Jan 2009 00:00:00 GMT\r\n" +
|
||||
"Server: httpd.js\r\n" +
|
||||
@ -129,7 +133,16 @@ function test_partial() {
|
||||
}
|
||||
|
||||
function test_cached() {
|
||||
storeCache("http://localhost:4444/bug482601/cached",
|
||||
asyncOpenCacheEntry("http://localhost:4444/bug482601/cached",
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ANYWHERE,
|
||||
Ci.nsICache.ACCESS_READ_WRITE,
|
||||
test_cached2);
|
||||
}
|
||||
|
||||
function test_cached2(status, entry) {
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
storeCache(entry,
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Date: Thu, 1 Jan 2009 00:00:00 GMT\r\n" +
|
||||
"Server: httpd.js\r\n" +
|
||||
@ -147,7 +160,16 @@ function test_cached() {
|
||||
}
|
||||
|
||||
function test_only_from_cache() {
|
||||
storeCache("http://localhost:4444/bug482601/only_from_cache",
|
||||
asyncOpenCacheEntry("http://localhost:4444/bug482601/only_from_cache",
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ANYWHERE,
|
||||
Ci.nsICache.ACCESS_READ_WRITE,
|
||||
test_only_from_cache2);
|
||||
}
|
||||
|
||||
function test_only_from_cache2(status, entry) {
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
storeCache(entry,
|
||||
"HTTP/1.1 200 OK\r\n" +
|
||||
"Date: Thu, 1 Jan 2009 00:00:00 GMT\r\n" +
|
||||
"Server: httpd.js\r\n" +
|
||||
|
@ -1,45 +1,3 @@
|
||||
function getURLContent(aURL) {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
|
||||
var uri = ios.newURI(aURL, null, null);
|
||||
var chan = ios.newChannelFromURI(uri);
|
||||
var inp = chan.open();
|
||||
var scinp = Components.classes["@mozilla.org/scriptableinputstream;1"].
|
||||
createInstance(Components.interfaces.nsIScriptableInputStream);
|
||||
scinp.init(inp);
|
||||
var result = "";
|
||||
var avail = scinp.available();
|
||||
while (avail) {
|
||||
result += scinp.read(avail);
|
||||
avail = scinp.available();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function storeCache(aURL, aContent) {
|
||||
const nsICache = Components.interfaces.nsICache;
|
||||
|
||||
var cache = Components.classes["@mozilla.org/network/cache-service;1"].
|
||||
getService(Components.interfaces.nsICacheService);
|
||||
|
||||
var session = cache.createSession("FTP", nsICache.STORE_ANYWHERE, nsICache.STREAM_BASED);
|
||||
|
||||
var cacheEntry = session.openCacheEntry(aURL, nsICache.ACCESS_READ_WRITE, false);
|
||||
|
||||
cacheEntry.setMetaDataElement("servertype", "0");
|
||||
var oStream = cacheEntry.openOutputStream(0);
|
||||
|
||||
var written = oStream.write(aContent, aContent.length);
|
||||
if (written != aContent.length) {
|
||||
do_throw("oStream.write has not written all data!\n" +
|
||||
" Expected: " + written + "\n" +
|
||||
" Actual: " + aContent.length + "\n");
|
||||
}
|
||||
oStream.close();
|
||||
cacheEntry.close();
|
||||
}
|
||||
|
||||
const URL = "ftp://localhost/bug464884/";
|
||||
|
||||
const tests = [
|
||||
@ -105,10 +63,45 @@ const tests = [
|
||||
"201: \"file2\" 95077 Sun%2C%2001%20Jan%202000%2001%3A00%3A00 FILE \n"]
|
||||
]
|
||||
|
||||
function run_test() {
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
storeCache(URL, tests[i][0]);
|
||||
var parsedData = getURLContent(URL);
|
||||
do_check_eq(parsedData, tests[i][1]);
|
||||
function checkData(request, data, ctx) {
|
||||
do_check_eq(tests[0][1], data);
|
||||
tests.shift();
|
||||
next_test();
|
||||
}
|
||||
|
||||
function storeData(status, entry) {
|
||||
do_check_eq(status, Components.results.NS_OK);
|
||||
entry.setMetaDataElement("servertype", "0");
|
||||
var os = entry.openOutputStream(0);
|
||||
|
||||
var written = os.write(tests[0][0], tests[0][0].length);
|
||||
if (written != tests[0][0].length) {
|
||||
do_throw("os.write has not written all data!\n" +
|
||||
" Expected: " + written + "\n" +
|
||||
" Actual: " + tests[0][0].length + "\n");
|
||||
}
|
||||
os.close();
|
||||
entry.close();
|
||||
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
var channel = ios.newChannel(URL, "", null);
|
||||
channel.asyncOpen(new ChannelListener(checkData, null, CL_ALLOW_UNKNOWN_CL), null);
|
||||
}
|
||||
|
||||
function next_test() {
|
||||
if (tests.length == 0)
|
||||
do_test_finished();
|
||||
else {
|
||||
asyncOpenCacheEntry(URL,
|
||||
"FTP",
|
||||
Components.interfaces.nsICache.STORE_ANYWHERE,
|
||||
Components.interfaces.nsICache.ACCESS_READ_WRITE,
|
||||
storeData);
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
do_execute_soon(next_test);
|
||||
do_test_pending();
|
||||
}
|
||||
|
@ -33,12 +33,6 @@ var tests = [
|
||||
|
||||
];
|
||||
|
||||
function getCacheService()
|
||||
{
|
||||
return Components.classes["@mozilla.org/network/cache-service;1"].
|
||||
getService(Components.interfaces.nsICacheService);
|
||||
}
|
||||
|
||||
function logit(i, data) {
|
||||
dump(tests[i].url + "\t requested [" + tests[i].server + "]" +
|
||||
" got [" + data + "] expected [" + tests[i].expected + "]");
|
||||
@ -83,8 +77,8 @@ function run_test() {
|
||||
httpserver.start(4444);
|
||||
|
||||
// clear cache
|
||||
getCacheService().
|
||||
evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
triggerNextTest();
|
||||
|
||||
do_test_pending();
|
||||
|
@ -7,11 +7,6 @@ var tests = [
|
||||
{ url : "/bug510359", server : "1", expected : "1"},
|
||||
];
|
||||
|
||||
function getCacheService() {
|
||||
return Components.classes["@mozilla.org/network/cache-service;1"]
|
||||
.getService(Components.interfaces.nsICacheService);
|
||||
}
|
||||
|
||||
function setupChannel(suffix, value) {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
@ -44,8 +39,8 @@ function run_test() {
|
||||
httpserver.start(4444);
|
||||
|
||||
// clear cache
|
||||
getCacheService().evictEntries(
|
||||
Components.interfaces.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
triggerNextTest();
|
||||
|
||||
do_test_pending();
|
||||
|
@ -1,45 +1,3 @@
|
||||
function getURLContent(aURL) {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
|
||||
var uri = ios.newURI(aURL, null, null);
|
||||
var chan = ios.newChannelFromURI(uri);
|
||||
var inp = chan.open();
|
||||
var scinp = Components.classes["@mozilla.org/scriptableinputstream;1"].
|
||||
createInstance(Components.interfaces.nsIScriptableInputStream);
|
||||
scinp.init(inp);
|
||||
var result = "";
|
||||
var avail = scinp.available();
|
||||
while (avail) {
|
||||
result += scinp.read(avail);
|
||||
avail = scinp.available();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function storeCache(aURL, aContent) {
|
||||
const nsICache = Components.interfaces.nsICache;
|
||||
|
||||
var cache = Components.classes["@mozilla.org/network/cache-service;1"].
|
||||
getService(Components.interfaces.nsICacheService);
|
||||
|
||||
var session = cache.createSession("FTP", nsICache.STORE_ANYWHERE, nsICache.STREAM_BASED);
|
||||
|
||||
var cacheEntry = session.openCacheEntry(aURL, nsICache.ACCESS_READ_WRITE, false);
|
||||
|
||||
cacheEntry.setMetaDataElement("servertype", "0");
|
||||
var oStream = cacheEntry.openOutputStream(0);
|
||||
|
||||
var written = oStream.write(aContent, aContent.length);
|
||||
if (written != aContent.length) {
|
||||
do_throw("oStream.write has not written all data!\n" +
|
||||
" Expected: " + written + "\n" +
|
||||
" Actual: " + aContent.length + "\n");
|
||||
}
|
||||
oStream.close();
|
||||
cacheEntry.close();
|
||||
}
|
||||
|
||||
const URL = "ftp://localhost/bug515583/";
|
||||
|
||||
const tests = [
|
||||
@ -63,10 +21,45 @@ const tests = [
|
||||
"200: filename content-length last-modified file-type\n"]
|
||||
]
|
||||
|
||||
function run_test() {
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
storeCache(URL, tests[i][0]);
|
||||
var parsedData = getURLContent(URL);
|
||||
do_check_eq(parsedData, tests[i][1]);
|
||||
function checkData(request, data, ctx) {
|
||||
do_check_eq(tests[0][1], data);
|
||||
tests.shift();
|
||||
next_test();
|
||||
}
|
||||
|
||||
function storeData(status, entry) {
|
||||
do_check_eq(status, Components.results.NS_OK);
|
||||
entry.setMetaDataElement("servertype", "0");
|
||||
var os = entry.openOutputStream(0);
|
||||
|
||||
var written = os.write(tests[0][0], tests[0][0].length);
|
||||
if (written != tests[0][0].length) {
|
||||
do_throw("os.write has not written all data!\n" +
|
||||
" Expected: " + written + "\n" +
|
||||
" Actual: " + tests[0][0].length + "\n");
|
||||
}
|
||||
os.close();
|
||||
entry.close();
|
||||
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
var channel = ios.newChannel(URL, "", null);
|
||||
channel.asyncOpen(new ChannelListener(checkData, null, CL_ALLOW_UNKNOWN_CL), null);
|
||||
}
|
||||
|
||||
function next_test() {
|
||||
if (tests.length == 0)
|
||||
do_test_finished();
|
||||
else {
|
||||
asyncOpenCacheEntry(URL,
|
||||
"FTP",
|
||||
Components.interfaces.nsICache.STORE_ANYWHERE,
|
||||
Components.interfaces.nsICache.ACCESS_READ_WRITE,
|
||||
storeData);
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
do_execute_soon(next_test);
|
||||
do_test_pending();
|
||||
}
|
||||
|
@ -2,14 +2,18 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
function run_test() {
|
||||
var cs = Components.classes["@mozilla.org/network/cache-service;1"].
|
||||
getService(Components.interfaces.nsICacheService);
|
||||
var nsICache = Components.interfaces.nsICache;
|
||||
var session = cs.createSession("client",
|
||||
nsICache.STORE_ANYWHERE,
|
||||
true);
|
||||
var entry = session.openCacheEntry("key", nsICache.STORE_ON_DISK, true);
|
||||
function continue_test(status, entry) {
|
||||
do_check_eq(status, Components.results.NS_OK);
|
||||
entry.deviceID;
|
||||
// if the above line does not crash, the test was successful
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
asyncOpenCacheEntry("key",
|
||||
"client",
|
||||
Components.interfaces.nsICache.STORE_ANYWHERE,
|
||||
Components.interfaces.nsICache.ACCESS_WRITE,
|
||||
continue_test);
|
||||
do_test_pending();
|
||||
}
|
||||
|
@ -1,45 +1,3 @@
|
||||
function getURLContent(aURL) {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
|
||||
var uri = ios.newURI(aURL, null, null);
|
||||
var chan = ios.newChannelFromURI(uri);
|
||||
var inp = chan.open();
|
||||
var scinp = Components.classes["@mozilla.org/scriptableinputstream;1"].
|
||||
createInstance(Components.interfaces.nsIScriptableInputStream);
|
||||
scinp.init(inp);
|
||||
var result = "";
|
||||
var avail = scinp.available();
|
||||
while (avail) {
|
||||
result += scinp.read(avail);
|
||||
avail = scinp.available();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function storeCache(aURL, aContent) {
|
||||
const nsICache = Components.interfaces.nsICache;
|
||||
|
||||
var cache = Components.classes["@mozilla.org/network/cache-service;1"].
|
||||
getService(Components.interfaces.nsICacheService);
|
||||
|
||||
var session = cache.createSession("FTP", nsICache.STORE_ANYWHERE, nsICache.STREAM_BASED);
|
||||
|
||||
var cacheEntry = session.openCacheEntry(aURL, nsICache.ACCESS_READ_WRITE, false);
|
||||
|
||||
cacheEntry.setMetaDataElement("servertype", "0");
|
||||
var oStream = cacheEntry.openOutputStream(0);
|
||||
|
||||
var written = oStream.write(aContent, aContent.length);
|
||||
if (written != aContent.length) {
|
||||
do_throw("oStream.write has not written all data!\n" +
|
||||
" Expected: " + written + "\n" +
|
||||
" Actual: " + aContent.length + "\n");
|
||||
}
|
||||
oStream.close();
|
||||
cacheEntry.close();
|
||||
}
|
||||
|
||||
const URL = "ftp://localhost/bug543805/";
|
||||
|
||||
var year = new Date().getFullYear().toString();
|
||||
@ -81,10 +39,45 @@ const tests = [
|
||||
"201: \"test2.file\" 66 Sun%2C%2001%20Apr%202008%2000%3A00%3A00 FILE \n"]
|
||||
]
|
||||
|
||||
function run_test() {
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
storeCache(URL, tests[i][0]);
|
||||
var parsedData = getURLContent(URL);
|
||||
do_check_eq(parsedData, tests[i][1]);
|
||||
function checkData(request, data, ctx) {
|
||||
do_check_eq(tests[0][1], data);
|
||||
tests.shift();
|
||||
next_test();
|
||||
}
|
||||
|
||||
function storeData(status, entry) {
|
||||
do_check_eq(status, Components.results.NS_OK);
|
||||
entry.setMetaDataElement("servertype", "0");
|
||||
var os = entry.openOutputStream(0);
|
||||
|
||||
var written = os.write(tests[0][0], tests[0][0].length);
|
||||
if (written != tests[0][0].length) {
|
||||
do_throw("os.write has not written all data!\n" +
|
||||
" Expected: " + written + "\n" +
|
||||
" Actual: " + tests[0][0].length + "\n");
|
||||
}
|
||||
os.close();
|
||||
entry.close();
|
||||
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"].
|
||||
getService(Components.interfaces.nsIIOService);
|
||||
var channel = ios.newChannel(URL, "", null);
|
||||
channel.asyncOpen(new ChannelListener(checkData, null, CL_ALLOW_UNKNOWN_CL), null);
|
||||
}
|
||||
|
||||
function next_test() {
|
||||
if (tests.length == 0)
|
||||
do_test_finished();
|
||||
else {
|
||||
asyncOpenCacheEntry(URL,
|
||||
"FTP",
|
||||
Components.interfaces.nsICache.STORE_ANYWHERE,
|
||||
Components.interfaces.nsICache.ACCESS_READ_WRITE,
|
||||
storeData);
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
do_execute_soon(next_test);
|
||||
do_test_pending();
|
||||
}
|
||||
|
@ -8,12 +8,6 @@ do_load_httpd_js();
|
||||
var httpserver = new nsHttpServer();
|
||||
var iteration = 0;
|
||||
|
||||
function getCacheService()
|
||||
{
|
||||
return Components.classes["@mozilla.org/network/cache-service;1"]
|
||||
.getService(Components.interfaces.nsICacheService);
|
||||
}
|
||||
|
||||
function setupChannel(suffix)
|
||||
{
|
||||
var ios =
|
||||
@ -38,8 +32,7 @@ function run_test()
|
||||
httpserver.start(4444);
|
||||
|
||||
// clear cache
|
||||
getCacheService().
|
||||
evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
// load first time
|
||||
var channel = setupChannel("/redirect1");
|
||||
|
@ -35,12 +35,6 @@ function checkValue(request, data, ctx) {
|
||||
httpserv.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function getCacheService()
|
||||
{
|
||||
return Components.classes["@mozilla.org/network/cache-service;1"]
|
||||
.getService(Components.interfaces.nsICacheService);
|
||||
}
|
||||
|
||||
function makeChan(url) {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
@ -70,8 +64,7 @@ function run_test() {
|
||||
Components.interfaces.nsIProtocolProxyService.PROXYCONFIG_SYSTEM);
|
||||
|
||||
// clear cache
|
||||
getCacheService().
|
||||
evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
var chan = makeChan("http://localhost:4444/target");
|
||||
chan.asyncOpen(new ChannelListener(checkValue, null), null);
|
||||
|
@ -2,11 +2,6 @@ do_load_httpd_js();
|
||||
var httpserver = new nsHttpServer();
|
||||
var expectedOnStopRequests = 3;
|
||||
|
||||
function getCacheService() {
|
||||
return Components.classes["@mozilla.org/network/cache-service;1"]
|
||||
.getService(Components.interfaces.nsICacheService);
|
||||
}
|
||||
|
||||
function setupChannel(suffix, xRequest, flags) {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
@ -58,8 +53,7 @@ function run_test() {
|
||||
do_get_profile();
|
||||
|
||||
// clear cache
|
||||
getCacheService().evictEntries(
|
||||
Components.interfaces.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
var ch0 = setupChannel("/bug596443", "Response0", Ci.nsIRequest.LOAD_BYPASS_CACHE);
|
||||
ch0.asyncOpen(new Listener("Response0"), null);
|
||||
|
@ -14,11 +14,6 @@ do_load_httpd_js();
|
||||
|
||||
var httpserv;
|
||||
|
||||
function getCacheService() {
|
||||
return Components.classes["@mozilla.org/network/cache-service;1"]
|
||||
.getService(Components.interfaces.nsICacheService);
|
||||
}
|
||||
|
||||
function setupChannel(path) {
|
||||
var ios =
|
||||
Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
@ -85,8 +80,7 @@ function run_test() {
|
||||
httpserv.start(4444);
|
||||
|
||||
// Clear cache
|
||||
getCacheService().evictEntries(
|
||||
Components.interfaces.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
// Load Content-Location URI into cache and start the chain of loads
|
||||
var channel = setupChannel("http://localhost:4444/cl");
|
||||
|
@ -6,15 +6,6 @@ const CACHECTRL_HDR_NAME = "X-CACHE-CONTROL-HEADER";
|
||||
|
||||
var httpserver = null;
|
||||
|
||||
var _CSvc;
|
||||
function get_cache_service() {
|
||||
if (_CSvc)
|
||||
return _CSvc;
|
||||
|
||||
return _CSvc = Cc["@mozilla.org/network/cache-service;1"].
|
||||
getService(Ci.nsICacheService);
|
||||
}
|
||||
|
||||
function make_channel(flags, vary, value) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
@ -182,7 +173,7 @@ function handler(metadata, response) {
|
||||
function run_test() {
|
||||
|
||||
// clear the cache
|
||||
get_cache_service().evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
httpserver = new nsHttpServer();
|
||||
httpserver.registerPathHandler("/bug633743", handler);
|
||||
|
@ -21,8 +21,7 @@ function SyncWithCacheThread(aFunc) {
|
||||
do_check_eq(sync_with_cache_IO_thread_cb.listener, null);
|
||||
sync_with_cache_IO_thread_cb.listener = aFunc;
|
||||
|
||||
var cache = Cc["@mozilla.org/network/cache-service;1"].
|
||||
getService(Ci.nsICacheService);
|
||||
var cache = get_cache_service();
|
||||
var session = cache.createSession(
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ANYWHERE,
|
||||
@ -44,12 +43,6 @@ var sync_with_cache_IO_thread_cb = {
|
||||
}
|
||||
};
|
||||
|
||||
function clearCache() {
|
||||
var service = Components.classes["@mozilla.org/network/cache-service;1"]
|
||||
.getService(Ci.nsICacheService);
|
||||
service.evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||
}
|
||||
|
||||
function setupChannel(suffix, value) {
|
||||
var ios = Components.classes["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
@ -88,7 +81,7 @@ function nextTest() {
|
||||
// We really want each test to be self-contained. Make sure cache is
|
||||
// cleared and also let all operations finish before starting a new test
|
||||
SyncWithCacheThread(function() {
|
||||
clearCache();
|
||||
evict_cache_entries();
|
||||
SyncWithCacheThread(runNextTest);
|
||||
});
|
||||
}
|
||||
|
@ -2,15 +2,6 @@ const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
var _CSvc;
|
||||
function get_cache_service() {
|
||||
if (_CSvc)
|
||||
return _CSvc;
|
||||
|
||||
return _CSvc = Cc["@mozilla.org/network/cache-service;1"].
|
||||
getService(Ci.nsICacheService);
|
||||
}
|
||||
|
||||
var _PSvc;
|
||||
function get_pref_service() {
|
||||
if (_PSvc)
|
||||
@ -20,49 +11,6 @@ function get_pref_service() {
|
||||
getService(Ci.nsIPrefBranch);
|
||||
}
|
||||
|
||||
function get_ostream_for_entry(key, asFile, append, entryRef)
|
||||
{
|
||||
var cache = get_cache_service();
|
||||
var session = cache.createSession(
|
||||
"HTTP",
|
||||
asFile ? Ci.nsICache.STORE_ON_DISK_AS_FILE
|
||||
: Ci.nsICache.STORE_ON_DISK,
|
||||
Ci.nsICache.STREAM_BASED);
|
||||
var cacheEntry = session.openCacheEntry(
|
||||
key,
|
||||
append ? Ci.nsICache.ACCESS_READ_WRITE
|
||||
: Ci.nsICache.ACCESS_WRITE,
|
||||
true);
|
||||
var oStream = cacheEntry.openOutputStream(append ? cacheEntry.dataSize : 0);
|
||||
entryRef.value = cacheEntry;
|
||||
return oStream;
|
||||
}
|
||||
|
||||
function sync_with_cache_IO_thread(aFunc)
|
||||
{
|
||||
do_check_eq(sync_with_cache_IO_thread_cb.listener, null);
|
||||
sync_with_cache_IO_thread_cb.listener = aFunc;
|
||||
var cache = get_cache_service();
|
||||
var session = cache.createSession(
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ON_DISK,
|
||||
Ci.nsICache.STREAM_BASED);
|
||||
var cacheEntry = session.asyncOpenCacheEntry(
|
||||
"nonexistententry",
|
||||
Ci.nsICache.ACCESS_READ,
|
||||
sync_with_cache_IO_thread_cb);
|
||||
}
|
||||
var sync_with_cache_IO_thread_cb = {
|
||||
listener: null,
|
||||
|
||||
onCacheEntryAvailable: function oCEA(descriptor, accessGranted, status) {
|
||||
do_check_eq(status, Cr.NS_ERROR_CACHE_KEY_NOT_FOUND);
|
||||
cb = this.listener;
|
||||
this.listener = null;
|
||||
do_timeout(0, cb);
|
||||
}
|
||||
};
|
||||
|
||||
function gen_1MiB()
|
||||
{
|
||||
var i;
|
||||
@ -82,10 +30,10 @@ function write_and_check(str, data, len)
|
||||
}
|
||||
}
|
||||
|
||||
function write_datafile()
|
||||
function write_datafile(status, entry)
|
||||
{
|
||||
var entry = {};
|
||||
var oStr = get_ostream_for_entry("data", true, false, entry);
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
var os = entry.openOutputStream(0);
|
||||
var data = gen_1MiB();
|
||||
|
||||
// max size in MB
|
||||
@ -95,50 +43,56 @@ function write_datafile()
|
||||
// write larger entry than is allowed
|
||||
var i;
|
||||
for (i=0 ; i<(max_size+1) ; i++)
|
||||
write_and_check(oStr, data, data.length);
|
||||
write_and_check(os, data, data.length);
|
||||
|
||||
oStr.close();
|
||||
entry.value.close();
|
||||
os.close();
|
||||
entry.close();
|
||||
|
||||
// wait until writing is done, then append to entry
|
||||
sync_with_cache_IO_thread(append_datafile);
|
||||
// append to entry
|
||||
asyncOpenCacheEntry("data",
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ON_DISK,
|
||||
Ci.nsICache.ACCESS_READ_WRITE,
|
||||
append_datafile);
|
||||
}
|
||||
|
||||
function append_datafile()
|
||||
function append_datafile(status, entry)
|
||||
{
|
||||
var entry = {};
|
||||
var oStr = get_ostream_for_entry("data", false, true, entry);
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
var os = entry.openOutputStream(entry.dataSize);
|
||||
var data = gen_1MiB();
|
||||
|
||||
|
||||
// append 1MiB
|
||||
try {
|
||||
write_and_check(oStr, data, data.length);
|
||||
write_and_check(os, data, data.length);
|
||||
do_throw();
|
||||
}
|
||||
catch (ex) { }
|
||||
|
||||
// closing the ostream should fail in this case
|
||||
try {
|
||||
oStr.close();
|
||||
os.close();
|
||||
do_throw();
|
||||
}
|
||||
catch (ex) { }
|
||||
|
||||
entry.value.close();
|
||||
|
||||
// wait until cache-operations have finished, then finish test
|
||||
sync_with_cache_IO_thread(do_test_finished);
|
||||
entry.close();
|
||||
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
|
||||
// clear the cache
|
||||
get_cache_service().evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
// wait until clearing is done, then force to write file bigger than 5MiB
|
||||
sync_with_cache_IO_thread(write_datafile);
|
||||
// force to write file bigger than 5MiB
|
||||
asyncOpenCacheEntry("data",
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ON_DISK_AS_FILE,
|
||||
Ci.nsICache.ACCESS_WRITE,
|
||||
write_datafile);
|
||||
|
||||
do_test_pending();
|
||||
}
|
||||
|
@ -2,33 +2,6 @@ const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
var _CSvc;
|
||||
function get_cache_service() {
|
||||
if (_CSvc)
|
||||
return _CSvc;
|
||||
|
||||
return _CSvc = Cc["@mozilla.org/network/cache-service;1"].
|
||||
getService(Ci.nsICacheService);
|
||||
}
|
||||
|
||||
function get_ostream_for_entry(key, asFile, append, entryRef)
|
||||
{
|
||||
var cache = get_cache_service();
|
||||
var session = cache.createSession(
|
||||
"HTTP",
|
||||
asFile ? Ci.nsICache.STORE_ON_DISK_AS_FILE
|
||||
: Ci.nsICache.STORE_ON_DISK,
|
||||
Ci.nsICache.STREAM_BASED);
|
||||
var cacheEntry = session.openCacheEntry(
|
||||
key,
|
||||
append ? Ci.nsICache.ACCESS_READ_WRITE
|
||||
: Ci.nsICache.ACCESS_WRITE,
|
||||
true);
|
||||
var oStream = cacheEntry.openOutputStream(append ? cacheEntry.dataSize : 0);
|
||||
entryRef.value = cacheEntry;
|
||||
return oStream;
|
||||
}
|
||||
|
||||
function gen_1MiB()
|
||||
{
|
||||
var i;
|
||||
@ -55,46 +28,58 @@ function make_input_stream_scriptable(input) {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
function write_datafile()
|
||||
function write_datafile(status, entry)
|
||||
{
|
||||
var entry = {};
|
||||
var oStr = get_ostream_for_entry("data", true, false, entry);
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
var os = entry.openOutputStream(0);
|
||||
var data = gen_1MiB();
|
||||
|
||||
write_and_check(oStr, data, data.length);
|
||||
write_and_check(os, data, data.length);
|
||||
|
||||
os.close();
|
||||
entry.close();
|
||||
|
||||
// open, doom, append, read
|
||||
asyncOpenCacheEntry("data",
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ON_DISK,
|
||||
Ci.nsICache.ACCESS_READ_WRITE,
|
||||
test_read_after_doom);
|
||||
|
||||
oStr.close();
|
||||
entry.value.close();
|
||||
}
|
||||
|
||||
function test_read_after_doom()
|
||||
function test_read_after_doom(status, entry)
|
||||
{
|
||||
var entry = {};
|
||||
var oStr = get_ostream_for_entry("data", false, true, entry);
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
var os = entry.openOutputStream(entry.dataSize);
|
||||
var data = gen_1MiB();
|
||||
|
||||
entry.value.doom();
|
||||
write_and_check(oStr, data, data.length);
|
||||
entry.doom();
|
||||
write_and_check(os, data, data.length);
|
||||
|
||||
oStr.close();
|
||||
os.close();
|
||||
|
||||
var iStr = make_input_stream_scriptable(entry.value.openInputStream(0));
|
||||
var read = iStr.read(iStr.available());
|
||||
var is = make_input_stream_scriptable(entry.openInputStream(0));
|
||||
var read = is.read(is.available());
|
||||
do_check_eq(read.length, 2*1024*1024);
|
||||
iStr.close();
|
||||
is.close();
|
||||
|
||||
entry.value.close();
|
||||
entry.close();
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
|
||||
// clear the cache
|
||||
get_cache_service().evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
// force to write file bigger than 5MiB
|
||||
write_datafile();
|
||||
asyncOpenCacheEntry("data",
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ON_DISK_AS_FILE,
|
||||
Ci.nsICache.ACCESS_WRITE,
|
||||
write_datafile);
|
||||
|
||||
// open, doom, append, read
|
||||
test_read_after_doom();
|
||||
do_test_pending();
|
||||
}
|
||||
|
@ -2,33 +2,6 @@ const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
var _CSvc;
|
||||
function get_cache_service() {
|
||||
if (_CSvc)
|
||||
return _CSvc;
|
||||
|
||||
return _CSvc = Cc["@mozilla.org/network/cache-service;1"].
|
||||
getService(Ci.nsICacheService);
|
||||
}
|
||||
|
||||
function get_ostream_for_entry(key, asFile, append, entryRef)
|
||||
{
|
||||
var cache = get_cache_service();
|
||||
var session = cache.createSession(
|
||||
"HTTP",
|
||||
asFile ? Ci.nsICache.STORE_ON_DISK_AS_FILE
|
||||
: Ci.nsICache.STORE_ON_DISK,
|
||||
Ci.nsICache.STREAM_BASED);
|
||||
var cacheEntry = session.openCacheEntry(
|
||||
key,
|
||||
append ? Ci.nsICache.ACCESS_READ_WRITE
|
||||
: Ci.nsICache.ACCESS_WRITE,
|
||||
true);
|
||||
var oStream = cacheEntry.openOutputStream(append ? cacheEntry.dataSize : 0);
|
||||
entryRef.value = cacheEntry;
|
||||
return oStream;
|
||||
}
|
||||
|
||||
function gen_1MiB()
|
||||
{
|
||||
var i;
|
||||
@ -48,40 +21,51 @@ function write_and_check(str, data, len)
|
||||
}
|
||||
}
|
||||
|
||||
function write_datafile()
|
||||
function write_datafile(status, entry)
|
||||
{
|
||||
var entry = {};
|
||||
var oStr = get_ostream_for_entry("data", true, false, entry);
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
var os = entry.openOutputStream(0);
|
||||
var data = gen_1MiB();
|
||||
|
||||
write_and_check(oStr, data, data.length);
|
||||
write_and_check(os, data, data.length);
|
||||
|
||||
oStr.close();
|
||||
entry.value.close();
|
||||
os.close();
|
||||
entry.close();
|
||||
|
||||
// try to open the entry for appending
|
||||
asyncOpenCacheEntry("data",
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ON_DISK,
|
||||
Ci.nsICache.ACCESS_READ_WRITE,
|
||||
open_for_readwrite);
|
||||
}
|
||||
|
||||
function open_for_readwrite()
|
||||
function open_for_readwrite(status, entry)
|
||||
{
|
||||
var entry = {};
|
||||
var oStr = get_ostream_for_entry("data", false, true, entry);
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
var os = entry.openOutputStream(entry.dataSize);
|
||||
|
||||
// Opening the entry for appending data calls nsDiskCacheStreamIO::Seek()
|
||||
// which initializes mFD. If no data is written then mBufDirty is false and
|
||||
// mFD won't be closed in nsDiskCacheStreamIO::Flush().
|
||||
|
||||
oStr.close();
|
||||
entry.value.close();
|
||||
os.close();
|
||||
entry.close();
|
||||
|
||||
do_test_finished();
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
|
||||
// clear the cache
|
||||
get_cache_service().evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
// force to write file bigger than 5MiB
|
||||
write_datafile();
|
||||
asyncOpenCacheEntry("data",
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ON_DISK_AS_FILE,
|
||||
Ci.nsICache.ACCESS_WRITE,
|
||||
write_datafile);
|
||||
|
||||
// try to open the entry for appending
|
||||
open_for_readwrite();
|
||||
do_test_pending();
|
||||
}
|
||||
|
@ -1,12 +1,6 @@
|
||||
do_load_httpd_js();
|
||||
var httpserver = new nsHttpServer();
|
||||
|
||||
function getCacheService()
|
||||
{
|
||||
return Components.classes["@mozilla.org/network/cache-service;1"]
|
||||
.getService(Components.interfaces.nsICacheService);
|
||||
}
|
||||
|
||||
function setupChannel(suffix)
|
||||
{
|
||||
var ios =
|
||||
@ -29,8 +23,7 @@ function run_test()
|
||||
httpserver.start(4444);
|
||||
|
||||
// clear cache
|
||||
getCacheService().
|
||||
evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
// load first time
|
||||
var channel = setupChannel("/redirect1");
|
||||
|
@ -2,7 +2,6 @@ var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
var Cr = Components.results;
|
||||
|
||||
var _cacheSvc;
|
||||
var _ios;
|
||||
|
||||
var ACCESS_WRITE = Ci.nsICache.ACCESS_WRITE;
|
||||
@ -71,15 +70,6 @@ CacheVisitor.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
function get_cache_service() {
|
||||
if (!_cacheSvc) {
|
||||
_cacheSvc = Cc["@mozilla.org/network/cache-service;1"].
|
||||
getService(Ci.nsICacheService);
|
||||
}
|
||||
|
||||
return _cacheSvc
|
||||
}
|
||||
|
||||
function get_io_service() {
|
||||
if (!_ios) {
|
||||
_ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
@ -141,8 +131,7 @@ function run_test() {
|
||||
do_get_profile();
|
||||
|
||||
// Make sure the cache is empty
|
||||
var cache = get_cache_service();
|
||||
cache.evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
// Add new tests at the end of this section
|
||||
add_test(test_corrupt_secinfo);
|
||||
|
121
netwerk/test/unit/test_cacheForOfflineUse_no-store.js
Normal file
121
netwerk/test/unit/test_cacheForOfflineUse_no-store.js
Normal file
@ -0,0 +1,121 @@
|
||||
"use strict";
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=760955
|
||||
|
||||
do_load_httpd_js();
|
||||
|
||||
var httpServer = null;
|
||||
const testFileName = "test_nsHttpChannel_CacheForOfflineUse-no-store";
|
||||
const cacheClientID = testFileName;
|
||||
const basePath = "/" + testFileName + "/";
|
||||
const baseURI = "http://localhost:4444" + basePath;
|
||||
const normalEntry = "normal";
|
||||
const noStoreEntry = "no-store";
|
||||
|
||||
var cacheUpdateObserver = null;
|
||||
|
||||
function make_channel_for_offline_use(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var chan = ios.newChannel(url, "", null);
|
||||
var cachingChan = chan.QueryInterface(Ci.nsICachingChannel);
|
||||
cachingChan.cacheForOfflineUse = true;
|
||||
cachingChan.offlineCacheClientID = cacheClientID;
|
||||
return chan;
|
||||
}
|
||||
|
||||
function make_uri(url) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
return ios.newURI(url, null, null);
|
||||
}
|
||||
|
||||
function CacheListener() { }
|
||||
CacheListener.prototype = {
|
||||
QueryInterface : function(iid)
|
||||
{
|
||||
if (iid.equals(Components.interfaces.nsICacheListener))
|
||||
return this;
|
||||
throw Components.results.NS_NOINTERFACE;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
function asyncCheckCacheEntryExistance(entryName, shouldExist)
|
||||
{
|
||||
var listener = new CacheListener();
|
||||
listener.onCacheEntryAvailable = function(descriptor, accessGranted, status) {
|
||||
if (shouldExist) {
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
do_check_true(!!descriptor);
|
||||
} else {
|
||||
todo_check_eq(status, Cr.NS_ERROR_CACHE_KEY_NOT_FOUND); // bug 761040
|
||||
todo_check_null(descriptor); // bug 761040
|
||||
}
|
||||
run_next_test();
|
||||
};
|
||||
|
||||
var service = Cc["@mozilla.org/network/cache-service;1"]
|
||||
.getService(Ci.nsICacheService);
|
||||
var session = service.createSession(cacheClientID, Ci.nsICache.STORE_OFFLINE,
|
||||
true);
|
||||
session.asyncOpenCacheEntry(baseURI + entryName, Ci.nsICache.ACCESS_READ,
|
||||
listener);
|
||||
}
|
||||
|
||||
const responseBody = "response body";
|
||||
|
||||
// A HTTP channel for updating the offline cache should normally succeed.
|
||||
function normalHandler(metadata, response)
|
||||
{
|
||||
do_print("normalHandler");
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
function checkNormal(request, buffer)
|
||||
{
|
||||
do_check_eq(buffer, responseBody);
|
||||
asyncCheckCacheEntryExistance(normalEntry, true);
|
||||
}
|
||||
add_test(function test_normal() {
|
||||
var chan = make_channel_for_offline_use(baseURI + normalEntry);
|
||||
chan.asyncOpen(new ChannelListener(checkNormal, chan), null);
|
||||
});
|
||||
|
||||
// An HTTP channel for updating the offline cache should fail when it gets a
|
||||
// response with Cache-Control: no-store.
|
||||
function noStoreHandler(metadata, response)
|
||||
{
|
||||
do_print("noStoreHandler");
|
||||
response.setHeader("Content-Type", "text/plain");
|
||||
response.setHeader("Cache-Control", "no-store");
|
||||
response.bodyOutputStream.write(responseBody, responseBody.length);
|
||||
}
|
||||
function checkNoStore(request, buffer)
|
||||
{
|
||||
todo_check_eq(buffer, ""); // bug 761040
|
||||
asyncCheckCacheEntryExistance(noStoreEntry, false);
|
||||
run_next_test();
|
||||
}
|
||||
add_test(function test_noStore() {
|
||||
var chan = make_channel_for_offline_use(baseURI + noStoreEntry);
|
||||
// The no-store should cause the channel to fail to load.
|
||||
chan.asyncOpen(new ChannelListener(checkNoStore, chan
|
||||
/*, TODO(bug 761040): CL_EXPECT_FAILURE*/),
|
||||
null);
|
||||
});
|
||||
|
||||
function run_test()
|
||||
{
|
||||
do_get_profile();
|
||||
|
||||
httpServer = new nsHttpServer();
|
||||
httpServer.registerPathHandler(basePath + normalEntry, normalHandler);
|
||||
httpServer.registerPathHandler(basePath + noStoreEntry, noStoreHandler);
|
||||
httpServer.start(4444);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function finish_test(request, buffer)
|
||||
{
|
||||
httpServer.stop(do_test_finished);
|
||||
}
|
@ -6,37 +6,6 @@ const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
var _CSvc;
|
||||
function get_cache_service() {
|
||||
if (_CSvc)
|
||||
return _CSvc;
|
||||
|
||||
return _CSvc = Cc["@mozilla.org/network/cache-service;1"].
|
||||
getService(Ci.nsICacheService);
|
||||
}
|
||||
|
||||
function get_ostream_for_entry(key, append, compress, entryRef)
|
||||
{
|
||||
var cache = get_cache_service();
|
||||
var session = cache.createSession(
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ON_DISK,
|
||||
Ci.nsICache.STREAM_BASED);
|
||||
var cacheEntry = session.openCacheEntry(
|
||||
key,
|
||||
append ? Ci.nsICache.ACCESS_READ_WRITE
|
||||
: Ci.nsICache.ACCESS_WRITE,
|
||||
true);
|
||||
|
||||
if (compress)
|
||||
if (!append)
|
||||
cacheEntry.setMetaDataElement("uncompressed-len", "0");
|
||||
|
||||
var oStream = cacheEntry.openOutputStream(append ? cacheEntry.storageDataSize : 0);
|
||||
entryRef.value = cacheEntry;
|
||||
return oStream;
|
||||
}
|
||||
|
||||
function write_and_check(str, data, len)
|
||||
{
|
||||
var written = str.write(data, len);
|
||||
@ -47,60 +16,77 @@ function write_and_check(str, data, len)
|
||||
}
|
||||
}
|
||||
|
||||
function check_datafile()
|
||||
function TestAppend(compress, callback)
|
||||
{
|
||||
var cache = get_cache_service();
|
||||
var session = cache.createSession(
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ON_DISK,
|
||||
Ci.nsICache.STREAM_BASED);
|
||||
var entry = session.openCacheEntry(
|
||||
"data",
|
||||
Ci.nsICache.ACCESS_READ,
|
||||
true);
|
||||
|
||||
var wrapper = Cc["@mozilla.org/scriptableinputstream;1"].
|
||||
createInstance(Ci.nsIScriptableInputStream);
|
||||
|
||||
wrapper.init(entry.openInputStream(0));
|
||||
|
||||
var str = wrapper.read(wrapper.available());
|
||||
do_check_eq(str.length, 10);
|
||||
do_check_eq(str, "12345abcde");
|
||||
|
||||
wrapper.close();
|
||||
entry.close();
|
||||
this._compress = compress;
|
||||
this._callback = callback;
|
||||
this.run();
|
||||
}
|
||||
|
||||
TestAppend.prototype = {
|
||||
_compress: false,
|
||||
_callback: null,
|
||||
|
||||
function write_datafile(compress)
|
||||
{
|
||||
var entry = {};
|
||||
var oStr = get_ostream_for_entry("data", false, compress, entry);
|
||||
write_and_check(oStr, "12345", 5);
|
||||
oStr.close();
|
||||
entry.value.close();
|
||||
}
|
||||
run: function() {
|
||||
evict_cache_entries();
|
||||
asyncOpenCacheEntry("data",
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ON_DISK,
|
||||
Ci.nsICache.ACCESS_WRITE,
|
||||
this.writeData.bind(this));
|
||||
},
|
||||
|
||||
function append_datafile()
|
||||
{
|
||||
var entry = {};
|
||||
var oStr = get_ostream_for_entry("data", true, false, entry);
|
||||
write_and_check(oStr, "abcde", 5);
|
||||
oStr.close();
|
||||
entry.value.close();
|
||||
}
|
||||
writeData: function(status, entry) {
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
if (this._compress)
|
||||
entry.setMetaDataElement("uncompressed-len", "0");
|
||||
var os = entry.openOutputStream(0);
|
||||
write_and_check(os, "12345", 5);
|
||||
os.close();
|
||||
entry.close();
|
||||
asyncOpenCacheEntry("data",
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ON_DISK,
|
||||
Ci.nsICache.ACCESS_READ_WRITE,
|
||||
this.appendData.bind(this));
|
||||
},
|
||||
|
||||
function test_append(compress)
|
||||
{
|
||||
get_cache_service().evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||
write_datafile(compress);
|
||||
append_datafile();
|
||||
check_datafile();
|
||||
}
|
||||
appendData: function(status, entry) {
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
var os = entry.openOutputStream(entry.storageDataSize);
|
||||
write_and_check(os, "abcde", 5);
|
||||
os.close();
|
||||
entry.close();
|
||||
|
||||
asyncOpenCacheEntry("data",
|
||||
"HTTP",
|
||||
Ci.nsICache.STORE_ON_DISK,
|
||||
Ci.nsICache.ACCESS_READ,
|
||||
this.checkData.bind(this));
|
||||
},
|
||||
|
||||
checkData: function(status, entry) {
|
||||
do_check_eq(status, Cr.NS_OK);
|
||||
var wrapper = Cc["@mozilla.org/scriptableinputstream;1"].
|
||||
createInstance(Ci.nsIScriptableInputStream);
|
||||
wrapper.init(entry.openInputStream(0));
|
||||
var str = wrapper.read(wrapper.available());
|
||||
do_check_eq(str.length, 10);
|
||||
do_check_eq(str, "12345abcde");
|
||||
|
||||
wrapper.close();
|
||||
entry.close();
|
||||
|
||||
do_execute_soon(this._callback);
|
||||
}
|
||||
};
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
test_append(false);
|
||||
test_append(true);
|
||||
new TestAppend(false, run_test2);
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function run_test2() {
|
||||
new TestAppend(true, do_test_finished);
|
||||
}
|
||||
|
@ -10,15 +10,6 @@ const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
var _CSvc;
|
||||
function get_cache_service() {
|
||||
if (_CSvc)
|
||||
return _CSvc;
|
||||
|
||||
return _CSvc = Cc["@mozilla.org/network/cache-service;1"].
|
||||
getService(Ci.nsICacheService);
|
||||
}
|
||||
|
||||
function GetOutputStreamForEntry(key, asFile, append, callback)
|
||||
{
|
||||
this._key = key;
|
||||
@ -164,7 +155,7 @@ function run_test() {
|
||||
do_get_profile();
|
||||
|
||||
// clear the cache
|
||||
get_cache_service().evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
write_entry();
|
||||
do_test_pending();
|
||||
}
|
||||
|
@ -8,13 +8,6 @@ const responseBody = [0x1f, 0x8b, 0x08, 0x08, 0xef, 0x70, 0xe6, 0x4c, 0x00, 0x03
|
||||
0xe2, 0x9c, 0xcc, 0xf4, 0x8c, 0x92, 0x9c, 0x4a, 0x85, 0x9c, 0xfc, 0xbc, 0xf4, 0xd4, 0x22, 0x85,
|
||||
0x92, 0xd4, 0xe2, 0x12, 0x2e, 0x2e, 0x00, 0x00, 0xe5, 0xe6, 0xf0, 0x20, 0x00, 0x00, 0x00];
|
||||
|
||||
function getCacheService()
|
||||
{
|
||||
var nsCacheService = Components.classes["@mozilla.org/network/cache-service;1"];
|
||||
var service = nsCacheService.getService(Components.interfaces.nsICacheService);
|
||||
return service;
|
||||
}
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
@ -82,7 +75,7 @@ function run_test() {
|
||||
httpserver.start(4444);
|
||||
|
||||
// wipe out cached content
|
||||
getCacheService().evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
var chan = make_channel("http://localhost:4444/cached/test.gz");
|
||||
chan.asyncOpen(new ChannelListener(continue_test, null, CL_EXPECT_GZIP), null);
|
||||
|
@ -1,6 +1,5 @@
|
||||
do_load_httpd_js();
|
||||
var httpserver = new nsHttpServer();
|
||||
var cacheService;
|
||||
var ios;
|
||||
|
||||
// Test the handling of a cache revalidation with mismatching last-modified
|
||||
@ -103,12 +102,10 @@ var listener_1 = {
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
cacheService = Cc["@mozilla.org/network/cache-service;1"].
|
||||
getService(Ci.nsICacheService);
|
||||
ios = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Ci.nsIIOService);
|
||||
|
||||
cacheService.evictEntries(Ci.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
httpserver.registerPathHandler("/test1", handler);
|
||||
httpserver.start(4444);
|
||||
|
@ -38,8 +38,6 @@ Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const kNS_OFFLINECACHEUPDATESERVICE_CONTRACTID =
|
||||
"@mozilla.org/offlinecacheupdate-service;1";
|
||||
const kNS_CACHESERVICE_CONTRACTID =
|
||||
"@mozilla.org/network/cache-service;1";
|
||||
|
||||
const kManifest1 = "CACHE MANIFEST\n" +
|
||||
"/pages/foo1\n" +
|
||||
@ -120,9 +118,7 @@ function init_cache_capacity() {
|
||||
}
|
||||
|
||||
function clean_app_cache() {
|
||||
let cache_service = Cc[kNS_CACHESERVICE_CONTRACTID].
|
||||
getService(Ci.nsICacheService);
|
||||
cache_service.evictEntries(Ci.nsICache.STORE_OFFLINE);
|
||||
evict_cache_entries(Ci.nsICache.STORE_OFFLINE);
|
||||
}
|
||||
|
||||
function do_app_cache(manifestURL, pageURL, pinned) {
|
||||
|
@ -29,13 +29,6 @@ const decodedBody = [0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20,
|
||||
|
||||
const partial_data_length = 4;
|
||||
|
||||
function getCacheService()
|
||||
{
|
||||
var nsCacheService = Components.classes["@mozilla.org/network/cache-service;1"];
|
||||
var service = nsCacheService.getService(Components.interfaces.nsICacheService);
|
||||
return service;
|
||||
}
|
||||
|
||||
function make_channel(url, callback, ctx) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
@ -249,7 +242,7 @@ function run_test() {
|
||||
httpserver.start(4444);
|
||||
|
||||
// wipe out cached content
|
||||
getCacheService().evictEntries(Components.interfaces.nsICache.STORE_ANYWHERE);
|
||||
evict_cache_entries();
|
||||
|
||||
// Case 2: zero-length partial entry must not trigger range-request
|
||||
var chan = make_channel("http://localhost:4444/test_2");
|
||||
|
@ -1,7 +1,9 @@
|
||||
[DEFAULT]
|
||||
head = head_channels.js
|
||||
head = head_channels.js head_cache.js
|
||||
tail =
|
||||
|
||||
[test_304_responses.js]
|
||||
[test_cacheForOfflineUse_no-store.js]
|
||||
[test_307_redirect.js]
|
||||
[test_NetUtil.js]
|
||||
[test_URIs.js]
|
||||
|
@ -17,6 +17,7 @@ Alex Grönholm
|
||||
Anatoly Techtonik
|
||||
Antonio Cuni
|
||||
Armin Ronacher
|
||||
Bradley Ayers
|
||||
Cap Petschulat
|
||||
CBWhiz
|
||||
Chris McDonough
|
||||
@ -24,6 +25,7 @@ Christian Stefanescu
|
||||
Christopher Nilsson
|
||||
Cliff Xuan
|
||||
Curt Micol
|
||||
David Schoonover
|
||||
Doug Hellmann
|
||||
Doug Napoleone
|
||||
Douglas Creager
|
||||
@ -35,9 +37,14 @@ Jeff Hammel
|
||||
Jonathan Griffin
|
||||
Jorge Vargas
|
||||
Josh Bronson
|
||||
Konstantin Zemlyak
|
||||
Kumar McMillan
|
||||
Lars Francke
|
||||
Marc Abramowitz
|
||||
Mike Hommey
|
||||
Miki Tebeka
|
||||
Philip Jenvey
|
||||
Raul Leal
|
||||
Ronny Pfannschmidt
|
||||
Stefano Rivera
|
||||
Tarek Ziadé
|
||||
|
@ -1,9 +1,11 @@
|
||||
recursive-include docs *.txt
|
||||
recursive-include bin *
|
||||
recursive-include docs *
|
||||
recursive-include scripts *
|
||||
recursive-include virtualenv_support *.egg *.tar.gz
|
||||
recursive-include virtualenv_embedded *
|
||||
recursive-exclude docs/_templates *.*
|
||||
recursive-exclude docs/_templates *
|
||||
recursive-exclude docs/_build *
|
||||
include virtualenv_support/__init__.py
|
||||
include *.py
|
||||
include AUTHORS.txt
|
||||
include LICENSE.txt
|
||||
include LICENSE.txt
|
||||
|
@ -17,8 +17,8 @@ Installation
|
||||
------------
|
||||
|
||||
You can install virtualenv with ``pip install virtualenv``, or the `latest
|
||||
development version <https://github.com/pypa/virtualenv/tarball/develop#egg=virtualenv-dev>`_
|
||||
with ``pip install virtualenv==dev``.
|
||||
development version <https://github.com/pypa/virtualenv/tarball/develop>`_
|
||||
with ``pip install https://github.com/pypa/virtualenv/tarball/develop``.
|
||||
|
||||
You can also use ``easy_install``, or if you have no Python package manager
|
||||
available at all, you can just grab the single file `virtualenv.py`_ and run
|
||||
@ -52,6 +52,9 @@ environment that has its own installation directories, that doesn't
|
||||
share libraries with other virtualenv environments (and optionally
|
||||
doesn't access the globally installed libraries either).
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
The basic usage is::
|
||||
|
||||
$ python virtualenv.py ENV
|
||||
@ -71,12 +74,116 @@ Distribute instead of setuptools, just call virtualenv like this::
|
||||
|
||||
$ python virtualenv.py --distribute ENV
|
||||
|
||||
You can also set the environment variable VIRTUALENV_USE_DISTRIBUTE.
|
||||
You can also set the environment variable VIRTUALENV_DISTRIBUTE.
|
||||
|
||||
A new virtualenv also includes the `pip <http://pypy.python.org/pypi/pip>`_
|
||||
A new virtualenv also includes the `pip <http://pypi.python.org/pypi/pip>`_
|
||||
installer, so you can use ``ENV/bin/pip`` to install additional packages into
|
||||
the environment.
|
||||
|
||||
|
||||
activate script
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
In a newly created virtualenv there will be a ``bin/activate`` shell
|
||||
script. For Windows systems, activation scripts are provided for CMD.exe
|
||||
and Powershell.
|
||||
|
||||
On Posix systems you can do::
|
||||
|
||||
$ source bin/activate
|
||||
|
||||
This will change your ``$PATH`` so its first entry is the virtualenv's
|
||||
``bin/`` directory. (You have to use ``source`` because it changes your
|
||||
shell environment in-place.) This is all it does; it's purely a
|
||||
convenience. If you directly run a script or the python interpreter
|
||||
from the virtualenv's ``bin/`` directory (e.g. ``path/to/env/bin/pip``
|
||||
or ``/path/to/env/bin/python script.py``) there's no need for
|
||||
activation.
|
||||
|
||||
After activating an environment you can use the function ``deactivate`` to
|
||||
undo the changes to your ``$PATH``.
|
||||
|
||||
The ``activate`` script will also modify your shell prompt to indicate
|
||||
which environment is currently active. You can disable this behavior,
|
||||
which can be useful if you have your own custom prompt that already
|
||||
displays the active environment name. To do so, set the
|
||||
``VIRTUAL_ENV_DISABLE_PROMPT`` environment variable to any non-empty
|
||||
value before running the ``activate`` script.
|
||||
|
||||
On Windows you just do::
|
||||
|
||||
> \path\to\env\Scripts\activate
|
||||
|
||||
And type `deactivate` to undo the changes.
|
||||
|
||||
Based on your active shell (CMD.exe or Powershell.exe), Windows will use
|
||||
either activate.bat or activate.ps1 (as appropriate) to activate the
|
||||
virtual environment. If using Powershell, see the notes about code signing
|
||||
below.
|
||||
|
||||
.. note::
|
||||
|
||||
If using Powershell, the ``activate`` script is subject to the
|
||||
`execution policies`_ on the system. By default on Windows 7, the system's
|
||||
excution policy is set to ``Restricted``, meaning no scripts like the
|
||||
``activate`` script are allowed to be executed. But that can't stop us
|
||||
from changing that slightly to allow it to be executed.
|
||||
|
||||
In order to use the script, you have to relax your system's execution
|
||||
policy to ``AllSigned``, meaning all scripts on the system must be
|
||||
digitally signed to be executed. Since the virtualenv activation
|
||||
script is signed by one of the authors (Jannis Leidel) this level of
|
||||
the execution policy suffices. As an administrator run::
|
||||
|
||||
PS C:\> Set-ExecutionPolicy AllSigned
|
||||
|
||||
Then you'll be asked to trust the signer, when executing the script.
|
||||
You will be prompted with the following::
|
||||
|
||||
PS C:\> virtualenv .\foo
|
||||
New python executable in C:\foo\Scripts\python.exe
|
||||
Installing setuptools................done.
|
||||
Installing pip...................done.
|
||||
PS C:\> .\foo\scripts\activate
|
||||
|
||||
Do you want to run software from this untrusted publisher?
|
||||
File C:\foo\scripts\activate.ps1 is published by E=jannis@leidel.info,
|
||||
CN=Jannis Leidel, L=Berlin, S=Berlin, C=DE, Description=581796-Gh7xfJxkxQSIO4E0
|
||||
and is not trusted on your system. Only run scripts from trusted publishers.
|
||||
[V] Never run [D] Do not run [R] Run once [A] Always run [?] Help
|
||||
(default is "D"):A
|
||||
(foo) PS C:\>
|
||||
|
||||
If you select ``[A] Always Run``, the certificate will be added to the
|
||||
Trusted Publishers of your user account, and will be trusted in this
|
||||
user's context henceforth. If you select ``[R] Run Once``, the script will
|
||||
be run, but you will be prometed on a subsequent invocation. Advanced users
|
||||
can add the signer's certificate to the Trusted Publishers of the Computer
|
||||
account to apply to all users (though this technique is out of scope of this
|
||||
document).
|
||||
|
||||
Alternatively, you may relax the system execution policy to allow running
|
||||
of local scripts without verifying the code signature using the following::
|
||||
|
||||
PS C:\> Set-ExecutionPolicy RemoteSigned
|
||||
|
||||
Since the ``activate.ps1`` script is generated locally for each virtualenv,
|
||||
it is not considered a remote script and can then be executed.
|
||||
|
||||
.. _`execution policies`: http://technet.microsoft.com/en-us/library/dd347641.aspx
|
||||
|
||||
The ``--system-site-packages`` Option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you build with ``virtualenv --system-site-packages ENV``, your virtual
|
||||
environment will inherit packages from ``/usr/lib/python2.7/site-packages``
|
||||
(or wherever your global site-packages directory is).
|
||||
|
||||
This can be used if you have control over the global site-packages directory,
|
||||
and you want to depend on the packages there. If you want isolation from the
|
||||
global system, do not use this flag.
|
||||
|
||||
|
||||
Environment variables and configuration files
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -93,7 +200,7 @@ virtualenv can not only be configured by passing command line options such as
|
||||
For example, to automatically install Distribute instead of setuptools
|
||||
you can also set an environment variable::
|
||||
|
||||
$ export VIRTUALENV_USE_DISTRIBUTE=true
|
||||
$ export VIRTUALENV_DISTRIBUTE=true
|
||||
$ python virtualenv.py ENV
|
||||
|
||||
It's the same as passing the option to virtualenv directly::
|
||||
@ -114,7 +221,7 @@ virtualenv can not only be configured by passing command line options such as
|
||||
|
||||
virtualenv also looks for a standard ini config file. On Unix and Mac OS X
|
||||
that's ``$HOME/.virtualenv/virtualenv.ini`` and on Windows, it's
|
||||
``%HOME%\\virtualenv\\virtualenv.ini``.
|
||||
``%APPDATA%\virtualenv\virtualenv.ini``.
|
||||
|
||||
The names of the settings are derived from the long command line option,
|
||||
e.g. the option ``--distribute`` would look like this::
|
||||
@ -225,109 +332,9 @@ Here's a more concrete example of how you could use this::
|
||||
Another example is available `here
|
||||
<https://github.com/socialplanning/fassembler/blob/master/fassembler/create-venv-script.py>`_.
|
||||
|
||||
activate script
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
In a newly created virtualenv there will be a ``bin/activate`` shell
|
||||
script. For Windows systems, activation scripts are provided for CMD.exe
|
||||
and Powershell.
|
||||
|
||||
On Posix systems you can do::
|
||||
|
||||
$ source bin/activate
|
||||
|
||||
This will change your ``$PATH`` to point to the virtualenv's ``bin/``
|
||||
directory. (You have to use ``source`` because it changes your shell
|
||||
environment in-place.) This is all it does; it's purely a convenience. If
|
||||
you directly run a script or the python interpreter from the virtualenv's
|
||||
``bin/`` directory (e.g. ``path/to/env/bin/pip`` or
|
||||
``/path/to/env/bin/python script.py``) there's no need for activation.
|
||||
|
||||
After activating an environment you can use the function ``deactivate`` to
|
||||
undo the changes to your ``$PATH``.
|
||||
|
||||
The ``activate`` script will also modify your shell prompt to indicate
|
||||
which environment is currently active. You can disable this behavior,
|
||||
which can be useful if you have your own custom prompt that already
|
||||
displays the active environment name. To do so, set the
|
||||
``VIRTUAL_ENV_DISABLE_PROMPT`` environment variable to any non-empty
|
||||
value before running the ``activate`` script.
|
||||
|
||||
On Windows you just do::
|
||||
|
||||
> \path\to\env\Scripts\activate
|
||||
|
||||
And type `deactivate` to undo the changes.
|
||||
|
||||
Based on your active shell (CMD.exe or Powershell.exe), Windows will use
|
||||
either activate.bat or activate.ps1 (as appropriate) to activate the
|
||||
virtual environment. If using Powershell, see the notes about code signing
|
||||
below.
|
||||
|
||||
.. note::
|
||||
|
||||
If using Powershell, the ``activate`` script is subject to the
|
||||
`execution policies`_ on the system. By default on Windows 7, the system's
|
||||
excution policy is set to ``Restricted``, meaning no scripts like the
|
||||
``activate`` script are allowed to be executed. But that can't stop us
|
||||
from changing that slightly to allow it to be executed.
|
||||
|
||||
In order to use the script, you have to relax your system's execution
|
||||
policy to ``AllSigned``, meaning all scripts on the system must be
|
||||
digitally signed to be executed. Since the virtualenv activation
|
||||
script is signed by one of the authors (Jannis Leidel) this level of
|
||||
the execution policy suffices. As an adminstrator run::
|
||||
|
||||
PS C:\> Set-ExecutionPolicy AllSigned
|
||||
|
||||
Then you'll be asked to trust the signer, when executing the script.
|
||||
You will be prompted with the following::
|
||||
|
||||
PS C:\> virtualenv .\foo
|
||||
New python executable in C:\foo\Scripts\python.exe
|
||||
Installing setuptools................done.
|
||||
Installing pip...................done.
|
||||
PS C:\> .\foo\scripts\activate
|
||||
|
||||
Do you want to run software from this untrusted publisher?
|
||||
File C:\foo\scripts\activate.ps1 is published by E=jannis@leidel.info,
|
||||
CN=Jannis Leidel, L=Berlin, S=Berlin, C=DE, Description=581796-Gh7xfJxkxQSIO4E0
|
||||
and is not trusted on your system. Only run scripts from trusted publishers.
|
||||
[V] Never run [D] Do not run [R] Run once [A] Always run [?] Help
|
||||
(default is "D"):A
|
||||
(foo) PS C:\>
|
||||
|
||||
If you select ``[A] Always Run``, the certificate will be added to the
|
||||
Trusted Publishers of your user account, and will be trusted in this
|
||||
user's context henceforth. If you select ``[R] Run Once``, the script will
|
||||
be run, but you will be prometed on a subsequent invocation. Advanced users
|
||||
can add the signer's certificate to the Trusted Publishers of the Computer
|
||||
account to apply to all users (though this technique is out of scope of this
|
||||
document).
|
||||
|
||||
Alternatively, you may relax the system execution policy to allow running
|
||||
of local scripts without verifying the code signature using the following::
|
||||
|
||||
PS C:\> Set-ExecutionPolicy RemoteSigned
|
||||
|
||||
Since the ``activate.ps1`` script is generated locally for each virtualenv,
|
||||
it is not considered a remote script and can then be executed.
|
||||
|
||||
.. _`execution policies`: http://technet.microsoft.com/en-us/library/dd347641.aspx
|
||||
|
||||
The ``--system-site-packages`` Option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you build with ``virtualenv --system-site-packages ENV``, your virtual
|
||||
environment will inherit packages from ``/usr/lib/python2.7/site-packages``
|
||||
(or wherever your global site-packages directory is).
|
||||
|
||||
This can be used if you have control over the global site-packages directory,
|
||||
and you want to depend on the packages there. If you want isolation from the
|
||||
global system, do not use this flag.
|
||||
|
||||
Using Virtualenv without ``bin/python``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
---------------------------------------
|
||||
|
||||
Sometimes you can't or don't want to use the Python interpreter
|
||||
created by the virtualenv. For instance, in a `mod_python
|
||||
@ -353,7 +360,7 @@ request; you should activate *one* environment as early as possible, and not
|
||||
do it again in that process.
|
||||
|
||||
Making Environments Relocatable
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-------------------------------
|
||||
|
||||
Note: this option is somewhat experimental, and there are probably
|
||||
caveats that have not yet been identified. Also this does not
|
||||
@ -390,8 +397,8 @@ layout).
|
||||
If you use this flag to create an environment, currently, the
|
||||
``--system-site-packages`` option will be implied.
|
||||
|
||||
The ``--extra-search-dir`` Option
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The ``--extra-search-dir`` option
|
||||
---------------------------------
|
||||
|
||||
When it creates a new environment, virtualenv installs either
|
||||
setuptools or distribute, and pip. In normal operation, the latest
|
||||
@ -479,13 +486,15 @@ Contributing
|
||||
------------
|
||||
|
||||
Refer to the `contributing to pip`_ documentation - it applies equally to
|
||||
virtualenv.
|
||||
virtualenv, except that virtualenv issues should filed on the `virtualenv
|
||||
repo`_ at GitHub.
|
||||
|
||||
Virtualenv's release schedule is tied to pip's -- each time there's a new pip
|
||||
release, there will be a new virtualenv release that bundles the new version of
|
||||
pip.
|
||||
|
||||
.. _contributing to pip: http://www.pip-installer.org/en/latest/contributing.html
|
||||
.. _virtualenv repo: https://github.com/pypa/virtualenv/
|
||||
|
||||
Running the tests
|
||||
~~~~~~~~~~~~~~~~~
|
||||
@ -537,7 +546,7 @@ Other Documentation and Links
|
||||
<http://code.google.com/p/modwsgi/wiki/VirtualEnvironments>`_.
|
||||
|
||||
* `virtualenv commands
|
||||
<http://thisismedium.com/tech/extending-virtualenv/>`_ for some more
|
||||
<https://github.com/thisismedium/virtualenv-commands>`_ for some more
|
||||
workflow-related tools around virtualenv.
|
||||
|
||||
Status and License
|
||||
|
@ -1,6 +1,49 @@
|
||||
Changes & News
|
||||
--------------
|
||||
|
||||
.. warning::
|
||||
|
||||
Python bugfix releases 2.6.8, 2.7.3, 3.1.5 and 3.2.3 include a change that
|
||||
will cause "import random" to fail with "cannot import name urandom" on any
|
||||
virtualenv created on a Unix host with an earlier release of Python
|
||||
2.6/2.7/3.1/3.2, if the underlying system Python is upgraded. This is due to
|
||||
the fact that a virtualenv uses the system Python's standard library but
|
||||
contains its own copy of the Python interpreter, so an upgrade to the system
|
||||
Python results in a mismatch between the version of the Python interpreter
|
||||
and the version of the standard library. It can be fixed by removing
|
||||
``$ENV/bin/python`` and re-running virtualenv on the same target directory
|
||||
with the upgraded Python.
|
||||
|
||||
|
||||
1.7.2 (2012-06-22)
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* Updated to distribute 0.6.27.
|
||||
|
||||
* Fix activate.fish on OS X. Fixes #8. Thanks David Schoonover.
|
||||
|
||||
* Create a virtualenv-x.x script with the Python version when installing, so
|
||||
virtualenv for multiple Python versions can be installed to the same
|
||||
script location. Thanks Miki Tebeka.
|
||||
|
||||
* Restored ability to create a virtualenv with a path longer than 78
|
||||
characters, without breaking creation of virtualenvs with non-ASCII paths.
|
||||
Thanks, Bradley Ayers.
|
||||
|
||||
* Added ability to create virtualenvs without having installed Apple's
|
||||
developers tools (using an own implementation of ``install_name_tool``).
|
||||
Thanks Mike Hommey.
|
||||
|
||||
* Fixed PyPy and Jython support on Windows. Thanks Konstantin Zemlyak.
|
||||
|
||||
* Added pydoc script to ease use. Thanks Marc Abramowitz. Fixes #149.
|
||||
|
||||
* Fixed creating a bootstrap script on Python 3. Thanks Raul Leal. Fixes #280.
|
||||
|
||||
* Fixed inconsistency when having set the ``PYTHONDONTWRITEBYTECODE`` env var
|
||||
with the --distribute option or the ``VIRTUALENV_USE_DISTRIBUTE`` env var.
|
||||
``VIRTUALENV_USE_DISTRIBUTE`` is now considered again as a legacy alias.
|
||||
|
||||
1.7.1.2 (2012-02-17)
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@ -210,7 +253,7 @@ Changes & News
|
||||
* Fix problem with ``virtualenv --relocate`` when ``bin/`` has
|
||||
subdirectories (e.g., ``bin/.svn/``); from Alan Franzoni.
|
||||
|
||||
* If you set ``$VIRTUALENV_USE_DISTRIBUTE`` then virtualenv will use
|
||||
* If you set ``$VIRTUALENV_DISTRIBUTE`` then virtualenv will use
|
||||
Distribute by default (so you don't have to remember to use
|
||||
``--distribute``).
|
||||
|
||||
@ -301,7 +344,7 @@ Changes & News
|
||||
``distutils.cfg`` -- this has been causing problems for a lot of
|
||||
people, in rather obscure ways.
|
||||
|
||||
* If you use a `boot script <./index.html#boot-script>`_ it will attempt to import ``virtualenv``
|
||||
* If you use a boot script it will attempt to import ``virtualenv``
|
||||
and find a pre-downloaded Setuptools egg using that.
|
||||
|
||||
* Added platform-specific paths, like ``/usr/lib/pythonX.Y/plat-linux2``
|
||||
|
@ -1,16 +1,31 @@
|
||||
import sys, os
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
try:
|
||||
from setuptools import setup
|
||||
kw = {'entry_points':
|
||||
"""[console_scripts]\nvirtualenv = virtualenv:main\n""",
|
||||
'zip_safe': False}
|
||||
setup_params = {
|
||||
'entry_points': {
|
||||
'console_scripts': [
|
||||
'virtualenv=virtualenv:main',
|
||||
'virtualenv-%s.%s=virtualenv:main' % sys.version_info[:2]
|
||||
],
|
||||
},
|
||||
'zip_safe': False,
|
||||
'test_suite': 'nose.collector',
|
||||
'tests_require': ['nose', 'Mock'],
|
||||
}
|
||||
except ImportError:
|
||||
from distutils.core import setup
|
||||
if sys.platform == 'win32':
|
||||
print('Note: without Setuptools installed you will have to use "python -m virtualenv ENV"')
|
||||
kw = {}
|
||||
setup_params = {}
|
||||
else:
|
||||
kw = {'scripts': ['scripts/virtualenv']}
|
||||
script = 'scripts/virtualenv'
|
||||
script_ver = script + '-%s.%s' % sys.version_info[:2]
|
||||
shutil.copy(script, script_ver)
|
||||
setup_params = {'scripts': [script, script_ver]}
|
||||
|
||||
here = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
@ -23,13 +38,35 @@ f = open(os.path.join(here, 'docs', 'news.txt'))
|
||||
long_description += "\n\n" + f.read()
|
||||
f.close()
|
||||
|
||||
setup(name='virtualenv',
|
||||
# If you change the version here, change it in virtualenv.py and
|
||||
# docs/conf.py as well
|
||||
version="1.7.1.2",
|
||||
description="Virtual Python Environment builder",
|
||||
long_description=long_description,
|
||||
classifiers=[
|
||||
|
||||
def get_version():
|
||||
f = open(os.path.join(here, 'virtualenv.py'))
|
||||
version_file = f.read()
|
||||
f.close()
|
||||
version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]",
|
||||
version_file, re.M)
|
||||
if version_match:
|
||||
return version_match.group(1)
|
||||
raise RuntimeError("Unable to find version string.")
|
||||
|
||||
|
||||
# Hack to prevent stupid TypeError: 'NoneType' object is not callable error on
|
||||
# exit of python setup.py test # in multiprocessing/util.py _exit_function when
|
||||
# running python setup.py test (see
|
||||
# http://www.eby-sarna.com/pipermail/peak/2010-May/003357.html)
|
||||
try:
|
||||
import multiprocessing
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
setup(
|
||||
name='virtualenv',
|
||||
# If you change the version here, change it in virtualenv.py and
|
||||
# docs/conf.py as well
|
||||
version=get_version(),
|
||||
description="Virtual Python Environment builder",
|
||||
long_description=long_description,
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
'Intended Audience :: Developers',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
@ -41,18 +78,15 @@ setup(name='virtualenv',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.1',
|
||||
'Programming Language :: Python :: 3.2',
|
||||
],
|
||||
keywords='setuptools deployment installation distutils',
|
||||
author='Ian Bicking',
|
||||
author_email='ianb@colorstudy.com',
|
||||
maintainer='Jannis Leidel, Carl Meyer and Brian Rosner',
|
||||
maintainer_email='python-virtualenv@groups.google.com',
|
||||
url='http://www.virtualenv.org',
|
||||
license='MIT',
|
||||
py_modules=['virtualenv'],
|
||||
packages=['virtualenv_support'],
|
||||
package_data={'virtualenv_support': ['*-py%s.egg' % sys.version[:3], '*.tar.gz']},
|
||||
test_suite='nose.collector',
|
||||
tests_require=['nose', 'Mock'],
|
||||
**kw
|
||||
)
|
||||
],
|
||||
keywords='setuptools deployment installation distutils',
|
||||
author='Ian Bicking',
|
||||
author_email='ianb@colorstudy.com',
|
||||
maintainer='Jannis Leidel, Carl Meyer and Brian Rosner',
|
||||
maintainer_email='python-virtualenv@groups.google.com',
|
||||
url='http://www.virtualenv.org',
|
||||
license='MIT',
|
||||
py_modules=['virtualenv'],
|
||||
packages=['virtualenv_support'],
|
||||
package_data={'virtualenv_support': ['*-py%s.egg' % sys.version[:3], '*.tar.gz']},
|
||||
**setup_params)
|
||||
|
@ -4,11 +4,13 @@
|
||||
|
||||
# If you change the version here, change it in setup.py
|
||||
# and docs/conf.py as well.
|
||||
virtualenv_version = "1.7.1.2"
|
||||
__version__ = "1.7.2" # following best practices
|
||||
virtualenv_version = __version__ # legacy, again
|
||||
|
||||
import base64
|
||||
import sys
|
||||
import os
|
||||
import codecs
|
||||
import optparse
|
||||
import re
|
||||
import shutil
|
||||
@ -18,6 +20,7 @@ import zlib
|
||||
import errno
|
||||
import distutils.sysconfig
|
||||
from distutils.util import strtobool
|
||||
import struct
|
||||
|
||||
try:
|
||||
import subprocess
|
||||
@ -443,7 +446,7 @@ def writefile(dest, content, overwrite=True):
|
||||
f = open(dest, 'rb')
|
||||
c = f.read()
|
||||
f.close()
|
||||
if c != content:
|
||||
if c != content.encode("utf-8"):
|
||||
if not overwrite:
|
||||
logger.notify('File %s exists with different content; not overwriting', dest)
|
||||
return
|
||||
@ -487,7 +490,7 @@ def _install_req(py_executable, unzip=False, distribute=False,
|
||||
source = None
|
||||
else:
|
||||
setup_fn = None
|
||||
source = 'distribute-0.6.24.tar.gz'
|
||||
source = 'distribute-0.6.27.tar.gz'
|
||||
project_name = 'distribute'
|
||||
bootstrap_script = DISTRIBUTE_SETUP_PY
|
||||
|
||||
@ -568,6 +571,8 @@ def _install_req(py_executable, unzip=False, distribute=False,
|
||||
finally:
|
||||
logger.indent -= 2
|
||||
logger.end_progress()
|
||||
if cwd is not None:
|
||||
shutil.rmtree(cwd)
|
||||
if os.getcwd() != old_chdir:
|
||||
os.chdir(old_chdir)
|
||||
if is_jython and os._name == 'nt':
|
||||
@ -616,9 +621,18 @@ def install_pip(py_executable, search_dirs=None, never_download=False):
|
||||
easy_install_script = 'easy_install'
|
||||
if sys.platform == 'win32':
|
||||
easy_install_script = 'easy_install-script.py'
|
||||
cmd = [join(os.path.dirname(py_executable), easy_install_script), filename]
|
||||
if sys.platform == 'win32':
|
||||
cmd.insert(0, py_executable)
|
||||
# There's two subtle issues here when invoking easy_install.
|
||||
# 1. On unix-like systems the easy_install script can *only* be executed
|
||||
# directly if its full filesystem path is no longer than 78 characters.
|
||||
# 2. A work around to [1] is to use the `python path/to/easy_install foo`
|
||||
# pattern, but that breaks if the path contains non-ASCII characters, as
|
||||
# you can't put the file encoding declaration before the shebang line.
|
||||
# The solution is to use Python's -x flag to skip the first line of the
|
||||
# script (and any ASCII decoding errors that may have occurred in that line)
|
||||
cmd = [py_executable, '-x', join(os.path.dirname(py_executable), easy_install_script), filename]
|
||||
# jython and pypy don't yet support -x
|
||||
if is_jython or is_pypy:
|
||||
cmd.remove('-x')
|
||||
if filename == 'pip':
|
||||
if never_download:
|
||||
logger.fatal("Can't find any local distributions of pip to install "
|
||||
@ -754,7 +768,7 @@ class ConfigOptionParser(optparse.OptionParser):
|
||||
# Old, pre-Optik 1.5 behaviour.
|
||||
return optparse.Values(self.defaults)
|
||||
|
||||
defaults = self.update_defaults(self.defaults.copy()) # ours
|
||||
defaults = self.update_defaults(self.defaults.copy()) # ours
|
||||
for option in self._get_all_options():
|
||||
default = defaults.get(option.dest)
|
||||
if isinstance(default, basestring):
|
||||
@ -797,12 +811,13 @@ def main():
|
||||
action='store_true',
|
||||
help="Clear out the non-root install and start from scratch")
|
||||
|
||||
parser.set_defaults(system_site_packages=False)
|
||||
parser.add_option(
|
||||
'--no-site-packages',
|
||||
dest='no_site_packages',
|
||||
action='store_true',
|
||||
dest='system_site_packages',
|
||||
action='store_false',
|
||||
help="Don't give access to the global site-packages dir to the "
|
||||
"virtual environment")
|
||||
"virtual environment (default)")
|
||||
|
||||
parser.add_option(
|
||||
'--system-site-packages',
|
||||
@ -825,7 +840,7 @@ def main():
|
||||
'This fixes up scripts and makes all .pth files relative')
|
||||
|
||||
parser.add_option(
|
||||
'--distribute',
|
||||
'--distribute', '--use-distribute', # the second option is for legacy reasons here. Hi Kenneth!
|
||||
dest='use_distribute',
|
||||
action='store_true',
|
||||
help='Use Distribute instead of Setuptools. Set environ variable '
|
||||
@ -848,7 +863,7 @@ def main():
|
||||
"if local distributions of setuptools/distribute/pip are not present.")
|
||||
|
||||
parser.add_option(
|
||||
'--prompt=',
|
||||
'--prompt',
|
||||
dest='prompt',
|
||||
help='Provides an alternative prompt prefix for this environment')
|
||||
|
||||
@ -863,7 +878,7 @@ def main():
|
||||
adjust_options(options, args)
|
||||
|
||||
verbosity = options.verbose - options.quiet
|
||||
logger = Logger([(Logger.level_for_integer(2-verbosity), sys.stdout)])
|
||||
logger = Logger([(Logger.level_for_integer(2 - verbosity), sys.stdout)])
|
||||
|
||||
if options.python and not os.environ.get('VIRTUALENV_INTERPRETER_RUNNING'):
|
||||
env = os.environ.copy()
|
||||
@ -914,10 +929,6 @@ def main():
|
||||
make_environment_relocatable(home_dir)
|
||||
return
|
||||
|
||||
if options.no_site_packages:
|
||||
logger.warn('The --no-site-packages flag is deprecated; it is now '
|
||||
'the default behavior.')
|
||||
|
||||
create_environment(home_dir,
|
||||
site_packages=options.system_site_packages,
|
||||
clear=options.clear,
|
||||
@ -1030,9 +1041,7 @@ def create_environment(home_dir, site_packages=False, clear=False,
|
||||
|
||||
install_distutils(home_dir)
|
||||
|
||||
# use_distribute also is True if VIRTUALENV_DISTRIBUTE env var is set
|
||||
# we also check VIRTUALENV_USE_DISTRIBUTE for backwards compatibility
|
||||
if use_distribute or os.environ.get('VIRTUALENV_USE_DISTRIBUTE'):
|
||||
if use_distribute:
|
||||
install_distribute(py_executable, unzip=unzip_setuptools,
|
||||
search_dirs=search_dirs, never_download=never_download)
|
||||
else:
|
||||
@ -1065,7 +1074,7 @@ def path_locations(home_dir):
|
||||
lib_dir = join(home_dir, 'Lib')
|
||||
inc_dir = join(home_dir, 'Include')
|
||||
bin_dir = join(home_dir, 'Scripts')
|
||||
elif is_jython:
|
||||
if is_jython:
|
||||
lib_dir = join(home_dir, 'Lib')
|
||||
inc_dir = join(home_dir, 'Include')
|
||||
bin_dir = join(home_dir, 'bin')
|
||||
@ -1073,7 +1082,7 @@ def path_locations(home_dir):
|
||||
lib_dir = home_dir
|
||||
inc_dir = join(home_dir, 'include')
|
||||
bin_dir = join(home_dir, 'bin')
|
||||
else:
|
||||
elif sys.platform != 'win32':
|
||||
lib_dir = join(home_dir, 'lib', py_version)
|
||||
inc_dir = join(home_dir, 'include', py_version + abiflags)
|
||||
bin_dir = join(home_dir, 'bin')
|
||||
@ -1096,8 +1105,9 @@ def change_prefix(filename, dst_prefix):
|
||||
for src_prefix in prefixes:
|
||||
if filename.startswith(src_prefix):
|
||||
_, relpath = filename.split(src_prefix, 1)
|
||||
assert relpath[0] == os.sep
|
||||
relpath = relpath[1:]
|
||||
if src_prefix != os.sep: # sys.prefix == "/"
|
||||
assert relpath[0] == os.sep
|
||||
relpath = relpath[1:]
|
||||
return join(dst_prefix, relpath)
|
||||
assert False, "Filename %s does not start with any of these prefixes: %s" % \
|
||||
(filename, prefixes)
|
||||
@ -1250,7 +1260,7 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
|
||||
if os.path.exists(pyd_pth):
|
||||
logger.info('Deleting %s (not Windows env or not build directory python)' % pyd_pth)
|
||||
os.unlink(pyd_pth)
|
||||
|
||||
|
||||
if sys.executable != py_executable:
|
||||
## FIXME: could I just hard link?
|
||||
executable = sys.executable
|
||||
@ -1295,9 +1305,17 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
|
||||
if is_pypy:
|
||||
# make a symlink python --> pypy-c
|
||||
python_executable = os.path.join(os.path.dirname(py_executable), 'python')
|
||||
if sys.platform in ('win32', 'cygwin'):
|
||||
python_executable += '.exe'
|
||||
logger.info('Also created executable %s' % python_executable)
|
||||
copyfile(py_executable, python_executable)
|
||||
|
||||
if sys.platform == 'win32':
|
||||
for name in 'libexpat.dll', 'libpypy.dll', 'libpypy-c.dll', 'libeay32.dll', 'ssleay32.dll', 'sqlite.dll':
|
||||
src = join(prefix, name)
|
||||
if os.path.exists(src):
|
||||
copyfile(src, join(bin_dir, name))
|
||||
|
||||
if os.path.splitext(os.path.basename(py_executable))[0] != expected_exe:
|
||||
secondary_exe = os.path.join(os.path.dirname(py_executable),
|
||||
expected_exe)
|
||||
@ -1340,15 +1358,23 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
|
||||
|
||||
# And then change the install_name of the copied python executable
|
||||
try:
|
||||
call_subprocess(
|
||||
["install_name_tool", "-change",
|
||||
os.path.join(prefix, 'Python'),
|
||||
'@executable_path/../.Python',
|
||||
py_executable])
|
||||
mach_o_change(py_executable,
|
||||
os.path.join(prefix, 'Python'),
|
||||
'@executable_path/../.Python')
|
||||
except:
|
||||
logger.fatal(
|
||||
"Could not call install_name_tool -- you must have Apple's development tools installed")
|
||||
raise
|
||||
e = sys.exc_info()[1]
|
||||
logger.warn("Could not call mach_o_change: %s. "
|
||||
"Trying to call install_name_tool instead." % e)
|
||||
try:
|
||||
call_subprocess(
|
||||
["install_name_tool", "-change",
|
||||
os.path.join(prefix, 'Python'),
|
||||
'@executable_path/../.Python',
|
||||
py_executable])
|
||||
except:
|
||||
logger.fatal("Could not call install_name_tool -- you must "
|
||||
"have Apple's development tools installed")
|
||||
raise
|
||||
|
||||
# Some tools depend on pythonX.Y being present
|
||||
py_executable_version = '%s.%s' % (
|
||||
@ -1372,17 +1398,9 @@ def install_python(home_dir, lib_dir, inc_dir, bin_dir, site_packages, clear):
|
||||
# argument that has a space in it. Instead we have to quote
|
||||
# the value:
|
||||
py_executable = '"%s"' % py_executable
|
||||
cmd = [py_executable, '-c', """
|
||||
import sys
|
||||
prefix = sys.prefix
|
||||
if sys.version_info[0] == 3:
|
||||
prefix = prefix.encode('utf8')
|
||||
if hasattr(sys.stdout, 'detach'):
|
||||
sys.stdout = sys.stdout.detach()
|
||||
elif hasattr(sys.stdout, 'buffer'):
|
||||
sys.stdout = sys.stdout.buffer
|
||||
sys.stdout.write(prefix)
|
||||
"""]
|
||||
# NOTE: keep this check as one line, cmd.exe doesn't cope with line breaks
|
||||
cmd = [py_executable, '-c', 'import sys;out=sys.stdout;'
|
||||
'getattr(out, "buffer", out).write(sys.prefix.encode("utf-8"))']
|
||||
logger.info('Testing executable with %s %s "%s"' % tuple(cmd))
|
||||
try:
|
||||
proc = subprocess.Popen(cmd,
|
||||
@ -1394,7 +1412,7 @@ sys.stdout.write(prefix)
|
||||
logger.fatal('ERROR: The executable %s could not be run: %s' % (py_executable, e))
|
||||
sys.exit(100)
|
||||
else:
|
||||
raise e
|
||||
raise e
|
||||
|
||||
proc_stdout = proc_stdout.strip().decode("utf-8")
|
||||
proc_stdout = os.path.normcase(os.path.abspath(proc_stdout))
|
||||
@ -1430,6 +1448,7 @@ sys.stdout.write(prefix)
|
||||
|
||||
return py_executable
|
||||
|
||||
|
||||
def install_activate(home_dir, bin_dir, prompt=None):
|
||||
home_dir = os.path.abspath(home_dir)
|
||||
if sys.platform == 'win32' or is_jython and os._name == 'nt':
|
||||
@ -1444,7 +1463,7 @@ def install_activate(home_dir, bin_dir, prompt=None):
|
||||
home_dir_msys = (drive and "/%s%s" or "%s%s") % (drive[:1], tail)
|
||||
|
||||
# Run-time conditional enables (basic) Cygwin compatibility
|
||||
home_dir_sh = ("""$(if [ "$OSTYPE" "==" "cygwin" ]; then cygpath -u '%s'; else echo '%s'; fi;)""" %
|
||||
home_dir_sh = ("""$(if [ "$OSTYPE" "==" "cygwin" ]; then cygpath -u '%s'; else echo '%s'; fi;)""" %
|
||||
(home_dir, home_dir_msys))
|
||||
files['activate'] = ACTIVATE_SH.replace('__VIRTUAL_ENV__', home_dir_sh)
|
||||
|
||||
@ -1658,7 +1677,7 @@ def fixup_pth_file(filename):
|
||||
|
||||
def fixup_egg_link(filename):
|
||||
f = open(filename)
|
||||
link = f.read().strip()
|
||||
link = f.readline().strip()
|
||||
f.close()
|
||||
if os.path.abspath(link) != link:
|
||||
logger.debug('Link in %s already relative' % filename)
|
||||
@ -1750,7 +1769,7 @@ def create_bootstrap_script(extra_text, python_version=''):
|
||||
filename = __file__
|
||||
if filename.endswith('.pyc'):
|
||||
filename = filename[:-1]
|
||||
f = open(filename, 'rb')
|
||||
f = codecs.open(filename, 'r', encoding='utf-8')
|
||||
content = f.read()
|
||||
f.close()
|
||||
py_exe = 'python%s' % python_version
|
||||
@ -1852,57 +1871,57 @@ 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
|
||||
Q7wQmAIMcman2gOwRiH4P2ts6wE=
|
||||
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
|
||||
YAowyJmdag/AGoXg/wBaZusT
|
||||
""")
|
||||
|
||||
##file ez_setup.py
|
||||
@ -1978,139 +1997,139 @@ BDaonX65d/fwEjNqlDjLVIvM9X+XVxF7
|
||||
|
||||
##file distribute_setup.py
|
||||
DISTRIBUTE_SETUP_PY = convert("""
|
||||
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
|
||||
""")
|
||||
|
||||
##file activate.sh
|
||||
ACTIVATE_SH = convert("""
|
||||
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
|
||||
9f8c6P8+zPcNcszYX1+tk3g=
|
||||
""")
|
||||
|
||||
##file activate.fish
|
||||
ACTIVATE_FISH = convert("""
|
||||
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
|
||||
""")
|
||||
|
||||
##file activate.csh
|
||||
ACTIVATE_CSH = convert("""
|
||||
eJx9U11vmzAUffevOCVRu+UB9pws29Kl0iq1aVWllaZlcgxciiViItsQdb9+xiQp+dh4QOB7Pu49
|
||||
XHqY59IgkwVhVRmLmFAZSrGRNkdgykonhFiqSCRW1sJSmJg8wCDT5QrucRCyHn6WFRKhVGmhKwVp
|
||||
kUpNiS3emup3TY6XIn7DVNQyJUwlrgthJD6n/iCNv72uhCzCpFx9CRkThRQGKe08cWXJ9db/yh/u
|
||||
pvzl9mn+PLnjj5P5D1yM8QmXlzBkSdXwZ0H/BBc0mEo5FE5qI2jKhclHOOvy9HD/OO/6YO1mX9vx
|
||||
sY0H/tPIV0dtqel0V7iZvWyNg8XFcBA0ToEqVeqOdNUEQFvN41SumAv32VtJrakQNSmLWmgp4oJM
|
||||
yDoBHgoydtoEAs47r5wHHnUal5vbJ8oOI+9wI86vb2d8Nrm/4Xy4RZ8R85E4uTZPB5EZPnTaaAGu
|
||||
E59J8BE2J8XgrkbLeXMlVoQxznEYFYY8uFFdxsKQRx90Giwx9vSueHP1YNaUSFG4vTaErNSYuBOF
|
||||
lXiVyXa9Sy3JdClEyK1dD6Nos9mEf8iKlOpmqSNTZnYjNEWiUYn2pKNB3ttcLJ3HmYYXy6Un76f7
|
||||
r8rRsC1TpTJj7f19m5sUf/V3Ir+x/yjtLu8KjLX/CmN/AcVGUUo=
|
||||
eJx9U11v2jAUffevOA2o3ZBG9gxjGx2VVqmlVUUrTWMyTnLTWEocZDsg+uvnOEDDx5aHKLn3fFyf
|
||||
3HQwy6RBKnNCURmLiFAZSrCWNkNgykrHhEiqUMRWroSlfmyyAL1UlwXcY6/POvhVVoiFUqWFrhSk
|
||||
RSI1xTbf1N0fmhwvQbTBRKxkQphIXOfCSHxJfCGJvr8WQub9uCy+9hkTuRQGCe08cWXJzdb9xh/u
|
||||
Jvzl9mn2PL7jj+PZT1yM8BmXlzBkSa3ga0H3BBfUmEo5FE56Q2jKhMmGOOvy9HD/OGv7YOnOvrSj
|
||||
YxsP/KeR7w6bVj3prnEzfdkaB/OLQS+onQJVqsSVdFUHQFvNk1Ra1eUmKeMr5tJ+9t5Sa8rFipTF
|
||||
SmgpopxMn7W4hw6MnU6FgPPWK+eBR53m54LwEbPDb9Dihpxf3075dHx/w/lgiz4j5jNyck3ADiJT
|
||||
fGiN0QDcJD6k4CNsRorBXbWW8+ZKFIQRznEY5YY8uFZdRMKQRx9MGiww8vS2eH11YJYUS5G7RTeE
|
||||
tNQYu4pCIV5lvN33UksybQoRMmuXgzBcr9f9N7IioVW95aEpU7sWmkJRq4R70tFB3secL5zHmYHn
|
||||
i4Un70/3X5WjwzZMlciUNff39a5T/N3difzB/qM0y71r7H5Wv4DubrNS4VPRvDPW/FmM/QUd6WEa
|
||||
""")
|
||||
|
||||
##file activate.bat
|
||||
@ -2221,28 +2240,27 @@ QastYw==
|
||||
|
||||
##file distutils-init.py
|
||||
DISTUTILS_INIT = convert("""
|
||||
eJytV92L4zYQf/dfMU0ottuse7RvC6FQrg8Lxz2Ugz4si9HacqKuIxlJ2ST313dG8odkO9d7aGBB
|
||||
luZLv/nNjFacOqUtKJMIvzK3cXlhWgp5MDBsqK5SNYftsBAGpLLA4F1oe2Ytl+9wUvW55TswCi4c
|
||||
KibhbFDSglXQCFmDPXIwtm7FawLRbwtPzg2T9gf4gupKv4GS0N262w7V0NvpbCy8cvTo3eAus6C5
|
||||
ETU3ICQZX1hFTw/dzR6V/AW1RCN4/XAtbsVXqIXmlVX6liS4lOzEYY9QFB2zx6LfoSNjz1a0pqT9
|
||||
QOIfJWQ2E888NEVZNqLlZZnvIB0NpHkimlFdKn2iRRY7yGG/CCJb6Iz280d34SFXBS2yEYPNF0Q7
|
||||
yM7oCjpWvbEDQmnhRwOs6zjThpKE8HogwRAgraqYFZgGZvzmzVh+mgz9vskT3hruwyjdFcqyENJw
|
||||
bbMPO5jdzonxK68QKT7B57CMRRG5shRSWDTX3dI8LzRndZbnSWL1zfvriUmK4TcGWSnZiEPCrxXv
|
||||
bM+sP7VW2is2WgWXCO3sAu3Rzysz3FiNCA8WPyM4gb1JAAmCiyTZbhFjWx3h9SzauuRXC9MFoVbc
|
||||
yNTCm1QXOOIfIn/g1kGMhDUBN72hI5XCBQtIXQw8UEEdma6Jaz4vJIJ51Orc15hzzmu6TdFp3ogr
|
||||
Aof0c98tsw1SiaiWotHffk3XYCkqdToxWRfTFXqgpg2khcLluOHMVC0zZhLKIomesfSreUNNgbXi
|
||||
Ky9VRzwzkBneNoGQyyvGjbsFQqOZvpWIjqH281lJ/jireFgR3cPzSyTGWzQpDNIU+03Fs4XKLkhp
|
||||
/n0uFnuF6VphB44b3uWRneSbBoMSioqE8oeF0JY+qTvYfEK+bPLYdoR4McfYQ7wMZj39q0kfP8q+
|
||||
FfsymO0GzNlPh644Jje06ulqHpOEQqdJUfoidI2O4CWx4qOglLye6RrFQirpCRXvhoRqXH3sYdVJ
|
||||
AItvc+VUsLO2v2hVAWrNIfVGtkG351cUMNncbh/WdowtSPtCdkzYFv6mwYc9o2Jt68ud6wectBr8
|
||||
hYAulPSlgzH44YbV3ikjrulEaNJxt+/H3wZ7bXSXje/YY4tfVVrVmUstaDwwOBLMg6iduDB0lMVC
|
||||
UyzYx7Ab4kjCqdViEJmDcdk/SKbgsjYXgfMznUWcrtS4z4fmJ/XOM1LPk/iIpqass5XwNbdnLb1Y
|
||||
8h3ERXSWZI6rZJxKs1LBqVH65w0Oy4ra0CBYxEeuOMbDmV5GI6E0Ha/wgVTtkX0+OXvqsD02CKLf
|
||||
XHbeft85D7tTCMYy2Njp4DJP7gWJr6paVWXZ1+/6YXLv/iE0M90FktiI7yFJD9e7SOLhEkkaMTUO
|
||||
azq9i2woBNR0/0eoF1HFMf0H8ChxH/jgcB34GZIz3Qn4/vid+VEamQrOVqAPTrOfmD4MPdVh09tb
|
||||
8dLLjvh/61lEP4yW5vJaH4vHcevG8agXvzPGoOhhXNncpTr99PTHx6e/UvffFLaxUSjuSeP286Dw
|
||||
gtEMcW1xKr/he4/6IQ6FUXP+0gkioHY5iwC9Eyx3HKO7af0zPPe+XyLn7fAY78k4aiR387bCr5XT
|
||||
5C4rFgwLGfMvJuAMew==
|
||||
eJytV92L4zYQf9dfMU0ottuse7RvC6FQrg8Lxz2Ugz4si9HacqKuIxlJ2ST313fG8odkO9d7qGFB
|
||||
keZLv/nNjFaeWm0caMukX9nbuLxwo6Q6WBg2dFvqSsB2WEgLSjvg8C6NO/NGqHc46erciB1YDRcB
|
||||
JVdwtijpwGmoparAHQVYVzXylUH0beGpc8OV+wG+oLo2b6AVtLf2tkM19HY6WwevAj16N7jLHRhh
|
||||
ZSUsSEXGF1bR00N7c0etfkEtWUtRPVzzW/4VKmlE6bS5MYZLxU8C9ghF3nJ3zPsdOrLu7GRjC9oP
|
||||
JP7RUqUz8dRDkxdFLRtRFNkOktFAkjFZj+pKmxMt0thBBvtFEOlCZ7SfPXYXHnKV0yIdMdh8QbSD
|
||||
7IyuoOXlGz8glA5+tMDbVnBjKUkIrwcSLAHS6JI7iWng1m/erBOnydDvm4yJxgofRtFdoShyqaww
|
||||
Lv2wg9ntOjFxFSUiJSb4OixjUUSuKKSSDs21tyTLciN4lWYZY7XRQQjQ05M2dhRgqVUtD4w5c/Nh
|
||||
vXIrrDMIEBPXUrQOPuPd/jRGm7kA5hcXjG23CJErj/B6lk1ViKuDKT6otLAqcfCm9AWO+IfAHYTr
|
||||
EEK+2YBa3tCRmHxB/uuLhQeqhyM3FVHFw0oimAajz32JdM5FRdfJWyNqecV7I3u63w13NTKBmJKg
|
||||
0d9+Tfw1YlzyUp9OXFX5dIUeqWkDs6pxOW50ZsqGWzsJpZFETzj6KlFTTfNGfhWFbokmFlIrmjoQ
|
||||
oo/ixt0coTHc3ApEx1L3+KyVeJwVLKyI7uH5JRITDZqUFlmG7aIU6UJlF6Q0+z4Xi73cto10A0Wt
|
||||
aLPIDvumwaACIo5T/pDHTeGTuoPNJ+TLJottR4jnc4w9xMtg1tO/mvTxR9F3Ul8Gs92AOfvpsCuO
|
||||
yQ2terraR8YodGr0ha/Crk8RvCSWf5SUktczXSNfSLGeUPFuSKi6q489rDoJYPFdqpgKdta1F50m
|
||||
QK0+JN7INmjW4ooCNp3b7cPajrEFaV/Ijgnbwt80t7BnlLxpfLkL84CD0oC/ENCFWF86GIOfTVjt
|
||||
rbbymkyEJp3u9v302mCrjO6y8Q137NCrSqs6c6kFjQcGR4JZEHUnLi0dpbHQFAv2MeyGOFFw6DQY
|
||||
RNrBuOwfJJMLVdmLxPGXzCJOVmrc58OIk34XKalnLD6ioaeqdCV8I9zZKC/GvoO4iM6SzHGVjGNp
|
||||
Vio4NQr/OsFZV1IbGgTz+KgrjvFwppfSSChsK0p835R7ZJ9Pzp46bI8Ngug3l5233++ch90pBGMZ
|
||||
bOx0cJmxe0Hio6jSZVH09bt+yO7dP4RmprtAEhvxPSTp3XkXSTxcIkkjpsJhTad3kQ2FgJru/wj1
|
||||
Iqo4pv8AHiXuAx8crgM/Q3KmOwHfH79zP0ojU8HZCvTBafoTN4ehp3bY9PZWvPSyI/7fehbRh9HS
|
||||
XF7rY/E4brpxPOrF74wxKHrXli7rUp18evrj49NfSffPELaxUSjuSeP286DwgtEMcW1xKr/he4/6
|
||||
IQ6FUXP+0gkioHY5iwC9Eyx3HKO7af0zPPe+XyLnZDUk46jB7uZthV8rp+wuKxYMCxnzL9Vk9s4=
|
||||
""")
|
||||
|
||||
##file distutils.cfg
|
||||
@ -2266,6 +2284,145 @@ YdN2dEngUlbC4PG60M1WEN0piu7Nq7on0mgyyUw3iV1etLo6r/81biWdQ9MWHFaePWZYaq+nmp+t
|
||||
s3az+sj7eA0jfgPfeoN1
|
||||
""")
|
||||
|
||||
MH_MAGIC = 0xfeedface
|
||||
MH_CIGAM = 0xcefaedfe
|
||||
MH_MAGIC_64 = 0xfeedfacf
|
||||
MH_CIGAM_64 = 0xcffaedfe
|
||||
FAT_MAGIC = 0xcafebabe
|
||||
BIG_ENDIAN = '>'
|
||||
LITTLE_ENDIAN = '<'
|
||||
LC_LOAD_DYLIB = 0xc
|
||||
maxint = majver == 3 and getattr(sys, 'maxsize') or getattr(sys, 'maxint')
|
||||
|
||||
|
||||
class fileview(object):
|
||||
"""
|
||||
A proxy for file-like objects that exposes a given view of a file.
|
||||
Modified from macholib.
|
||||
"""
|
||||
|
||||
def __init__(self, fileobj, start=0, size=maxint):
|
||||
if isinstance(fileobj, fileview):
|
||||
self._fileobj = fileobj._fileobj
|
||||
else:
|
||||
self._fileobj = fileobj
|
||||
self._start = start
|
||||
self._end = start + size
|
||||
self._pos = 0
|
||||
|
||||
def __repr__(self):
|
||||
return '<fileview [%d, %d] %r>' % (
|
||||
self._start, self._end, self._fileobj)
|
||||
|
||||
def tell(self):
|
||||
return self._pos
|
||||
|
||||
def _checkwindow(self, seekto, op):
|
||||
if not (self._start <= seekto <= self._end):
|
||||
raise IOError("%s to offset %d is outside window [%d, %d]" % (
|
||||
op, seekto, self._start, self._end))
|
||||
|
||||
def seek(self, offset, whence=0):
|
||||
seekto = offset
|
||||
if whence == os.SEEK_SET:
|
||||
seekto += self._start
|
||||
elif whence == os.SEEK_CUR:
|
||||
seekto += self._start + self._pos
|
||||
elif whence == os.SEEK_END:
|
||||
seekto += self._end
|
||||
else:
|
||||
raise IOError("Invalid whence argument to seek: %r" % (whence,))
|
||||
self._checkwindow(seekto, 'seek')
|
||||
self._fileobj.seek(seekto)
|
||||
self._pos = seekto - self._start
|
||||
|
||||
def write(self, bytes):
|
||||
here = self._start + self._pos
|
||||
self._checkwindow(here, 'write')
|
||||
self._checkwindow(here + len(bytes), 'write')
|
||||
self._fileobj.seek(here, os.SEEK_SET)
|
||||
self._fileobj.write(bytes)
|
||||
self._pos += len(bytes)
|
||||
|
||||
def read(self, size=maxint):
|
||||
assert size >= 0
|
||||
here = self._start + self._pos
|
||||
self._checkwindow(here, 'read')
|
||||
size = min(size, self._end - here)
|
||||
self._fileobj.seek(here, os.SEEK_SET)
|
||||
bytes = self._fileobj.read(size)
|
||||
self._pos += len(bytes)
|
||||
return bytes
|
||||
|
||||
|
||||
def read_data(file, endian, num=1):
|
||||
"""
|
||||
Read a given number of 32-bits unsigned integers from the given file
|
||||
with the given endianness.
|
||||
"""
|
||||
res = struct.unpack(endian + 'L' * num, file.read(num * 4))
|
||||
if len(res) == 1:
|
||||
return res[0]
|
||||
return res
|
||||
|
||||
|
||||
def mach_o_change(path, what, value):
|
||||
"""
|
||||
Replace a given name (what) in any LC_LOAD_DYLIB command found in
|
||||
the given binary with a new name (value), provided it's shorter.
|
||||
"""
|
||||
|
||||
def do_macho(file, bits, endian):
|
||||
# Read Mach-O header (the magic number is assumed read by the caller)
|
||||
cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = read_data(file, endian, 6)
|
||||
# 64-bits header has one more field.
|
||||
if bits == 64:
|
||||
read_data(file, endian)
|
||||
# The header is followed by ncmds commands
|
||||
for n in range(ncmds):
|
||||
where = file.tell()
|
||||
# Read command header
|
||||
cmd, cmdsize = read_data(file, endian, 2)
|
||||
if cmd == LC_LOAD_DYLIB:
|
||||
# The first data field in LC_LOAD_DYLIB commands is the
|
||||
# offset of the name, starting from the beginning of the
|
||||
# command.
|
||||
name_offset = read_data(file, endian)
|
||||
file.seek(where + name_offset, os.SEEK_SET)
|
||||
# Read the NUL terminated string
|
||||
load = file.read(cmdsize - name_offset)
|
||||
load = load[:load.index('\0')]
|
||||
# If the string is what is being replaced, overwrite it.
|
||||
if load == what:
|
||||
file.seek(where + name_offset, os.SEEK_SET)
|
||||
file.write(value + '\0')
|
||||
# Seek to the next command
|
||||
file.seek(where + cmdsize, os.SEEK_SET)
|
||||
|
||||
def do_file(file, offset=0, size=maxint):
|
||||
file = fileview(file, offset, size)
|
||||
# Read magic number
|
||||
magic = read_data(file, BIG_ENDIAN)
|
||||
if magic == FAT_MAGIC:
|
||||
# Fat binaries contain nfat_arch Mach-O binaries
|
||||
nfat_arch = read_data(file, BIG_ENDIAN)
|
||||
for n in range(nfat_arch):
|
||||
# Read arch header
|
||||
cputype, cpusubtype, offset, size, align = read_data(file, BIG_ENDIAN, 5)
|
||||
do_file(file, offset, size)
|
||||
elif magic == MH_MAGIC:
|
||||
do_macho(file, 32, BIG_ENDIAN)
|
||||
elif magic == MH_CIGAM:
|
||||
do_macho(file, 32, LITTLE_ENDIAN)
|
||||
elif magic == MH_MAGIC_64:
|
||||
do_macho(file, 64, BIG_ENDIAN)
|
||||
elif magic == MH_CIGAM_64:
|
||||
do_macho(file, 64, LITTLE_ENDIAN)
|
||||
|
||||
assert(len(what) >= len(value))
|
||||
do_file(open(path, 'r+b'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
# You cannot run it directly.
|
||||
# Created by Davide Di Blasi <davidedb@gmail.com>.
|
||||
|
||||
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate'
|
||||
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate && unalias pydoc'
|
||||
|
||||
# Unset irrelavent variables.
|
||||
deactivate nondestructive
|
||||
@ -28,5 +28,7 @@ endif
|
||||
set prompt = "[$env_name] $prompt"
|
||||
unset env_name
|
||||
|
||||
alias pydoc python -m pydoc
|
||||
|
||||
rehash
|
||||
|
||||
|
@ -11,12 +11,17 @@ function deactivate -d "Exit virtualenv and return to normal shell environment"
|
||||
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
|
||||
set -e _OLD_VIRTUAL_PYTHONHOME
|
||||
end
|
||||
|
||||
|
||||
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
|
||||
functions -e fish_prompt
|
||||
set -e _OLD_FISH_PROMPT_OVERRIDE
|
||||
. ( begin
|
||||
printf "function fish_prompt\n\t#"
|
||||
functions _old_fish_prompt
|
||||
end | psub )
|
||||
functions -e _old_fish_prompt
|
||||
end
|
||||
|
||||
|
||||
set -e VIRTUAL_ENV
|
||||
if test "$argv[1]" != "nondestructive"
|
||||
# Self destruct!
|
||||
@ -39,41 +44,31 @@ if set -q PYTHONHOME
|
||||
end
|
||||
|
||||
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
|
||||
# fish shell uses a function, instead of env vars,
|
||||
# to produce the prompt. Overriding the existing function is easy.
|
||||
# However, adding to the current prompt, instead of clobbering it,
|
||||
# is a little more work.
|
||||
set -l oldpromptfile (tempfile)
|
||||
if test $status
|
||||
# save the current fish_prompt function...
|
||||
echo "function _old_fish_prompt" >> $oldpromptfile
|
||||
echo -n \# >> $oldpromptfile
|
||||
functions fish_prompt >> $oldpromptfile
|
||||
# we've made the "_old_fish_prompt" file, source it.
|
||||
. $oldpromptfile
|
||||
rm -f $oldpromptfile
|
||||
|
||||
# fish uses a function instead of an env var to generate the prompt.
|
||||
|
||||
# save the current fish_prompt function as the function _old_fish_prompt
|
||||
. ( begin
|
||||
printf "function _old_fish_prompt\n\t#"
|
||||
functions fish_prompt
|
||||
end | psub )
|
||||
|
||||
# with the original prompt function renamed, we can override with our own.
|
||||
function fish_prompt
|
||||
# Prompt override?
|
||||
if test -n "__VIRTUAL_PROMPT__"
|
||||
# We've been given us a prompt override.
|
||||
#
|
||||
# FIXME: Unsure how to handle this *safely*. We could just eval()
|
||||
# whatever is given, but the risk is a bit much.
|
||||
echo "activate.fish: Alternative prompt prefix is not supported under fish-shell." 1>&2
|
||||
echo "activate.fish: Alter the fish_prompt in this file as needed." 1>&2
|
||||
end
|
||||
|
||||
# with the original prompt function renamed, we can override with our own.
|
||||
function fish_prompt
|
||||
set -l _checkbase (basename "$VIRTUAL_ENV")
|
||||
if test $_checkbase = "__"
|
||||
# special case for Aspen magic directories
|
||||
# see http://www.zetadev.com/software/aspen/
|
||||
printf "%s[%s]%s %s" (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal) (_old_fish_prompt)
|
||||
else
|
||||
printf "%s(%s)%s%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal) (_old_fish_prompt)
|
||||
end
|
||||
end
|
||||
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
|
||||
end
|
||||
printf "%s%s%s" "__VIRTUAL_PROMPT__" (set_color normal) (_old_fish_prompt)
|
||||
return
|
||||
end
|
||||
# ...Otherwise, prepend env
|
||||
set -l _checkbase (basename "$VIRTUAL_ENV")
|
||||
if test $_checkbase = "__"
|
||||
# special case for Aspen magic directories
|
||||
# see http://www.zetadev.com/software/aspen/
|
||||
printf "%s[%s]%s %s" (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal) (_old_fish_prompt)
|
||||
else
|
||||
printf "%s(%s)%s%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal) (_old_fish_prompt)
|
||||
end
|
||||
end
|
||||
|
||||
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
|
||||
end
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
# you cannot run it directly
|
||||
|
||||
deactivate () {
|
||||
unset pydoc
|
||||
|
||||
# reset old environment variables
|
||||
if [ -n "$_OLD_VIRTUAL_PATH" ] ; then
|
||||
PATH="$_OLD_VIRTUAL_PATH"
|
||||
@ -18,7 +20,7 @@ deactivate () {
|
||||
# be called to get it to forget past commands. Without forgetting
|
||||
# past commands the $PATH changes we made may not be respected
|
||||
if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
|
||||
hash -r
|
||||
hash -r 2>/dev/null
|
||||
fi
|
||||
|
||||
if [ -n "$_OLD_VIRTUAL_PS1" ] ; then
|
||||
@ -68,9 +70,11 @@ if [ -z "$VIRTUAL_ENV_DISABLE_PROMPT" ] ; then
|
||||
export PS1
|
||||
fi
|
||||
|
||||
alias pydoc="python -m pydoc"
|
||||
|
||||
# This should detect bash and zsh, which have a hash command that must
|
||||
# be called to get it to forget past commands. Without forgetting
|
||||
# past commands the $PATH changes we made may not be respected
|
||||
if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
|
||||
hash -r
|
||||
hash -r 2>/dev/null
|
||||
fi
|
||||
|
@ -14,6 +14,7 @@ the appropriate options to ``use_setuptools()``.
|
||||
This file can also be run as a script to install or upgrade setuptools.
|
||||
"""
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
import fnmatch
|
||||
@ -46,7 +47,7 @@ except ImportError:
|
||||
args = [quote(arg) for arg in args]
|
||||
return os.spawnl(os.P_WAIT, sys.executable, *args) == 0
|
||||
|
||||
DEFAULT_VERSION = "0.6.24"
|
||||
DEFAULT_VERSION = "0.6.27"
|
||||
DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/"
|
||||
SETUPTOOLS_FAKED_VERSION = "0.6c11"
|
||||
|
||||
@ -63,7 +64,7 @@ Description: xxx
|
||||
""" % SETUPTOOLS_FAKED_VERSION
|
||||
|
||||
|
||||
def _install(tarball):
|
||||
def _install(tarball, install_args=()):
|
||||
# extracting the tarball
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
log.warn('Extracting in %s', tmpdir)
|
||||
@ -81,11 +82,12 @@ def _install(tarball):
|
||||
|
||||
# installing
|
||||
log.warn('Installing Distribute')
|
||||
if not _python_cmd('setup.py', 'install'):
|
||||
if not _python_cmd('setup.py', 'install', *install_args):
|
||||
log.warn('Something went wrong during the installation.')
|
||||
log.warn('See the error message above.')
|
||||
finally:
|
||||
os.chdir(old_wd)
|
||||
shutil.rmtree(tmpdir)
|
||||
|
||||
|
||||
def _build_egg(egg, tarball, to_dir):
|
||||
@ -110,6 +112,7 @@ def _build_egg(egg, tarball, to_dir):
|
||||
|
||||
finally:
|
||||
os.chdir(old_wd)
|
||||
shutil.rmtree(tmpdir)
|
||||
# returning the result
|
||||
log.warn(egg)
|
||||
if not os.path.exists(egg):
|
||||
@ -306,6 +309,9 @@ def _create_fake_setuptools_pkg_info(placeholder):
|
||||
log.warn('%s already exists', pkg_info)
|
||||
return
|
||||
|
||||
if not os.access(pkg_info, os.W_OK):
|
||||
log.warn("Don't have permissions to write %s, skipping", pkg_info)
|
||||
|
||||
log.warn('Creating %s', pkg_info)
|
||||
f = open(pkg_info, 'w')
|
||||
try:
|
||||
@ -474,11 +480,20 @@ def _extractall(self, path=".", members=None):
|
||||
else:
|
||||
self._dbg(1, "tarfile: %s" % e)
|
||||
|
||||
def _build_install_args(argv):
|
||||
install_args = []
|
||||
user_install = '--user' in argv
|
||||
if user_install and sys.version_info < (2,6):
|
||||
log.warn("--user requires Python 2.6 or later")
|
||||
raise SystemExit(1)
|
||||
if user_install:
|
||||
install_args.append('--user')
|
||||
return install_args
|
||||
|
||||
def main(argv, version=DEFAULT_VERSION):
|
||||
"""Install or upgrade setuptools and EasyInstall"""
|
||||
tarball = download_setuptools()
|
||||
_install(tarball)
|
||||
_install(tarball, _build_install_args(argv))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -15,11 +15,8 @@ else:
|
||||
__path__.insert(0, distutils_path)
|
||||
exec(open(os.path.join(distutils_path, '__init__.py')).read())
|
||||
|
||||
try:
|
||||
import dist
|
||||
import sysconfig
|
||||
except ImportError:
|
||||
from distutils import dist, sysconfig
|
||||
from distutils import dist, sysconfig
|
||||
|
||||
try:
|
||||
basestring
|
||||
except NameError:
|
||||
|
@ -422,7 +422,7 @@ class _Printer(object):
|
||||
for filename in self.__files:
|
||||
filename = os.path.join(dir, filename)
|
||||
try:
|
||||
fp = file(filename, "rU")
|
||||
fp = open(filename, "rU")
|
||||
data = fp.read()
|
||||
fp.close()
|
||||
break
|
||||
@ -553,9 +553,7 @@ def virtual_install_main_packages():
|
||||
hardcoded_relative_dirs = []
|
||||
if sys.path[0] == '':
|
||||
pos += 1
|
||||
if sys.platform == 'win32':
|
||||
paths = [os.path.join(sys.real_prefix, 'Lib'), os.path.join(sys.real_prefix, 'DLLs')]
|
||||
elif _is_jython:
|
||||
if _is_jython:
|
||||
paths = [os.path.join(sys.real_prefix, 'Lib')]
|
||||
elif _is_pypy:
|
||||
if sys.pypy_version_info >= (1, 5):
|
||||
@ -572,6 +570,8 @@ def virtual_install_main_packages():
|
||||
plat_path = os.path.join(path, 'plat-%s' % sys.platform)
|
||||
if os.path.exists(plat_path):
|
||||
paths.append(plat_path)
|
||||
elif sys.platform == 'win32':
|
||||
paths = [os.path.join(sys.real_prefix, 'Lib'), os.path.join(sys.real_prefix, 'DLLs')]
|
||||
else:
|
||||
paths = [os.path.join(sys.real_prefix, 'lib', 'python'+sys.version[:3])]
|
||||
hardcoded_relative_dirs = paths[:] # for the special 'darwin' case below
|
||||
|
Binary file not shown.
Binary file not shown.
@ -89,6 +89,10 @@ DEFINES += \
|
||||
-DDLL_SUFFIX=\"$(DLL_SUFFIX)\" \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS += \
|
||||
nsNSSShutDown.h \
|
||||
$(NULL)
|
||||
|
||||
# Use local includes because they are inserted before INCLUDES
|
||||
# so that Mozilla's nss.h is used, not glibc's
|
||||
LOCAL_INCLUDES += $(NSS_CFLAGS)
|
||||
|
@ -1 +1 @@
|
||||
http://hg.mozilla.org/projects/addon-sdk/archive/041eaf6ae5fb.tar.bz2
|
||||
http://hg.mozilla.org/projects/addon-sdk/archive/8d6150ab4903.tar.bz2
|
||||
|
@ -5406,61 +5406,37 @@ nsWindow::ClientMarginHitTestPoint(PRInt32 mx, PRInt32 my)
|
||||
if (mSizeMode == nsSizeMode_Maximized)
|
||||
isResizable = false;
|
||||
|
||||
// Ensure being accessible to borders of window. Even if contents are in
|
||||
// this area, the area must behave as border.
|
||||
nsIntMargin nonClientSize(NS_MAX(mHorResizeMargin - mNonClientOffset.left,
|
||||
kResizableBorderMinSize),
|
||||
NS_MAX(mCaptionHeight - mNonClientOffset.top,
|
||||
kResizableBorderMinSize),
|
||||
NS_MAX(mHorResizeMargin - mNonClientOffset.right,
|
||||
kResizableBorderMinSize),
|
||||
NS_MAX(mVertResizeMargin - mNonClientOffset.bottom,
|
||||
kResizableBorderMinSize));
|
||||
|
||||
bool allowContentOverride = mSizeMode == nsSizeMode_Maximized ||
|
||||
(mx >= winRect.left + nonClientSize.left &&
|
||||
mx <= winRect.right - nonClientSize.right &&
|
||||
my >= winRect.top + nonClientSize.top &&
|
||||
my <= winRect.bottom - nonClientSize.bottom);
|
||||
|
||||
// The border size. If there is no content under mouse cursor, the border
|
||||
// size should be larger than the values in system settings. Otherwise,
|
||||
// contents under the mouse cursor should be able to override the behavior.
|
||||
// E.g., user must expect that Firefox button always opens the popup menu
|
||||
// even when the user clicks on the above edge of it.
|
||||
nsIntMargin borderSize(NS_MAX(nonClientSize.left, mHorResizeMargin),
|
||||
NS_MAX(nonClientSize.top, mVertResizeMargin),
|
||||
NS_MAX(nonClientSize.right, mHorResizeMargin),
|
||||
NS_MAX(nonClientSize.bottom, mVertResizeMargin));
|
||||
|
||||
bool contentMayOverlap = false;
|
||||
|
||||
bool top = false;
|
||||
bool bottom = false;
|
||||
bool left = false;
|
||||
bool right = false;
|
||||
|
||||
if (my >= winRect.top && my < winRect.top + borderSize.top) {
|
||||
top = true;
|
||||
contentMayOverlap = (my >= winRect.top + nonClientSize.top);
|
||||
} else if (my <= winRect.bottom && my > winRect.bottom - borderSize.bottom) {
|
||||
bottom = true;
|
||||
contentMayOverlap = (my <= winRect.bottom - nonClientSize.bottom);
|
||||
}
|
||||
int topOffset = NS_MAX(mCaptionHeight - mNonClientOffset.top,
|
||||
kResizableBorderMinSize);
|
||||
int bottomOffset = NS_MAX(mVertResizeMargin - mNonClientOffset.bottom,
|
||||
kResizableBorderMinSize);
|
||||
int topBounds = winRect.top + topOffset;
|
||||
int bottomBounds = winRect.bottom - bottomOffset;
|
||||
|
||||
if (my >= winRect.top && my < topBounds)
|
||||
top = true;
|
||||
else if (my <= winRect.bottom && my > bottomBounds)
|
||||
bottom = true;
|
||||
|
||||
int leftOffset = NS_MAX(mHorResizeMargin - mNonClientOffset.left,
|
||||
kResizableBorderMinSize);
|
||||
int rightOffset = NS_MAX(mHorResizeMargin - mNonClientOffset.right,
|
||||
kResizableBorderMinSize);
|
||||
// (the 2x case here doubles the resize area for corners)
|
||||
int multiplier = (top || bottom) ? 2 : 1;
|
||||
if (mx >= winRect.left &&
|
||||
mx < winRect.left + (multiplier * borderSize.left)) {
|
||||
int leftBounds = winRect.left +
|
||||
(bottom ? (2*leftOffset) : leftOffset);
|
||||
int rightBounds = winRect.right -
|
||||
(bottom ? (2*rightOffset) : rightOffset);
|
||||
|
||||
if (mx >= winRect.left && mx < leftBounds)
|
||||
left = true;
|
||||
contentMayOverlap =
|
||||
contentMayOverlap || (mx >= winRect.left + nonClientSize.left);
|
||||
} else if (mx <= winRect.right &&
|
||||
mx > winRect.right - (multiplier * borderSize.right)) {
|
||||
else if (mx <= winRect.right && mx > rightBounds)
|
||||
right = true;
|
||||
contentMayOverlap =
|
||||
contentMayOverlap || (mx <= winRect.right - nonClientSize.right);
|
||||
}
|
||||
|
||||
if (isResizable) {
|
||||
if (top) {
|
||||
@ -5488,7 +5464,22 @@ nsWindow::ClientMarginHitTestPoint(PRInt32 mx, PRInt32 my)
|
||||
testResult = HTBORDER;
|
||||
}
|
||||
|
||||
if (!sIsInMouseCapture && allowContentOverride && contentMayOverlap) {
|
||||
bool contentOverlap = true;
|
||||
|
||||
if (mSizeMode != nsSizeMode_Maximized) {
|
||||
contentOverlap = mx >= winRect.left + leftOffset &&
|
||||
mx <= winRect.right - rightOffset &&
|
||||
my >= winRect.top + topOffset &&
|
||||
my <= winRect.bottom - bottomOffset;
|
||||
}
|
||||
|
||||
if (!sIsInMouseCapture &&
|
||||
contentOverlap &&
|
||||
(testResult == HTCLIENT ||
|
||||
testResult == HTTOP ||
|
||||
testResult == HTBORDER ||
|
||||
testResult == HTTOPLEFT ||
|
||||
testResult == HTCAPTION)) {
|
||||
LPARAM lParam = MAKELPARAM(mx, my);
|
||||
LPARAM lParamClient = lParamToClient(lParam);
|
||||
bool result = DispatchMouseEvent(NS_MOUSE_MOZHITTEST, 0, lParamClient,
|
||||
|
Loading…
Reference in New Issue
Block a user