1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  *
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef _nsCacheEntryDescriptor_h_
8 #define _nsCacheEntryDescriptor_h_
9 
10 #include "nsICacheEntryDescriptor.h"
11 #include "nsCacheEntry.h"
12 #include "nsIInputStream.h"
13 #include "nsIOutputStream.h"
14 #include "nsCacheService.h"
15 #include "zlib.h"
16 #include "mozilla/Mutex.h"
17 
18 /******************************************************************************
19  * nsCacheEntryDescriptor
20  *******************************************************************************/
21 class nsCacheEntryDescriptor final : public PRCList,
22                                      public nsICacheEntryDescriptor {
23  public:
24   NS_DECL_THREADSAFE_ISUPPORTS
25   NS_DECL_NSICACHEENTRYDESCRIPTOR
26   NS_DECL_NSICACHEENTRYINFO
27 
28   friend class nsAsyncDoomEvent;
29   friend class nsCacheService;
30 
31   nsCacheEntryDescriptor(nsCacheEntry* entry, nsCacheAccessMode mode);
32 
33   /**
34    * utility method to attempt changing data size of associated entry
35    */
36   nsresult RequestDataSizeChange(int32_t deltaSize);
37 
38   /**
39    * methods callbacks for nsCacheService
40    */
CacheEntry(void)41   nsCacheEntry* CacheEntry(void) { return mCacheEntry; }
ClearCacheEntry(void)42   bool ClearCacheEntry(void) {
43     NS_ASSERTION(mInputWrappers.IsEmpty(), "Bad state");
44     NS_ASSERTION(!mOutputWrapper, "Bad state");
45 
46     bool doomEntry = false;
47     bool asyncDoomPending;
48     {
49       mozilla::MutexAutoLock lock(mLock);
50       asyncDoomPending = mAsyncDoomPending;
51     }
52 
53     if (asyncDoomPending && mCacheEntry) {
54       doomEntry = true;
55       mDoomedOnClose = true;
56     }
57     mCacheEntry = nullptr;
58 
59     return doomEntry;
60   }
61 
62  private:
63   virtual ~nsCacheEntryDescriptor();
64 
65   /*************************************************************************
66    * input stream wrapper class -
67    *
68    * The input stream wrapper references the descriptor, but the descriptor
69    * doesn't need any references to the stream wrapper.
70    *************************************************************************/
71   class nsInputStreamWrapper : public nsIInputStream {
72     friend class nsCacheEntryDescriptor;
73 
74    private:
75     nsCacheEntryDescriptor* mDescriptor;
76     nsCOMPtr<nsIInputStream> mInput;
77     uint32_t mStartOffset;
78     bool mInitialized;
79     mozilla::Mutex mLock;
80 
81    public:
82     NS_DECL_THREADSAFE_ISUPPORTS
83     NS_DECL_NSIINPUTSTREAM
84 
nsInputStreamWrapper(nsCacheEntryDescriptor * desc,uint32_t off)85     nsInputStreamWrapper(nsCacheEntryDescriptor* desc, uint32_t off)
86         : mDescriptor(desc),
87           mStartOffset(off),
88           mInitialized(false),
89           mLock("nsInputStreamWrapper.mLock") {
90       NS_ADDREF(mDescriptor);
91     }
92 
93    private:
~nsInputStreamWrapper()94     virtual ~nsInputStreamWrapper() { NS_IF_RELEASE(mDescriptor); }
95 
96     nsresult LazyInit();
97     nsresult EnsureInit();
98     nsresult Read_Locked(char* buf, uint32_t count, uint32_t* countRead);
99     nsresult Close_Locked();
100     void CloseInternal();
101   };
102 
103   class nsDecompressInputStreamWrapper : public nsInputStreamWrapper {
104    private:
105     unsigned char* mReadBuffer;
106     uint32_t mReadBufferLen;
107     z_stream mZstream;
108     bool mStreamInitialized;
109     bool mStreamEnded;
110 
111    public:
112     NS_DECL_ISUPPORTS_INHERITED
113 
nsDecompressInputStreamWrapper(nsCacheEntryDescriptor * desc,uint32_t off)114     nsDecompressInputStreamWrapper(nsCacheEntryDescriptor* desc, uint32_t off)
115         : nsInputStreamWrapper(desc, off),
116           mReadBuffer(nullptr),
117           mReadBufferLen(0),
118           mZstream{},
119           mStreamInitialized(false),
120           mStreamEnded(false) {}
121     NS_IMETHOD Read(char* buf, uint32_t count, uint32_t* result) override;
122     NS_IMETHOD Close() override;
123 
124    private:
~nsDecompressInputStreamWrapper()125     virtual ~nsDecompressInputStreamWrapper() { Close(); }
126     nsresult InitZstream();
127     nsresult EndZstream();
128   };
129 
130   /*************************************************************************
131    * output stream wrapper class -
132    *
133    * The output stream wrapper references the descriptor, but the descriptor
134    * doesn't need any references to the stream wrapper.
135    *************************************************************************/
136   class nsOutputStreamWrapper : public nsIOutputStream {
137     friend class nsCacheEntryDescriptor;
138 
139    protected:
140     nsCacheEntryDescriptor* mDescriptor;
141     nsCOMPtr<nsIOutputStream> mOutput;
142     uint32_t mStartOffset;
143     bool mInitialized;
144     mozilla::Mutex mLock;
145 
146    public:
147     NS_DECL_THREADSAFE_ISUPPORTS
148     NS_DECL_NSIOUTPUTSTREAM
149 
nsOutputStreamWrapper(nsCacheEntryDescriptor * desc,uint32_t off)150     nsOutputStreamWrapper(nsCacheEntryDescriptor* desc, uint32_t off)
151         : mDescriptor(desc),
152           mStartOffset(off),
153           mInitialized(false),
154           mLock("nsOutputStreamWrapper.mLock") {
155       NS_ADDREF(mDescriptor);  // owning ref
156     }
157 
158    private:
~nsOutputStreamWrapper()159     virtual ~nsOutputStreamWrapper() {
160       Close();
161 
162       NS_ASSERTION(!mOutput, "Bad state");
163       NS_ASSERTION(!mDescriptor, "Bad state");
164     }
165 
166     nsresult LazyInit();
167     nsresult EnsureInit();
168     nsresult OnWrite(uint32_t count);
169     nsresult Write_Locked(const char* buf, uint32_t count, uint32_t* result);
170     nsresult Close_Locked();
171     void CloseInternal();
172   };
173 
174   class nsCompressOutputStreamWrapper : public nsOutputStreamWrapper {
175    private:
176     unsigned char* mWriteBuffer;
177     uint32_t mWriteBufferLen;
178     z_stream mZstream;
179     bool mStreamInitialized;
180     bool mStreamEnded;
181     uint32_t mUncompressedCount;
182 
183    public:
184     NS_DECL_ISUPPORTS_INHERITED
185 
nsCompressOutputStreamWrapper(nsCacheEntryDescriptor * desc,uint32_t off)186     nsCompressOutputStreamWrapper(nsCacheEntryDescriptor* desc, uint32_t off)
187         : nsOutputStreamWrapper(desc, off),
188           mWriteBuffer(nullptr),
189           mWriteBufferLen(0),
190           mZstream{},
191           mStreamInitialized(false),
192           mStreamEnded(false),
193           mUncompressedCount(0) {}
194     NS_IMETHOD Write(const char* buf, uint32_t count,
195                      uint32_t* result) override;
196     NS_IMETHOD Close() override;
197 
198    private:
~nsCompressOutputStreamWrapper()199     virtual ~nsCompressOutputStreamWrapper() { Close(); }
200     nsresult InitZstream();
201     nsresult WriteBuffer();
202   };
203 
204  private:
205   /**
206    * nsCacheEntryDescriptor data members
207    */
208 
209   nsCOMPtr<nsICacheServiceInternal> mCacheService;
210   nsCacheEntry* mCacheEntry;  // we are a child of the entry
211   nsCacheAccessMode mAccessGranted;
212   nsTArray<nsInputStreamWrapper*> mInputWrappers;
213   nsOutputStreamWrapper* mOutputWrapper;
214   mozilla::Mutex mLock;
215   bool mAsyncDoomPending;
216   bool mDoomedOnClose;
217   bool mClosingDescriptor;
218 };
219 
220 #endif  // _nsCacheEntryDescriptor_h_
221