Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 "nsDependentString.h"
19 #include "SpdyPush31.h"
21 namespace mozilla {
22 namespace net {
24 //////////////////////////////////////////
25 // SpdyPushedStream31
26 //////////////////////////////////////////
28 SpdyPushedStream31::SpdyPushedStream31(SpdyPush31TransactionBuffer *aTransaction,
29 SpdySession31 *aSession,
30 SpdyStream31 *aAssociatedStream,
31 uint32_t aID)
32 :SpdyStream31(aTransaction, aSession,
33 0 /* priority is only for sending, so ignore it on push */)
34 , mConsumerStream(nullptr)
35 , mBufferedPush(aTransaction)
36 , mStatus(NS_OK)
37 , mPushCompleted(false)
38 , mDeferCleanupOnSuccess(true)
39 {
40 LOG3(("SpdyPushedStream31 ctor this=%p id=0x%X\n", this, aID));
41 mStreamID = aID;
42 mBufferedPush->SetPushStream(this);
43 mLoadGroupCI = aAssociatedStream->LoadGroupConnectionInfo();
44 mLastRead = TimeStamp::Now();
45 }
47 bool
48 SpdyPushedStream31::GetPushComplete()
49 {
50 return mPushCompleted;
51 }
53 nsresult
54 SpdyPushedStream31::WriteSegments(nsAHttpSegmentWriter *writer,
55 uint32_t count,
56 uint32_t *countWritten)
57 {
58 nsresult rv = SpdyStream31::WriteSegments(writer, count, countWritten);
59 if (NS_SUCCEEDED(rv) && *countWritten) {
60 mLastRead = TimeStamp::Now();
61 }
63 if (rv == NS_BASE_STREAM_CLOSED) {
64 mPushCompleted = true;
65 rv = NS_OK; // this is what a normal HTTP transaction would do
66 }
67 if (rv != NS_BASE_STREAM_WOULD_BLOCK && NS_FAILED(rv))
68 mStatus = rv;
69 return rv;
70 }
72 nsresult
73 SpdyPushedStream31::ReadSegments(nsAHttpSegmentReader *, uint32_t, uint32_t *count)
74 {
75 // The SYN_STREAM for this has been processed, so we need to verify
76 // that :host, :scheme, and :path MUST be present
77 nsDependentCSubstring host, scheme, path;
78 nsresult rv;
80 rv = SpdyStream31::FindHeader(NS_LITERAL_CSTRING(":host"), host);
81 if (NS_FAILED(rv)) {
82 LOG3(("SpdyPushedStream31::ReadSegments session=%p ID 0x%X "
83 "push without required :host\n", mSession, mStreamID));
84 return rv;
85 }
87 rv = SpdyStream31::FindHeader(NS_LITERAL_CSTRING(":scheme"), scheme);
88 if (NS_FAILED(rv)) {
89 LOG3(("SpdyPushedStream31::ReadSegments session=%p ID 0x%X "
90 "push without required :scheme\n", mSession, mStreamID));
91 return rv;
92 }
94 rv = SpdyStream31::FindHeader(NS_LITERAL_CSTRING(":path"), path);
95 if (NS_FAILED(rv)) {
96 LOG3(("SpdyPushedStream31::ReadSegments session=%p ID 0x%X "
97 "push without required :host\n", mSession, mStreamID));
98 return rv;
99 }
101 CreatePushHashKey(nsCString(scheme), nsCString(host),
102 mSession->Serial(), path,
103 mOrigin, mHashKey);
105 LOG3(("SpdyPushStream31 0x%X hash key %s\n", mStreamID, mHashKey.get()));
107 // the write side of a pushed transaction just involves manipulating a little state
108 SpdyStream31::mSentFinOnData = 1;
109 SpdyStream31::mSynFrameComplete = 1;
110 SpdyStream31::ChangeState(UPSTREAM_COMPLETE);
111 *count = 0;
112 return NS_OK;
113 }
115 bool
116 SpdyPushedStream31::GetHashKey(nsCString &key)
117 {
118 if (mHashKey.IsEmpty())
119 return false;
121 key = mHashKey;
122 return true;
123 }
125 void
126 SpdyPushedStream31::ConnectPushedStream(SpdyStream31 *stream)
127 {
128 mSession->ConnectPushedStream(stream);
129 }
131 bool
132 SpdyPushedStream31::IsOrphaned(TimeStamp now)
133 {
134 MOZ_ASSERT(!now.IsNull());
136 // if spdy is not transmitting, and is also not connected to a consumer
137 // stream, and its been like that for too long then it is oprhaned
139 if (mConsumerStream)
140 return false;
142 bool rv = ((now - mLastRead).ToSeconds() > 30.0);
143 if (rv) {
144 LOG3(("SpdyPushedStream31::IsOrphaned 0x%X IsOrphaned %3.2f\n",
145 mStreamID, (now - mLastRead).ToSeconds()));
146 }
147 return rv;
148 }
150 nsresult
151 SpdyPushedStream31::GetBufferedData(char *buf,
152 uint32_t count,
153 uint32_t *countWritten)
154 {
155 if (NS_FAILED(mStatus))
156 return mStatus;
158 nsresult rv = mBufferedPush->GetBufferedData(buf, count, countWritten);
159 if (NS_FAILED(rv))
160 return rv;
162 if (!*countWritten)
163 rv = GetPushComplete() ? NS_BASE_STREAM_CLOSED : NS_BASE_STREAM_WOULD_BLOCK;
165 return rv;
166 }
168 //////////////////////////////////////////
169 // SpdyPush31TransactionBuffer
170 // This is the nsAHttpTransction owned by the stream when the pushed
171 // stream has not yet been matched with a pull request
172 //////////////////////////////////////////
174 NS_IMPL_ISUPPORTS0(SpdyPush31TransactionBuffer)
176 SpdyPush31TransactionBuffer::SpdyPush31TransactionBuffer()
177 : mStatus(NS_OK)
178 , mRequestHead(nullptr)
179 , mPushStream(nullptr)
180 , mIsDone(false)
181 , mBufferedHTTP1Size(kDefaultBufferSize)
182 , mBufferedHTTP1Used(0)
183 , mBufferedHTTP1Consumed(0)
184 {
185 mBufferedHTTP1 = new char[mBufferedHTTP1Size];
186 }
188 SpdyPush31TransactionBuffer::~SpdyPush31TransactionBuffer()
189 {
190 delete mRequestHead;
191 }
193 void
194 SpdyPush31TransactionBuffer::SetConnection(nsAHttpConnection *conn)
195 {
196 }
198 nsAHttpConnection *
199 SpdyPush31TransactionBuffer::Connection()
200 {
201 return nullptr;
202 }
204 void
205 SpdyPush31TransactionBuffer::GetSecurityCallbacks(nsIInterfaceRequestor **outCB)
206 {
207 *outCB = nullptr;
208 }
210 void
211 SpdyPush31TransactionBuffer::OnTransportStatus(nsITransport* transport,
212 nsresult status, uint64_t progress)
213 {
214 }
216 bool
217 SpdyPush31TransactionBuffer::IsDone()
218 {
219 return mIsDone;
220 }
222 nsresult
223 SpdyPush31TransactionBuffer::Status()
224 {
225 return mStatus;
226 }
228 uint32_t
229 SpdyPush31TransactionBuffer::Caps()
230 {
231 return 0;
232 }
234 void
235 SpdyPush31TransactionBuffer::SetDNSWasRefreshed()
236 {
237 }
239 uint64_t
240 SpdyPush31TransactionBuffer::Available()
241 {
242 return mBufferedHTTP1Used - mBufferedHTTP1Consumed;
243 }
245 nsresult
246 SpdyPush31TransactionBuffer::ReadSegments(nsAHttpSegmentReader *reader,
247 uint32_t count, uint32_t *countRead)
248 {
249 *countRead = 0;
250 return NS_ERROR_NOT_IMPLEMENTED;
251 }
253 nsresult
254 SpdyPush31TransactionBuffer::WriteSegments(nsAHttpSegmentWriter *writer,
255 uint32_t count, uint32_t *countWritten)
256 {
257 if ((mBufferedHTTP1Size - mBufferedHTTP1Used) < 20480) {
258 SpdySession31::EnsureBuffer(mBufferedHTTP1,
259 mBufferedHTTP1Size + kDefaultBufferSize,
260 mBufferedHTTP1Used,
261 mBufferedHTTP1Size);
262 }
264 count = std::min(count, mBufferedHTTP1Size - mBufferedHTTP1Used);
265 nsresult rv = writer->OnWriteSegment(mBufferedHTTP1 + mBufferedHTTP1Used,
266 count, countWritten);
267 if (NS_SUCCEEDED(rv)) {
268 mBufferedHTTP1Used += *countWritten;
269 }
270 else if (rv == NS_BASE_STREAM_CLOSED) {
271 mIsDone = true;
272 }
274 if (Available()) {
275 SpdyStream31 *consumer = mPushStream->GetConsumerStream();
277 if (consumer) {
278 LOG3(("SpdyPush31TransactionBuffer::WriteSegments notifying connection "
279 "consumer data available 0x%X [%u]\n",
280 mPushStream->StreamID(), Available()));
281 mPushStream->ConnectPushedStream(consumer);
282 }
283 }
285 return rv;
286 }
288 uint32_t
289 SpdyPush31TransactionBuffer::Http1xTransactionCount()
290 {
291 return 0;
292 }
294 nsHttpRequestHead *
295 SpdyPush31TransactionBuffer::RequestHead()
296 {
297 if (!mRequestHead)
298 mRequestHead = new nsHttpRequestHead();
299 return mRequestHead;
300 }
302 nsresult
303 SpdyPush31TransactionBuffer::TakeSubTransactions(
304 nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions)
305 {
306 return NS_ERROR_NOT_IMPLEMENTED;
307 }
309 void
310 SpdyPush31TransactionBuffer::SetProxyConnectFailed()
311 {
312 }
314 void
315 SpdyPush31TransactionBuffer::Close(nsresult reason)
316 {
317 mStatus = reason;
318 mIsDone = true;
319 }
321 nsresult
322 SpdyPush31TransactionBuffer::AddTransaction(nsAHttpTransaction *trans)
323 {
324 return NS_ERROR_NOT_IMPLEMENTED;
325 }
327 uint32_t
328 SpdyPush31TransactionBuffer::PipelineDepth()
329 {
330 return 0;
331 }
333 nsresult
334 SpdyPush31TransactionBuffer::SetPipelinePosition(int32_t position)
335 {
336 return NS_OK;
337 }
339 int32_t
340 SpdyPush31TransactionBuffer::PipelinePosition()
341 {
342 return 1;
343 }
345 nsresult
346 SpdyPush31TransactionBuffer::GetBufferedData(char *buf,
347 uint32_t count,
348 uint32_t *countWritten)
349 {
350 *countWritten = std::min(count, static_cast<uint32_t>(Available()));
351 if (*countWritten) {
352 memcpy(buf, mBufferedHTTP1 + mBufferedHTTP1Consumed, *countWritten);
353 mBufferedHTTP1Consumed += *countWritten;
354 }
356 // If all the data has been consumed then reset the buffer
357 if (mBufferedHTTP1Consumed == mBufferedHTTP1Used) {
358 mBufferedHTTP1Consumed = 0;
359 mBufferedHTTP1Used = 0;
360 }
362 return NS_OK;
363 }
365 } // namespace mozilla::net
366 } // namespace mozilla