Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this
3 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #include "nsDownloader.h"
6 : #include "nsIInputStream.h"
7 : #include "nsIOutputStream.h"
8 : #include "nsDirectoryServiceUtils.h"
9 : #include "nsDirectoryServiceDefs.h"
10 : #include "nsNetUtil.h"
11 : #include "nsCRTGlue.h"
12 :
13 0 : nsDownloader::~nsDownloader()
14 : {
15 0 : if (mLocation && mLocationIsTemp) {
16 : // release the sink first since it may still hold an open file
17 : // descriptor to mLocation. this needs to happen before the
18 : // file can be removed otherwise the Remove call will fail.
19 0 : if (mSink) {
20 0 : mSink->Close();
21 0 : mSink = nullptr;
22 : }
23 :
24 0 : nsresult rv = mLocation->Remove(false);
25 0 : if (NS_FAILED(rv))
26 0 : NS_ERROR("unable to remove temp file");
27 : }
28 0 : }
29 :
30 0 : NS_IMPL_ISUPPORTS(nsDownloader,
31 : nsIDownloader,
32 : nsIStreamListener,
33 : nsIRequestObserver)
34 :
35 : NS_IMETHODIMP
36 0 : nsDownloader::Init(nsIDownloadObserver *observer, nsIFile *location)
37 : {
38 0 : mObserver = observer;
39 0 : mLocation = location;
40 0 : return NS_OK;
41 : }
42 :
43 : NS_IMETHODIMP
44 0 : nsDownloader::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
45 : {
46 : nsresult rv;
47 0 : if (!mLocation) {
48 0 : nsCOMPtr<nsIFile> location;
49 0 : rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(location));
50 0 : if (NS_FAILED(rv)) return rv;
51 :
52 : char buf[13];
53 0 : NS_MakeRandomString(buf, 8);
54 0 : memcpy(buf+8, ".tmp", 5);
55 0 : rv = location->AppendNative(nsDependentCString(buf, 12));
56 0 : if (NS_FAILED(rv)) return rv;
57 :
58 0 : rv = location->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600);
59 0 : if (NS_FAILED(rv)) return rv;
60 :
61 0 : location.swap(mLocation);
62 0 : mLocationIsTemp = true;
63 : }
64 :
65 0 : rv = NS_NewLocalFileOutputStream(getter_AddRefs(mSink), mLocation);
66 0 : if (NS_FAILED(rv)) return rv;
67 :
68 : // we could wrap this output stream with a buffered output stream,
69 : // but it shouldn't be necessary since we will be writing large
70 : // chunks given to us via OnDataAvailable.
71 :
72 0 : return NS_OK;
73 : }
74 :
75 : NS_IMETHODIMP
76 0 : nsDownloader::OnStopRequest(nsIRequest *request,
77 : nsISupports *ctxt,
78 : nsresult status)
79 : {
80 0 : if (mSink) {
81 0 : mSink->Close();
82 0 : mSink = nullptr;
83 : }
84 :
85 0 : mObserver->OnDownloadComplete(this, request, ctxt, status, mLocation);
86 0 : mObserver = nullptr;
87 :
88 0 : return NS_OK;
89 : }
90 :
91 : nsresult
92 0 : nsDownloader::ConsumeData(nsIInputStream* in,
93 : void* closure,
94 : const char* fromRawSegment,
95 : uint32_t toOffset,
96 : uint32_t count,
97 : uint32_t *writeCount)
98 : {
99 0 : nsDownloader *self = (nsDownloader *) closure;
100 0 : if (self->mSink)
101 0 : return self->mSink->Write(fromRawSegment, count, writeCount);
102 :
103 0 : *writeCount = count;
104 0 : return NS_OK;
105 : }
106 :
107 : NS_IMETHODIMP
108 0 : nsDownloader::OnDataAvailable(nsIRequest *request, nsISupports *ctxt,
109 : nsIInputStream *inStr,
110 : uint64_t sourceOffset, uint32_t count)
111 : {
112 : uint32_t n;
113 0 : return inStr->ReadSegments(ConsumeData, this, count, &n);
114 : }
|