|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "nsBaseContentStream.h" |
|
7 #include "nsStreamUtils.h" |
|
8 |
|
9 //----------------------------------------------------------------------------- |
|
10 |
|
11 void |
|
12 nsBaseContentStream::DispatchCallback(bool async) |
|
13 { |
|
14 if (!mCallback) |
|
15 return; |
|
16 |
|
17 // It's important to clear mCallback and mCallbackTarget up-front because the |
|
18 // OnInputStreamReady implementation may call our AsyncWait method. |
|
19 |
|
20 nsCOMPtr<nsIInputStreamCallback> callback; |
|
21 if (async) { |
|
22 callback = NS_NewInputStreamReadyEvent(mCallback, mCallbackTarget); |
|
23 mCallback = nullptr; |
|
24 } else { |
|
25 callback.swap(mCallback); |
|
26 } |
|
27 mCallbackTarget = nullptr; |
|
28 |
|
29 callback->OnInputStreamReady(this); |
|
30 } |
|
31 |
|
32 //----------------------------------------------------------------------------- |
|
33 // nsBaseContentStream::nsISupports |
|
34 |
|
35 NS_IMPL_ADDREF(nsBaseContentStream) |
|
36 NS_IMPL_RELEASE(nsBaseContentStream) |
|
37 |
|
38 // We only support nsIAsyncInputStream when we are in non-blocking mode. |
|
39 NS_INTERFACE_MAP_BEGIN(nsBaseContentStream) |
|
40 NS_INTERFACE_MAP_ENTRY(nsIInputStream) |
|
41 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStream, mNonBlocking) |
|
42 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream) |
|
43 NS_INTERFACE_MAP_END_THREADSAFE |
|
44 |
|
45 //----------------------------------------------------------------------------- |
|
46 // nsBaseContentStream::nsIInputStream |
|
47 |
|
48 NS_IMETHODIMP |
|
49 nsBaseContentStream::Close() |
|
50 { |
|
51 return IsClosed() ? NS_OK : CloseWithStatus(NS_BASE_STREAM_CLOSED); |
|
52 } |
|
53 |
|
54 NS_IMETHODIMP |
|
55 nsBaseContentStream::Available(uint64_t *result) |
|
56 { |
|
57 *result = 0; |
|
58 return mStatus; |
|
59 } |
|
60 |
|
61 NS_IMETHODIMP |
|
62 nsBaseContentStream::Read(char *buf, uint32_t count, uint32_t *result) |
|
63 { |
|
64 return ReadSegments(NS_CopySegmentToBuffer, buf, count, result); |
|
65 } |
|
66 |
|
67 NS_IMETHODIMP |
|
68 nsBaseContentStream::ReadSegments(nsWriteSegmentFun fun, void *closure, |
|
69 uint32_t count, uint32_t *result) |
|
70 { |
|
71 *result = 0; |
|
72 |
|
73 if (mStatus == NS_BASE_STREAM_CLOSED) |
|
74 return NS_OK; |
|
75 |
|
76 // No data yet |
|
77 if (!IsClosed() && IsNonBlocking()) |
|
78 return NS_BASE_STREAM_WOULD_BLOCK; |
|
79 |
|
80 return mStatus; |
|
81 } |
|
82 |
|
83 NS_IMETHODIMP |
|
84 nsBaseContentStream::IsNonBlocking(bool *result) |
|
85 { |
|
86 *result = mNonBlocking; |
|
87 return NS_OK; |
|
88 } |
|
89 |
|
90 //----------------------------------------------------------------------------- |
|
91 // nsBaseContentStream::nsIAsyncInputStream |
|
92 |
|
93 NS_IMETHODIMP |
|
94 nsBaseContentStream::CloseWithStatus(nsresult status) |
|
95 { |
|
96 if (IsClosed()) |
|
97 return NS_OK; |
|
98 |
|
99 NS_ENSURE_ARG(NS_FAILED(status)); |
|
100 mStatus = status; |
|
101 |
|
102 DispatchCallback(); |
|
103 return NS_OK; |
|
104 } |
|
105 |
|
106 NS_IMETHODIMP |
|
107 nsBaseContentStream::AsyncWait(nsIInputStreamCallback *callback, |
|
108 uint32_t flags, uint32_t requestedCount, |
|
109 nsIEventTarget *target) |
|
110 { |
|
111 // Our _only_ consumer is nsInputStreamPump, so we simplify things here by |
|
112 // making assumptions about how we will be called. |
|
113 NS_ASSERTION(target, "unexpected parameter"); |
|
114 NS_ASSERTION(flags == 0, "unexpected parameter"); |
|
115 NS_ASSERTION(requestedCount == 0, "unexpected parameter"); |
|
116 |
|
117 #ifdef DEBUG |
|
118 bool correctThread; |
|
119 target->IsOnCurrentThread(&correctThread); |
|
120 NS_ASSERTION(correctThread, "event target must be on the current thread"); |
|
121 #endif |
|
122 |
|
123 mCallback = callback; |
|
124 mCallbackTarget = target; |
|
125 |
|
126 if (!mCallback) |
|
127 return NS_OK; |
|
128 |
|
129 // If we're already closed, then dispatch this callback immediately. |
|
130 if (IsClosed()) { |
|
131 DispatchCallback(); |
|
132 return NS_OK; |
|
133 } |
|
134 |
|
135 OnCallbackPending(); |
|
136 return NS_OK; |
|
137 } |