Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
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/. */
7 // HttpLog.h should generally be included first
8 #include "HttpLog.h"
10 // Log on level :5, instead of default :4.
11 #undef LOG
12 #define LOG(args) LOG5(args)
13 #undef LOG_ENABLED
14 #define LOG_ENABLED() LOG5_ENABLED()
16 #include <algorithm>
18 #include "SpdyPush3.h"
19 #include "PSpdyPush.h"
20 #include "SpdySession3.h"
21 #include "nsHttpRequestHead.h"
23 namespace mozilla {
24 namespace net {
26 //////////////////////////////////////////
27 // SpdyPushedStream3
28 //////////////////////////////////////////
30 SpdyPushedStream3::SpdyPushedStream3(SpdyPush3TransactionBuffer *aTransaction,
31 SpdySession3 *aSession,
32 SpdyStream3 *aAssociatedStream,
33 uint32_t aID)
34 :SpdyStream3(aTransaction, aSession,
35 0 /* priority is only for sending, so ignore it on push */)
36 , mConsumerStream(nullptr)
37 , mBufferedPush(aTransaction)
38 , mStatus(NS_OK)
39 , mPushCompleted(false)
40 , mDeferCleanupOnSuccess(true)
41 {
42 LOG3(("SpdyPushedStream3 ctor this=%p 0x%X\n", this, aID));
43 mStreamID = aID;
44 mBufferedPush->SetPushStream(this);
45 mLoadGroupCI = aAssociatedStream->LoadGroupConnectionInfo();
46 mLastRead = TimeStamp::Now();
47 }
49 bool
50 SpdyPushedStream3::GetPushComplete()
51 {
52 return mPushCompleted;
53 }
55 nsresult
56 SpdyPushedStream3::WriteSegments(nsAHttpSegmentWriter *writer,
57 uint32_t count,
58 uint32_t *countWritten)
59 {
60 nsresult rv = SpdyStream3::WriteSegments(writer, count, countWritten);
61 if (NS_SUCCEEDED(rv) && *countWritten) {
62 mLastRead = TimeStamp::Now();
63 }
65 if (rv == NS_BASE_STREAM_CLOSED) {
66 mPushCompleted = true;
67 rv = NS_OK; // this is what a normal HTTP transaction would do
68 }
69 if (rv != NS_BASE_STREAM_WOULD_BLOCK && NS_FAILED(rv))
70 mStatus = rv;
71 return rv;
72 }
74 nsresult
75 SpdyPushedStream3::ReadSegments(nsAHttpSegmentReader *, uint32_t, uint32_t *count)
76 {
77 // The SYN_STREAM for this has been processed, so we need to verify
78 // that :host, :scheme, and :path MUST be present
79 nsDependentCSubstring host, scheme, path;
80 nsresult rv;
82 rv = SpdyStream3::FindHeader(NS_LITERAL_CSTRING(":host"), host);
83 if (NS_FAILED(rv)) {
84 LOG3(("SpdyPushedStream3::ReadSegments session=%p ID 0x%X "
85 "push without required :host\n", mSession, mStreamID));
86 return rv;
87 }
89 rv = SpdyStream3::FindHeader(NS_LITERAL_CSTRING(":scheme"), scheme);
90 if (NS_FAILED(rv)) {
91 LOG3(("SpdyPushedStream3::ReadSegments session=%p ID 0x%X "
92 "push without required :scheme\n", mSession, mStreamID));
93 return rv;
94 }
96 rv = SpdyStream3::FindHeader(NS_LITERAL_CSTRING(":path"), path);
97 if (NS_FAILED(rv)) {
98 LOG3(("SpdyPushedStream3::ReadSegments session=%p ID 0x%X "
99 "push without required :host\n", mSession, mStreamID));
100 return rv;
101 }
103 CreatePushHashKey(nsCString(scheme), nsCString(host),
104 mSession->Serial(), path,
105 mOrigin, mHashKey);
107 LOG3(("SpdyPushStream3 0x%X hash key %s\n", mStreamID, mHashKey.get()));
109 // the write side of a pushed transaction just involves manipulating a little state
110 SpdyStream3::mSentFinOnData = 1;
111 SpdyStream3::mSynFrameComplete = 1;
112 SpdyStream3::ChangeState(UPSTREAM_COMPLETE);
113 *count = 0;
114 return NS_OK;
115 }
117 bool
118 SpdyPushedStream3::GetHashKey(nsCString &key)
119 {
120 if (mHashKey.IsEmpty())
121 return false;
123 key = mHashKey;
124 return true;
125 }
127 void
128 SpdyPushedStream3::ConnectPushedStream(SpdyStream3 *stream)
129 {
130 mSession->ConnectPushedStream(stream);
131 }
133 bool
134 SpdyPushedStream3::IsOrphaned(TimeStamp now)
135 {
136 MOZ_ASSERT(!now.IsNull());
138 // if spdy is not transmitting, and is also not connected to a consumer
139 // stream, and its been like that for too long then it is oprhaned
141 if (mConsumerStream)
142 return false;
144 bool rv = ((now - mLastRead).ToSeconds() > 30.0);
145 if (rv) {
146 LOG3(("SpdyPushCache::IsOrphaned 0x%X IsOrphaned %3.2f\n",
147 mStreamID, (now - mLastRead).ToSeconds()));
148 }
149 return rv;
150 }
152 nsresult
153 SpdyPushedStream3::GetBufferedData(char *buf,
154 uint32_t count,
155 uint32_t *countWritten)
156 {
157 if (NS_FAILED(mStatus))
158 return mStatus;
160 nsresult rv = mBufferedPush->GetBufferedData(buf, count, countWritten);
161 if (NS_FAILED(rv))
162 return rv;
164 if (!*countWritten)
165 rv = GetPushComplete() ? NS_BASE_STREAM_CLOSED : NS_BASE_STREAM_WOULD_BLOCK;
167 return rv;
168 }
170 //////////////////////////////////////////
171 // SpdyPush3TransactionBuffer
172 // This is the nsAHttpTransction owned by the stream when the pushed
173 // stream has not yet been matched with a pull request
174 //////////////////////////////////////////
176 NS_IMPL_ISUPPORTS0(SpdyPush3TransactionBuffer)
178 SpdyPush3TransactionBuffer::SpdyPush3TransactionBuffer()
179 : mStatus(NS_OK)
180 , mRequestHead(nullptr)
181 , mPushStream(nullptr)
182 , mIsDone(false)
183 , mBufferedHTTP1Size(kDefaultBufferSize)
184 , mBufferedHTTP1Used(0)
185 , mBufferedHTTP1Consumed(0)
186 {
187 mBufferedHTTP1 = new char[mBufferedHTTP1Size];
188 }
190 SpdyPush3TransactionBuffer::~SpdyPush3TransactionBuffer()
191 {
192 delete mRequestHead;
193 }
195 void
196 SpdyPush3TransactionBuffer::SetConnection(nsAHttpConnection *conn)
197 {
198 }
200 nsAHttpConnection *
201 SpdyPush3TransactionBuffer::Connection()
202 {
203 return nullptr;
204 }
206 void
207 SpdyPush3TransactionBuffer::GetSecurityCallbacks(nsIInterfaceRequestor **outCB)
208 {
209 *outCB = nullptr;
210 }
212 void
213 SpdyPush3TransactionBuffer::OnTransportStatus(nsITransport* transport,
214 nsresult status, uint64_t progress)
215 {
216 }
218 bool
219 SpdyPush3TransactionBuffer::IsDone()
220 {
221 return mIsDone;
222 }
224 nsresult
225 SpdyPush3TransactionBuffer::Status()
226 {
227 return mStatus;
228 }
230 uint32_t
231 SpdyPush3TransactionBuffer::Caps()
232 {
233 return 0;
234 }
236 void
237 SpdyPush3TransactionBuffer::SetDNSWasRefreshed()
238 {
239 }
241 uint64_t
242 SpdyPush3TransactionBuffer::Available()
243 {
244 return mBufferedHTTP1Used - mBufferedHTTP1Consumed;
245 }
247 nsresult
248 SpdyPush3TransactionBuffer::ReadSegments(nsAHttpSegmentReader *reader,
249 uint32_t count, uint32_t *countRead)
250 {
251 *countRead = 0;
252 return NS_ERROR_NOT_IMPLEMENTED;
253 }
255 nsresult
256 SpdyPush3TransactionBuffer::WriteSegments(nsAHttpSegmentWriter *writer,
257 uint32_t count, uint32_t *countWritten)
258 {
259 if ((mBufferedHTTP1Size - mBufferedHTTP1Used) < 20480) {
260 SpdySession3::EnsureBuffer(mBufferedHTTP1,
261 mBufferedHTTP1Size + kDefaultBufferSize,
262 mBufferedHTTP1Used,
263 mBufferedHTTP1Size);
264 }
266 count = std::min(count, mBufferedHTTP1Size - mBufferedHTTP1Used);
267 nsresult rv = writer->OnWriteSegment(mBufferedHTTP1 + mBufferedHTTP1Used,
268 count, countWritten);
269 if (NS_SUCCEEDED(rv)) {
270 mBufferedHTTP1Used += *countWritten;
271 }
272 else if (rv == NS_BASE_STREAM_CLOSED) {
273 mIsDone = true;
274 }
276 if (Available()) {
277 SpdyStream3 *consumer = mPushStream->GetConsumerStream();
279 if (consumer) {
280 LOG3(("SpdyPush3TransactionBuffer::WriteSegments notifying connection "
281 "consumer data available 0x%X [%u]\n",
282 mPushStream->StreamID(), Available()));
283 mPushStream->ConnectPushedStream(consumer);
284 }
285 }
287 return rv;
288 }
290 uint32_t
291 SpdyPush3TransactionBuffer::Http1xTransactionCount()
292 {
293 return 0;
294 }
296 nsHttpRequestHead *
297 SpdyPush3TransactionBuffer::RequestHead()
298 {
299 if (!mRequestHead)
300 mRequestHead = new nsHttpRequestHead();
301 return mRequestHead;
302 }
304 nsresult
305 SpdyPush3TransactionBuffer::TakeSubTransactions(
306 nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions)
307 {
308 return NS_ERROR_NOT_IMPLEMENTED;
309 }
311 void
312 SpdyPush3TransactionBuffer::SetProxyConnectFailed()
313 {
314 }
316 void
317 SpdyPush3TransactionBuffer::Close(nsresult reason)
318 {
319 mStatus = reason;
320 mIsDone = true;
321 }
323 nsresult
324 SpdyPush3TransactionBuffer::AddTransaction(nsAHttpTransaction *trans)
325 {
326 return NS_ERROR_NOT_IMPLEMENTED;
327 }
329 uint32_t
330 SpdyPush3TransactionBuffer::PipelineDepth()
331 {
332 return 0;
333 }
335 nsresult
336 SpdyPush3TransactionBuffer::SetPipelinePosition(int32_t position)
337 {
338 return NS_OK;
339 }
341 int32_t
342 SpdyPush3TransactionBuffer::PipelinePosition()
343 {
344 return 1;
345 }
347 nsresult
348 SpdyPush3TransactionBuffer::GetBufferedData(char *buf,
349 uint32_t count,
350 uint32_t *countWritten)
351 {
352 *countWritten = std::min(count, static_cast<uint32_t>(Available()));
353 if (*countWritten) {
354 memcpy(buf, mBufferedHTTP1 + mBufferedHTTP1Consumed, *countWritten);
355 mBufferedHTTP1Consumed += *countWritten;
356 }
358 // If all the data has been consumed then reset the buffer
359 if (mBufferedHTTP1Consumed == mBufferedHTTP1Used) {
360 mBufferedHTTP1Consumed = 0;
361 mBufferedHTTP1Used = 0;
362 }
364 return NS_OK;
365 }
367 } // namespace mozilla::net
368 } // namespace mozilla