michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "nsDownloader.h" michael@0: #include "nsIInputStream.h" michael@0: #include "nsDirectoryServiceUtils.h" michael@0: #include "nsDirectoryServiceDefs.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsCRTGlue.h" michael@0: michael@0: nsDownloader::~nsDownloader() michael@0: { michael@0: if (mLocation && mLocationIsTemp) { michael@0: // release the sink first since it may still hold an open file michael@0: // descriptor to mLocation. this needs to happen before the michael@0: // file can be removed otherwise the Remove call will fail. michael@0: if (mSink) { michael@0: mSink->Close(); michael@0: mSink = nullptr; michael@0: } michael@0: michael@0: nsresult rv = mLocation->Remove(false); michael@0: if (NS_FAILED(rv)) michael@0: NS_ERROR("unable to remove temp file"); michael@0: } michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsDownloader, michael@0: nsIDownloader, michael@0: nsIStreamListener, michael@0: nsIRequestObserver) michael@0: michael@0: NS_IMETHODIMP michael@0: nsDownloader::Init(nsIDownloadObserver *observer, nsIFile *location) michael@0: { michael@0: mObserver = observer; michael@0: mLocation = location; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDownloader::OnStartRequest(nsIRequest *request, nsISupports *ctxt) michael@0: { michael@0: nsresult rv; michael@0: if (!mLocation) { michael@0: nsCOMPtr location; michael@0: rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(location)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: char buf[13]; michael@0: NS_MakeRandomString(buf, 8); michael@0: memcpy(buf+8, ".tmp", 5); michael@0: rv = location->AppendNative(nsDependentCString(buf, 12)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = location->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: location.swap(mLocation); michael@0: mLocationIsTemp = true; michael@0: } michael@0: michael@0: rv = NS_NewLocalFileOutputStream(getter_AddRefs(mSink), mLocation); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: // we could wrap this output stream with a buffered output stream, michael@0: // but it shouldn't be necessary since we will be writing large michael@0: // chunks given to us via OnDataAvailable. michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDownloader::OnStopRequest(nsIRequest *request, michael@0: nsISupports *ctxt, michael@0: nsresult status) michael@0: { michael@0: if (mSink) { michael@0: mSink->Close(); michael@0: mSink = nullptr; michael@0: } michael@0: michael@0: mObserver->OnDownloadComplete(this, request, ctxt, status, mLocation); michael@0: mObserver = nullptr; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_METHOD michael@0: nsDownloader::ConsumeData(nsIInputStream* in, michael@0: void* closure, michael@0: const char* fromRawSegment, michael@0: uint32_t toOffset, michael@0: uint32_t count, michael@0: uint32_t *writeCount) michael@0: { michael@0: nsDownloader *self = (nsDownloader *) closure; michael@0: if (self->mSink) michael@0: return self->mSink->Write(fromRawSegment, count, writeCount); michael@0: michael@0: *writeCount = count; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsDownloader::OnDataAvailable(nsIRequest *request, nsISupports *ctxt, michael@0: nsIInputStream *inStr, michael@0: uint64_t sourceOffset, uint32_t count) michael@0: { michael@0: uint32_t n; michael@0: return inStr->ReadSegments(ConsumeData, this, count, &n); michael@0: }