netwerk/test/TestStreamTransport.cpp

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 #include "TestCommon.h"
michael@0 6 #include "nsIComponentRegistrar.h"
michael@0 7 #include "nsIStreamTransportService.h"
michael@0 8 #include "nsIAsyncInputStream.h"
michael@0 9 #include "nsIProgressEventSink.h"
michael@0 10 #include "nsIInterfaceRequestor.h"
michael@0 11 #include "nsIInterfaceRequestorUtils.h"
michael@0 12 #include "nsIRequest.h"
michael@0 13 #include "nsIServiceManager.h"
michael@0 14 #include "nsIComponentManager.h"
michael@0 15 #include "nsCOMPtr.h"
michael@0 16 #include "nsMemory.h"
michael@0 17 #include "nsStringAPI.h"
michael@0 18 #include "nsIFileStreams.h"
michael@0 19 #include "nsIStreamListener.h"
michael@0 20 #include "nsIFile.h"
michael@0 21 #include "nsNetUtil.h"
michael@0 22 #include "nsAutoLock.h"
michael@0 23 #include "prlog.h"
michael@0 24 #include "prenv.h"
michael@0 25
michael@0 26 ////////////////////////////////////////////////////////////////////////////////
michael@0 27
michael@0 28 #if defined(PR_LOGGING)
michael@0 29 //
michael@0 30 // set NSPR_LOG_MODULES=Test:5
michael@0 31 //
michael@0 32 static PRLogModuleInfo *gTestLog = nullptr;
michael@0 33 #endif
michael@0 34 #define LOG(args) PR_LOG(gTestLog, PR_LOG_DEBUG, args)
michael@0 35
michael@0 36 ////////////////////////////////////////////////////////////////////////////////
michael@0 37
michael@0 38 static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID);
michael@0 39
michael@0 40 ////////////////////////////////////////////////////////////////////////////////
michael@0 41
michael@0 42 #define CHUNK_SIZE 500
michael@0 43
michael@0 44 class MyCopier : public nsIInputStreamCallback
michael@0 45 , public nsIOutputStreamCallback
michael@0 46 {
michael@0 47 public:
michael@0 48 NS_DECL_THREADSAFE_ISUPPORTS
michael@0 49
michael@0 50 MyCopier()
michael@0 51 : mLock(nullptr)
michael@0 52 , mInputCondition(NS_OK)
michael@0 53 {
michael@0 54 }
michael@0 55
michael@0 56 virtual ~MyCopier()
michael@0 57 {
michael@0 58 if (mLock)
michael@0 59 nsAutoLock::DestroyLock(mLock);
michael@0 60 if (mInput)
michael@0 61 mInput->Close();
michael@0 62 if (mOutput)
michael@0 63 mOutput->Close();
michael@0 64 }
michael@0 65
michael@0 66 // called on any thread
michael@0 67 NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *inStr)
michael@0 68 {
michael@0 69 LOG(("OnInputStreamReady\n"));
michael@0 70 nsAutoLock lock(mLock);
michael@0 71 NS_ASSERTION(inStr == mInput, "unexpected stream");
michael@0 72 Process_Locked();
michael@0 73 return NS_OK;
michael@0 74 }
michael@0 75
michael@0 76 // called on any thread
michael@0 77 NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *outStr)
michael@0 78 {
michael@0 79 LOG(("OnOutputStreamReady\n"));
michael@0 80 nsAutoLock lock(mLock);
michael@0 81 NS_ASSERTION(outStr == mOutput, "unexpected stream");
michael@0 82 Process_Locked();
michael@0 83 return NS_OK;
michael@0 84 }
michael@0 85
michael@0 86 void Close_Locked()
michael@0 87 {
michael@0 88 LOG(("Close_Locked\n"));
michael@0 89
michael@0 90 mOutput->Close();
michael@0 91 mOutput = 0;
michael@0 92 mInput->Close();
michael@0 93 mInput = 0;
michael@0 94
michael@0 95 // post done copying event
michael@0 96 QuitPumpingEvents();
michael@0 97 }
michael@0 98
michael@0 99 void Process_Locked()
michael@0 100 {
michael@0 101 while (1) {
michael@0 102 mInputCondition = NS_OK; // reset
michael@0 103
michael@0 104 uint32_t n;
michael@0 105 nsresult rv = mOutput->WriteSegments(FillOutputBuffer, this, CHUNK_SIZE, &n);
michael@0 106 if (NS_FAILED(rv) || (n == 0)) {
michael@0 107 if (rv == NS_BASE_STREAM_WOULD_BLOCK)
michael@0 108 mOutput->AsyncWait(this, 0, 0, nullptr);
michael@0 109 else if (mInputCondition == NS_BASE_STREAM_WOULD_BLOCK)
michael@0 110 mInput->AsyncWait(this, 0, 0, nullptr);
michael@0 111 else
michael@0 112 Close_Locked();
michael@0 113 break;
michael@0 114 }
michael@0 115 }
michael@0 116 }
michael@0 117
michael@0 118 nsresult AsyncCopy(nsITransport *srcTrans, nsITransport *destTrans)
michael@0 119 {
michael@0 120 mLock = nsAutoLock::NewLock("MyCopier::mLock");
michael@0 121 if (!mLock)
michael@0 122 return NS_ERROR_OUT_OF_MEMORY;
michael@0 123
michael@0 124 nsresult rv;
michael@0 125
michael@0 126 nsCOMPtr<nsIInputStream> inStr;
michael@0 127 rv = srcTrans->OpenInputStream(0, 0, 0, getter_AddRefs(inStr));
michael@0 128 if (NS_FAILED(rv)) return rv;
michael@0 129
michael@0 130 nsCOMPtr<nsIOutputStream> outStr;
michael@0 131 rv = destTrans->OpenOutputStream(0, 0, 0, getter_AddRefs(outStr));
michael@0 132 if (NS_FAILED(rv)) return rv;
michael@0 133
michael@0 134 mInput = do_QueryInterface(inStr);
michael@0 135 mOutput = do_QueryInterface(outStr);
michael@0 136
michael@0 137 return mInput->AsyncWait(this, 0, 0, nullptr);
michael@0 138 }
michael@0 139
michael@0 140 static NS_METHOD FillOutputBuffer(nsIOutputStream *outStr,
michael@0 141 void *closure,
michael@0 142 char *buffer,
michael@0 143 uint32_t offset,
michael@0 144 uint32_t count,
michael@0 145 uint32_t *countRead)
michael@0 146 {
michael@0 147 MyCopier *self = (MyCopier *) closure;
michael@0 148
michael@0 149 nsresult rv = self->mInput->Read(buffer, count, countRead);
michael@0 150 if (NS_FAILED(rv))
michael@0 151 self->mInputCondition = rv;
michael@0 152 else if (*countRead == 0)
michael@0 153 self->mInputCondition = NS_BASE_STREAM_CLOSED;
michael@0 154
michael@0 155 return self->mInputCondition;
michael@0 156 }
michael@0 157
michael@0 158 protected:
michael@0 159 PRLock *mLock;
michael@0 160 nsCOMPtr<nsIAsyncInputStream> mInput;
michael@0 161 nsCOMPtr<nsIAsyncOutputStream> mOutput;
michael@0 162 nsresult mInputCondition;
michael@0 163 };
michael@0 164
michael@0 165 NS_IMPL_ISUPPORTS(MyCopier,
michael@0 166 nsIInputStreamCallback,
michael@0 167 nsIOutputStreamCallback)
michael@0 168
michael@0 169 ////////////////////////////////////////////////////////////////////////////////
michael@0 170
michael@0 171 /**
michael@0 172 * asynchronously copy file.
michael@0 173 */
michael@0 174 static nsresult
michael@0 175 RunTest(nsIFile *srcFile, nsIFile *destFile)
michael@0 176 {
michael@0 177 nsresult rv;
michael@0 178
michael@0 179 LOG(("RunTest\n"));
michael@0 180
michael@0 181 nsCOMPtr<nsIStreamTransportService> sts =
michael@0 182 do_GetService(kStreamTransportServiceCID, &rv);
michael@0 183 if (NS_FAILED(rv)) return rv;
michael@0 184
michael@0 185 nsCOMPtr<nsIInputStream> srcStr;
michael@0 186 rv = NS_NewLocalFileInputStream(getter_AddRefs(srcStr), srcFile);
michael@0 187 if (NS_FAILED(rv)) return rv;
michael@0 188
michael@0 189 nsCOMPtr<nsIOutputStream> destStr;
michael@0 190 rv = NS_NewLocalFileOutputStream(getter_AddRefs(destStr), destFile);
michael@0 191 if (NS_FAILED(rv)) return rv;
michael@0 192
michael@0 193 nsCOMPtr<nsITransport> srcTransport;
michael@0 194 rv = sts->CreateInputTransport(srcStr, int64_t(-1), int64_t(-1), true,
michael@0 195 getter_AddRefs(srcTransport));
michael@0 196 if (NS_FAILED(rv)) return rv;
michael@0 197
michael@0 198 nsCOMPtr<nsITransport> destTransport;
michael@0 199 rv = sts->CreateOutputTransport(destStr, int64_t(-1), int64_t(-1), true,
michael@0 200 getter_AddRefs(destTransport));
michael@0 201 if (NS_FAILED(rv)) return rv;
michael@0 202
michael@0 203 MyCopier *copier = new MyCopier();
michael@0 204 if (copier == nullptr)
michael@0 205 return NS_ERROR_OUT_OF_MEMORY;
michael@0 206 NS_ADDREF(copier);
michael@0 207
michael@0 208 rv = copier->AsyncCopy(srcTransport, destTransport);
michael@0 209 if (NS_FAILED(rv)) return rv;
michael@0 210
michael@0 211 PumpEvents();
michael@0 212
michael@0 213 NS_RELEASE(copier);
michael@0 214 return NS_OK;
michael@0 215 }
michael@0 216
michael@0 217 ////////////////////////////////////////////////////////////////////////////////
michael@0 218
michael@0 219 static nsresult
michael@0 220 RunBlockingTest(nsIFile *srcFile, nsIFile *destFile)
michael@0 221 {
michael@0 222 nsresult rv;
michael@0 223
michael@0 224 LOG(("RunBlockingTest\n"));
michael@0 225
michael@0 226 nsCOMPtr<nsIStreamTransportService> sts =
michael@0 227 do_GetService(kStreamTransportServiceCID, &rv);
michael@0 228 if (NS_FAILED(rv)) return rv;
michael@0 229
michael@0 230 nsCOMPtr<nsIInputStream> srcIn;
michael@0 231 rv = NS_NewLocalFileInputStream(getter_AddRefs(srcIn), srcFile);
michael@0 232 if (NS_FAILED(rv)) return rv;
michael@0 233
michael@0 234 nsCOMPtr<nsIOutputStream> fileOut;
michael@0 235 rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOut), destFile);
michael@0 236 if (NS_FAILED(rv)) return rv;
michael@0 237
michael@0 238 nsCOMPtr<nsITransport> destTransport;
michael@0 239 rv = sts->CreateOutputTransport(fileOut, int64_t(-1), int64_t(-1),
michael@0 240 true, getter_AddRefs(destTransport));
michael@0 241 if (NS_FAILED(rv)) return rv;
michael@0 242
michael@0 243 nsCOMPtr<nsIOutputStream> destOut;
michael@0 244 rv = destTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING, 100, 10, getter_AddRefs(destOut));
michael@0 245 if (NS_FAILED(rv)) return rv;
michael@0 246
michael@0 247 char buf[120];
michael@0 248 uint32_t n;
michael@0 249 for (;;) {
michael@0 250 rv = srcIn->Read(buf, sizeof(buf), &n);
michael@0 251 if (NS_FAILED(rv) || (n == 0)) return rv;
michael@0 252
michael@0 253 rv = destOut->Write(buf, n, &n);
michael@0 254 if (NS_FAILED(rv)) return rv;
michael@0 255 }
michael@0 256
michael@0 257 return NS_OK;
michael@0 258 }
michael@0 259
michael@0 260 ////////////////////////////////////////////////////////////////////////////////
michael@0 261
michael@0 262 int
michael@0 263 main(int argc, char* argv[])
michael@0 264 {
michael@0 265 if (test_common_init(&argc, &argv) != 0)
michael@0 266 return -1;
michael@0 267
michael@0 268 nsresult rv;
michael@0 269
michael@0 270 if (argc < 2) {
michael@0 271 printf("usage: %s <file-to-read>\n", argv[0]);
michael@0 272 return -1;
michael@0 273 }
michael@0 274 char* fileName = argv[1];
michael@0 275 {
michael@0 276 nsCOMPtr<nsIServiceManager> servMan;
michael@0 277 NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr);
michael@0 278 nsCOMPtr<nsIComponentRegistrar> registrar = do_QueryInterface(servMan);
michael@0 279 NS_ASSERTION(registrar, "Null nsIComponentRegistrar");
michael@0 280 if (registrar)
michael@0 281 registrar->AutoRegister(nullptr);
michael@0 282
michael@0 283 #if defined(PR_LOGGING)
michael@0 284 gTestLog = PR_NewLogModule("Test");
michael@0 285 #endif
michael@0 286
michael@0 287 nsCOMPtr<nsIFile> srcFile;
michael@0 288 rv = NS_NewNativeLocalFile(nsDependentCString(fileName), false, getter_AddRefs(srcFile));
michael@0 289 if (NS_FAILED(rv)) return rv;
michael@0 290
michael@0 291 nsCOMPtr<nsIFile> destFile;
michael@0 292 rv = srcFile->Clone(getter_AddRefs(destFile));
michael@0 293 if (NS_FAILED(rv)) return rv;
michael@0 294
michael@0 295 nsAutoCString leafName;
michael@0 296 rv = destFile->GetNativeLeafName(leafName);
michael@0 297 if (NS_FAILED(rv)) return rv;
michael@0 298
michael@0 299 nsAutoCString newName(leafName);
michael@0 300 newName.Append(NS_LITERAL_CSTRING(".1"));
michael@0 301 rv = destFile->SetNativeLeafName(newName);
michael@0 302 if (NS_FAILED(rv)) return rv;
michael@0 303
michael@0 304 rv = RunTest(srcFile, destFile);
michael@0 305 NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed");
michael@0 306
michael@0 307 newName = leafName;
michael@0 308 newName.Append(NS_LITERAL_CSTRING(".2"));
michael@0 309 rv = destFile->SetNativeLeafName(newName);
michael@0 310 if (NS_FAILED(rv)) return rv;
michael@0 311
michael@0 312 rv = RunBlockingTest(srcFile, destFile);
michael@0 313 NS_ASSERTION(NS_SUCCEEDED(rv), "RunBlockingTest failed");
michael@0 314
michael@0 315 // give background threads a chance to finish whatever work they may
michael@0 316 // be doing.
michael@0 317 PR_Sleep(PR_SecondsToInterval(1));
michael@0 318 } // this scopes the nsCOMPtrs
michael@0 319 // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
michael@0 320 rv = NS_ShutdownXPCOM(nullptr);
michael@0 321 NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed");
michael@0 322 return NS_OK;
michael@0 323 }

mercurial