/src/mozilla-central/netwerk/protocol/http/TunnelUtils.cpp
Line | Count | Source (jump to first uncovered line) |
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/. */ |
6 | | |
7 | | // HttpLog.h should generally be included first |
8 | | #include "HttpLog.h" |
9 | | |
10 | | #include "Http2Session.h" |
11 | | #include "nsHttp.h" |
12 | | #include "nsHttpHandler.h" |
13 | | #include "nsHttpRequestHead.h" |
14 | | #include "TCPFastOpen.h" |
15 | | #include "nsISocketProvider.h" |
16 | | #include "nsISocketProviderService.h" |
17 | | #include "nsISSLSocketControl.h" |
18 | | #include "nsISocketTransport.h" |
19 | | #include "nsISupportsPriority.h" |
20 | | #include "nsNetAddr.h" |
21 | | #include "prerror.h" |
22 | | #include "prio.h" |
23 | | #include "TunnelUtils.h" |
24 | | #include "nsNetCID.h" |
25 | | #include "nsServiceManagerUtils.h" |
26 | | #include "nsComponentManagerUtils.h" |
27 | | #include "nsSocketTransportService2.h" |
28 | | |
29 | | namespace mozilla { |
30 | | namespace net { |
31 | | |
32 | | static PRDescIdentity sLayerIdentity; |
33 | | static PRIOMethods sLayerMethods; |
34 | | static PRIOMethods *sLayerMethodsPtr = nullptr; |
35 | | |
36 | | TLSFilterTransaction::TLSFilterTransaction(nsAHttpTransaction *aWrapped, |
37 | | const char *aTLSHost, |
38 | | int32_t aTLSPort, |
39 | | nsAHttpSegmentReader *aReader, |
40 | | nsAHttpSegmentWriter *aWriter) |
41 | | : mTransaction(aWrapped) |
42 | | , mEncryptedTextUsed(0) |
43 | | , mEncryptedTextSize(0) |
44 | | , mSegmentReader(aReader) |
45 | | , mSegmentWriter(aWriter) |
46 | | , mFilterReadCode(NS_ERROR_NOT_INITIALIZED) |
47 | | , mForce(false) |
48 | | , mReadSegmentBlocked(false) |
49 | | , mNudgeCounter(0) |
50 | 0 | { |
51 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
52 | 0 | LOG(("TLSFilterTransaction ctor %p\n", this)); |
53 | 0 |
|
54 | 0 | nsCOMPtr<nsISocketProvider> provider; |
55 | 0 | nsCOMPtr<nsISocketProviderService> spserv = |
56 | 0 | do_GetService(NS_SOCKETPROVIDERSERVICE_CONTRACTID); |
57 | 0 |
|
58 | 0 | if (spserv) { |
59 | 0 | spserv->GetSocketProvider("ssl", getter_AddRefs(provider)); |
60 | 0 | } |
61 | 0 |
|
62 | 0 | // Install an NSPR layer to handle getpeername() with a failure. This is kind |
63 | 0 | // of silly, but the default one used by the pipe asserts when called and the |
64 | 0 | // nss code calls it to see if we are connected to a real socket or not. |
65 | 0 | if (!sLayerMethodsPtr) { |
66 | 0 | // one time initialization |
67 | 0 | sLayerIdentity = PR_GetUniqueIdentity("TLSFilterTransaction Layer"); |
68 | 0 | sLayerMethods = *PR_GetDefaultIOMethods(); |
69 | 0 | sLayerMethods.getpeername = GetPeerName; |
70 | 0 | sLayerMethods.getsocketoption = GetSocketOption; |
71 | 0 | sLayerMethods.setsocketoption = SetSocketOption; |
72 | 0 | sLayerMethods.read = FilterRead; |
73 | 0 | sLayerMethods.write = FilterWrite; |
74 | 0 | sLayerMethods.send = FilterSend; |
75 | 0 | sLayerMethods.recv = FilterRecv; |
76 | 0 | sLayerMethods.close = FilterClose; |
77 | 0 | sLayerMethodsPtr = &sLayerMethods; |
78 | 0 | } |
79 | 0 |
|
80 | 0 | mFD = PR_CreateIOLayerStub(sLayerIdentity, &sLayerMethods); |
81 | 0 |
|
82 | 0 | if (provider && mFD) { |
83 | 0 | mFD->secret = reinterpret_cast<PRFilePrivate *>(this); |
84 | 0 | provider->AddToSocket(PR_AF_INET, aTLSHost, aTLSPort, nullptr, |
85 | 0 | OriginAttributes(), 0, 0, mFD, |
86 | 0 | getter_AddRefs(mSecInfo)); |
87 | 0 | } |
88 | 0 |
|
89 | 0 | if (mTransaction) { |
90 | 0 | nsCOMPtr<nsIInterfaceRequestor> callbacks; |
91 | 0 | mTransaction->GetSecurityCallbacks(getter_AddRefs(callbacks)); |
92 | 0 | nsCOMPtr<nsISSLSocketControl> secCtrl(do_QueryInterface(mSecInfo)); |
93 | 0 | if (secCtrl) { |
94 | 0 | secCtrl->SetNotificationCallbacks(callbacks); |
95 | 0 | } |
96 | 0 | } |
97 | 0 | } |
98 | | |
99 | | TLSFilterTransaction::~TLSFilterTransaction() |
100 | 0 | { |
101 | 0 | LOG(("TLSFilterTransaction dtor %p\n", this)); |
102 | 0 | Cleanup(); |
103 | 0 | } |
104 | | |
105 | | void |
106 | | TLSFilterTransaction::Cleanup() |
107 | 0 | { |
108 | 0 | if (mTransaction) { |
109 | 0 | mTransaction->Close(NS_ERROR_ABORT); |
110 | 0 | mTransaction = nullptr; |
111 | 0 | } |
112 | 0 |
|
113 | 0 | if (mFD) { |
114 | 0 | PR_Close(mFD); |
115 | 0 | mFD = nullptr; |
116 | 0 | } |
117 | 0 | mSecInfo = nullptr; |
118 | 0 | if (mTimer) { |
119 | 0 | mTimer->Cancel(); |
120 | 0 | mTimer = nullptr; |
121 | 0 | } |
122 | 0 | } |
123 | | |
124 | | void |
125 | | TLSFilterTransaction::Close(nsresult aReason) |
126 | 0 | { |
127 | 0 | if (!mTransaction) { |
128 | 0 | return; |
129 | 0 | } |
130 | 0 | |
131 | 0 | if (mTimer) { |
132 | 0 | mTimer->Cancel(); |
133 | 0 | mTimer = nullptr; |
134 | 0 | } |
135 | 0 | mTransaction->Close(aReason); |
136 | 0 | mTransaction = nullptr; |
137 | 0 | } |
138 | | |
139 | | nsresult |
140 | | TLSFilterTransaction::OnReadSegment(const char *aData, |
141 | | uint32_t aCount, |
142 | | uint32_t *outCountRead) |
143 | 0 | { |
144 | 0 | LOG(("TLSFilterTransaction %p OnReadSegment %d (buffered %d)\n", |
145 | 0 | this, aCount, mEncryptedTextUsed)); |
146 | 0 |
|
147 | 0 | mReadSegmentBlocked = false; |
148 | 0 | MOZ_ASSERT(mSegmentReader); |
149 | 0 | if (!mSecInfo) { |
150 | 0 | return NS_ERROR_FAILURE; |
151 | 0 | } |
152 | 0 | |
153 | 0 | nsresult rv; |
154 | 0 | *outCountRead = 0; |
155 | 0 |
|
156 | 0 | // get rid of buffer first |
157 | 0 | if (mEncryptedTextUsed) { |
158 | 0 | rv = mSegmentReader->CommitToSegmentSize(mEncryptedTextUsed, mForce); |
159 | 0 | if (rv == NS_BASE_STREAM_WOULD_BLOCK) { |
160 | 0 | return rv; |
161 | 0 | } |
162 | 0 | |
163 | 0 | uint32_t amt; |
164 | 0 | rv = mSegmentReader->OnReadSegment(mEncryptedText.get(), mEncryptedTextUsed, &amt); |
165 | 0 | if (NS_FAILED(rv)) { |
166 | 0 | return rv; |
167 | 0 | } |
168 | 0 | |
169 | 0 | mEncryptedTextUsed -= amt; |
170 | 0 | if (mEncryptedTextUsed) { |
171 | 0 | memmove(mEncryptedText.get(), &mEncryptedText[amt], mEncryptedTextUsed); |
172 | 0 | return NS_OK; |
173 | 0 | } |
174 | 0 | } |
175 | 0 | |
176 | 0 | // encrypt for network write |
177 | 0 | // write aData down the SSL layer into the FilterWrite() method where it will |
178 | 0 | // be queued into mEncryptedText. We need to copy it like this in order to |
179 | 0 | // guarantee atomic writes |
180 | 0 | |
181 | 0 | EnsureBuffer(mEncryptedText, aCount + 4096, |
182 | 0 | 0, mEncryptedTextSize); |
183 | 0 |
|
184 | 0 | while (aCount > 0) { |
185 | 0 | int32_t written = PR_Write(mFD, aData, aCount); |
186 | 0 | LOG(("TLSFilterTransaction %p OnReadSegment PRWrite(%d) = %d %d\n", |
187 | 0 | this, aCount, written, |
188 | 0 | PR_GetError() == PR_WOULD_BLOCK_ERROR)); |
189 | 0 |
|
190 | 0 | if (written < 1) { |
191 | 0 | if (*outCountRead) { |
192 | 0 | return NS_OK; |
193 | 0 | } |
194 | 0 | // mTransaction ReadSegments actually obscures this code, so |
195 | 0 | // keep it in a member var for this::ReadSegments to insepct. Similar |
196 | 0 | // to nsHttpConnection::mSocketOutCondition |
197 | 0 | mReadSegmentBlocked = (PR_GetError() == PR_WOULD_BLOCK_ERROR); |
198 | 0 | return mReadSegmentBlocked ? NS_BASE_STREAM_WOULD_BLOCK : NS_ERROR_FAILURE; |
199 | 0 | } |
200 | 0 | aCount -= written; |
201 | 0 | aData += written; |
202 | 0 | *outCountRead += written; |
203 | 0 | mNudgeCounter = 0; |
204 | 0 | } |
205 | 0 |
|
206 | 0 | LOG(("TLSFilterTransaction %p OnReadSegment2 (buffered %d)\n", |
207 | 0 | this, mEncryptedTextUsed)); |
208 | 0 |
|
209 | 0 | uint32_t amt = 0; |
210 | 0 | if (mEncryptedTextUsed) { |
211 | 0 | // If we are tunneled on spdy CommitToSegmentSize will prevent partial |
212 | 0 | // writes that could interfere with multiplexing. H1 is fine with |
213 | 0 | // partial writes. |
214 | 0 | rv = mSegmentReader->CommitToSegmentSize(mEncryptedTextUsed, mForce); |
215 | 0 | if (rv != NS_BASE_STREAM_WOULD_BLOCK) { |
216 | 0 | rv = mSegmentReader->OnReadSegment(mEncryptedText.get(), mEncryptedTextUsed, &amt); |
217 | 0 | } |
218 | 0 |
|
219 | 0 | if (rv == NS_BASE_STREAM_WOULD_BLOCK) { |
220 | 0 | // return OK because all the data was consumed and stored in this buffer |
221 | 0 | Connection()->TransactionHasDataToWrite(this); |
222 | 0 | return NS_OK; |
223 | 0 | } else if (NS_FAILED(rv)) { |
224 | 0 | return rv; |
225 | 0 | } |
226 | 0 | } |
227 | 0 | |
228 | 0 | if (amt == mEncryptedTextUsed) { |
229 | 0 | mEncryptedText = nullptr; |
230 | 0 | mEncryptedTextUsed = 0; |
231 | 0 | mEncryptedTextSize = 0; |
232 | 0 | } else { |
233 | 0 | memmove(mEncryptedText.get(), &mEncryptedText[amt], mEncryptedTextUsed - amt); |
234 | 0 | mEncryptedTextUsed -= amt; |
235 | 0 | } |
236 | 0 | return NS_OK; |
237 | 0 | } |
238 | | |
239 | | int32_t |
240 | | TLSFilterTransaction::FilterOutput(const char *aBuf, int32_t aAmount) |
241 | 0 | { |
242 | 0 | EnsureBuffer(mEncryptedText, mEncryptedTextUsed + aAmount, |
243 | 0 | mEncryptedTextUsed, mEncryptedTextSize); |
244 | 0 | memcpy(&mEncryptedText[mEncryptedTextUsed], aBuf, aAmount); |
245 | 0 | mEncryptedTextUsed += aAmount; |
246 | 0 | return aAmount; |
247 | 0 | } |
248 | | |
249 | | nsresult |
250 | | TLSFilterTransaction::CommitToSegmentSize(uint32_t size, bool forceCommitment) |
251 | 0 | { |
252 | 0 | if (!mSegmentReader) { |
253 | 0 | return NS_ERROR_FAILURE; |
254 | 0 | } |
255 | 0 | |
256 | 0 | // pad the commit by a little bit to leave room for encryption overhead |
257 | 0 | // this isn't foolproof and we may still have to buffer, but its a good start |
258 | 0 | mForce = forceCommitment; |
259 | 0 | return mSegmentReader->CommitToSegmentSize(size + 1024, forceCommitment); |
260 | 0 | } |
261 | | |
262 | | nsresult |
263 | | TLSFilterTransaction::OnWriteSegment(char *aData, |
264 | | uint32_t aCount, |
265 | | uint32_t *outCountRead) |
266 | 0 | { |
267 | 0 |
|
268 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
269 | 0 | MOZ_ASSERT(mSegmentWriter); |
270 | 0 | LOG(("TLSFilterTransaction::OnWriteSegment %p max=%d\n", this, aCount)); |
271 | 0 | if (!mSecInfo) { |
272 | 0 | return NS_ERROR_FAILURE; |
273 | 0 | } |
274 | 0 | |
275 | 0 | // this will call through to FilterInput to get data from the higher |
276 | 0 | // level connection before removing the local TLS layer |
277 | 0 | mFilterReadCode = NS_OK; |
278 | 0 | int32_t bytesRead = PR_Read(mFD, aData, aCount); |
279 | 0 | if (bytesRead == -1) { |
280 | 0 | if (PR_GetError() == PR_WOULD_BLOCK_ERROR) { |
281 | 0 | return NS_BASE_STREAM_WOULD_BLOCK; |
282 | 0 | } |
283 | 0 | return NS_ERROR_FAILURE; |
284 | 0 | } |
285 | 0 | *outCountRead = bytesRead; |
286 | 0 |
|
287 | 0 | if (NS_SUCCEEDED(mFilterReadCode) && !bytesRead) { |
288 | 0 | LOG(("TLSFilterTransaction::OnWriteSegment %p " |
289 | 0 | "Second layer of TLS stripping results in STREAM_CLOSED\n", this)); |
290 | 0 | mFilterReadCode = NS_BASE_STREAM_CLOSED; |
291 | 0 | } |
292 | 0 |
|
293 | 0 | LOG(("TLSFilterTransaction::OnWriteSegment %p rv=%" PRIx32 " didread=%d " |
294 | 0 | "2 layers of ssl stripped to plaintext\n", |
295 | 0 | this, static_cast<uint32_t>(mFilterReadCode), bytesRead)); |
296 | 0 | return mFilterReadCode; |
297 | 0 | } |
298 | | |
299 | | int32_t |
300 | | TLSFilterTransaction::FilterInput(char *aBuf, int32_t aAmount) |
301 | 0 | { |
302 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
303 | 0 | MOZ_ASSERT(mSegmentWriter); |
304 | 0 | LOG(("TLSFilterTransaction::FilterInput max=%d\n", aAmount)); |
305 | 0 |
|
306 | 0 | uint32_t outCountRead = 0; |
307 | 0 | mFilterReadCode = mSegmentWriter->OnWriteSegment(aBuf, aAmount, &outCountRead); |
308 | 0 | if (NS_SUCCEEDED(mFilterReadCode) && outCountRead) { |
309 | 0 | LOG(("TLSFilterTransaction::FilterInput rv=%" PRIx32 " read=%d input from net " |
310 | 0 | "1 layer stripped, 1 still on\n", |
311 | 0 | static_cast<uint32_t>(mFilterReadCode), outCountRead)); |
312 | 0 | if (mReadSegmentBlocked) { |
313 | 0 | mNudgeCounter = 0; |
314 | 0 | } |
315 | 0 | } |
316 | 0 | if (mFilterReadCode == NS_BASE_STREAM_WOULD_BLOCK) { |
317 | 0 | PR_SetError(PR_WOULD_BLOCK_ERROR, 0); |
318 | 0 | return -1; |
319 | 0 | } |
320 | 0 | return outCountRead; |
321 | 0 | } |
322 | | |
323 | | nsresult |
324 | | TLSFilterTransaction::ReadSegments(nsAHttpSegmentReader *aReader, |
325 | | uint32_t aCount, uint32_t *outCountRead) |
326 | 0 | { |
327 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
328 | 0 | LOG(("TLSFilterTransaction::ReadSegments %p max=%d\n", this, aCount)); |
329 | 0 |
|
330 | 0 | if (!mTransaction) { |
331 | 0 | return NS_ERROR_UNEXPECTED; |
332 | 0 | } |
333 | 0 | |
334 | 0 | mReadSegmentBlocked = false; |
335 | 0 | mSegmentReader = aReader; |
336 | 0 | nsresult rv = mTransaction->ReadSegments(this, aCount, outCountRead); |
337 | 0 | LOG(("TLSFilterTransaction %p called trans->ReadSegments rv=%" PRIx32 " %d\n", |
338 | 0 | this, static_cast<uint32_t>(rv), *outCountRead)); |
339 | 0 | if (NS_SUCCEEDED(rv) && mReadSegmentBlocked) { |
340 | 0 | rv = NS_BASE_STREAM_WOULD_BLOCK; |
341 | 0 | LOG(("TLSFilterTransaction %p read segment blocked found rv=%" PRIx32 "\n", |
342 | 0 | this, static_cast<uint32_t>(rv))); |
343 | 0 | Unused << Connection()->ForceSend(); |
344 | 0 | } |
345 | 0 |
|
346 | 0 | return rv; |
347 | 0 | } |
348 | | |
349 | | nsresult |
350 | | TLSFilterTransaction::WriteSegments(nsAHttpSegmentWriter *aWriter, |
351 | | uint32_t aCount, uint32_t *outCountWritten) |
352 | 0 | { |
353 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
354 | 0 | LOG(("TLSFilterTransaction::WriteSegments %p max=%d\n", this, aCount)); |
355 | 0 |
|
356 | 0 | if (!mTransaction) { |
357 | 0 | return NS_ERROR_UNEXPECTED; |
358 | 0 | } |
359 | 0 | |
360 | 0 | mSegmentWriter = aWriter; |
361 | 0 | nsresult rv = mTransaction->WriteSegments(this, aCount, outCountWritten); |
362 | 0 | if (NS_SUCCEEDED(rv) && NS_FAILED(mFilterReadCode) && !(*outCountWritten)) { |
363 | 0 | // nsPipe turns failures into silent OK.. undo that! |
364 | 0 | rv = mFilterReadCode; |
365 | 0 | if (Connection() && (mFilterReadCode == NS_BASE_STREAM_WOULD_BLOCK)) { |
366 | 0 | Unused << Connection()->ResumeRecv(); |
367 | 0 | } |
368 | 0 | } |
369 | 0 | LOG(("TLSFilterTransaction %p called trans->WriteSegments rv=%" PRIx32 " %d\n", |
370 | 0 | this, static_cast<uint32_t>(rv), *outCountWritten)); |
371 | 0 | return rv; |
372 | 0 | } |
373 | | |
374 | | nsresult |
375 | | TLSFilterTransaction::GetTransactionSecurityInfo(nsISupports **outSecInfo) |
376 | 0 | { |
377 | 0 | if (!mSecInfo) { |
378 | 0 | return NS_ERROR_FAILURE; |
379 | 0 | } |
380 | 0 | |
381 | 0 | nsCOMPtr<nsISupports> temp(mSecInfo); |
382 | 0 | temp.forget(outSecInfo); |
383 | 0 | return NS_OK; |
384 | 0 | } |
385 | | |
386 | | nsresult |
387 | | TLSFilterTransaction::NudgeTunnel(NudgeTunnelCallback *aCallback) |
388 | 0 | { |
389 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
390 | 0 | LOG(("TLSFilterTransaction %p NudgeTunnel\n", this)); |
391 | 0 | mNudgeCallback = nullptr; |
392 | 0 |
|
393 | 0 | if (!mSecInfo) { |
394 | 0 | return NS_ERROR_FAILURE; |
395 | 0 | } |
396 | 0 | |
397 | 0 | nsCOMPtr<nsISSLSocketControl> ssl(do_QueryInterface(mSecInfo)); |
398 | 0 | nsresult rv = ssl ? ssl->DriveHandshake() : NS_ERROR_FAILURE; |
399 | 0 | if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) { |
400 | 0 | // fatal handshake failure |
401 | 0 | LOG(("TLSFilterTransaction %p Fatal Handshake Failure: %d\n", this, PR_GetError())); |
402 | 0 | return NS_ERROR_FAILURE; |
403 | 0 | } |
404 | 0 |
|
405 | 0 | uint32_t notUsed; |
406 | 0 | Unused << OnReadSegment("", 0, ¬Used); |
407 | 0 |
|
408 | 0 | // The SSL Layer does some unusual things with PR_Poll that makes it a bad |
409 | 0 | // match for multiplexed SSL sessions. We work around this by manually polling for |
410 | 0 | // the moment during the brief handshake phase or otherwise blocked on write. |
411 | 0 | // Thankfully this is a pretty unusual state. NSPR doesn't help us here - |
412 | 0 | // asserting when polling without the NSPR IO layer on the bottom of |
413 | 0 | // the stack. As a follow-on we can do some NSPR and maybe libssl changes |
414 | 0 | // to make this more event driven, but this is acceptable for getting started. |
415 | 0 |
|
416 | 0 | uint32_t counter = mNudgeCounter++; |
417 | 0 | uint32_t delay; |
418 | 0 |
|
419 | 0 | if (!counter) { |
420 | 0 | delay = 0; |
421 | 0 | } else if (counter < 8) { // up to 48ms at 6 |
422 | 0 | delay = 6; |
423 | 0 | } else if (counter < 34) { // up to 499 ms at 17ms |
424 | 0 | delay = 17; |
425 | 0 | } else { // after that at 51ms (3 old windows ticks) |
426 | 0 | delay = 51; |
427 | 0 | } |
428 | 0 |
|
429 | 0 | if(!mTimer) { |
430 | 0 | mTimer = NS_NewTimer(); |
431 | 0 | } |
432 | 0 |
|
433 | 0 | mNudgeCallback = aCallback; |
434 | 0 | if (!mTimer || |
435 | 0 | NS_FAILED(mTimer->InitWithCallback(this, delay, nsITimer::TYPE_ONE_SHOT))) { |
436 | 0 | return StartTimerCallback(); |
437 | 0 | } |
438 | 0 | |
439 | 0 | LOG(("TLSFilterTransaction %p NudgeTunnel timer started\n", this)); |
440 | 0 | return NS_OK; |
441 | 0 | } |
442 | | |
443 | | NS_IMETHODIMP |
444 | | TLSFilterTransaction::Notify(nsITimer *timer) |
445 | 0 | { |
446 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
447 | 0 | LOG(("TLSFilterTransaction %p NudgeTunnel notify\n", this)); |
448 | 0 |
|
449 | 0 | if (timer != mTimer) { |
450 | 0 | return NS_ERROR_UNEXPECTED; |
451 | 0 | } |
452 | 0 | DebugOnly<nsresult> rv = StartTimerCallback(); |
453 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
454 | 0 | return NS_OK; |
455 | 0 | } |
456 | | |
457 | | NS_IMETHODIMP |
458 | | TLSFilterTransaction::GetName(nsACString& aName) |
459 | 0 | { |
460 | 0 | aName.AssignLiteral("TLSFilterTransaction"); |
461 | 0 | return NS_OK; |
462 | 0 | } |
463 | | |
464 | | nsresult |
465 | | TLSFilterTransaction::StartTimerCallback() |
466 | 0 | { |
467 | 0 | LOG(("TLSFilterTransaction %p NudgeTunnel StartTimerCallback %p\n", |
468 | 0 | this, mNudgeCallback.get())); |
469 | 0 |
|
470 | 0 | if (mNudgeCallback) { |
471 | 0 | // This class can be called re-entrantly, so cleanup m* before ->on() |
472 | 0 | RefPtr<NudgeTunnelCallback> cb(mNudgeCallback); |
473 | 0 | mNudgeCallback = nullptr; |
474 | 0 | cb->OnTunnelNudged(this); |
475 | 0 | } |
476 | 0 | return NS_OK; |
477 | 0 | } |
478 | | |
479 | | PRStatus |
480 | | TLSFilterTransaction::GetPeerName(PRFileDesc *aFD, PRNetAddr*addr) |
481 | 0 | { |
482 | 0 | NetAddr peeraddr; |
483 | 0 | TLSFilterTransaction *self = reinterpret_cast<TLSFilterTransaction *>(aFD->secret); |
484 | 0 |
|
485 | 0 | if (!self->mTransaction || |
486 | 0 | NS_FAILED(self->mTransaction->Connection()->Transport()->GetPeerAddr(&peeraddr))) { |
487 | 0 | return PR_FAILURE; |
488 | 0 | } |
489 | 0 | NetAddrToPRNetAddr(&peeraddr, addr); |
490 | 0 | return PR_SUCCESS; |
491 | 0 | } |
492 | | |
493 | | PRStatus |
494 | | TLSFilterTransaction::GetSocketOption(PRFileDesc *aFD, PRSocketOptionData *aOpt) |
495 | 0 | { |
496 | 0 | if (aOpt->option == PR_SockOpt_Nonblocking) { |
497 | 0 | aOpt->value.non_blocking = PR_TRUE; |
498 | 0 | return PR_SUCCESS; |
499 | 0 | } |
500 | 0 | return PR_FAILURE; |
501 | 0 | } |
502 | | |
503 | | PRStatus |
504 | | TLSFilterTransaction::SetSocketOption(PRFileDesc *aFD, const PRSocketOptionData *aOpt) |
505 | 0 | { |
506 | 0 | return PR_FAILURE; |
507 | 0 | } |
508 | | |
509 | | PRStatus |
510 | | TLSFilterTransaction::FilterClose(PRFileDesc *aFD) |
511 | 0 | { |
512 | 0 | return PR_SUCCESS; |
513 | 0 | } |
514 | | |
515 | | int32_t |
516 | | TLSFilterTransaction::FilterWrite(PRFileDesc *aFD, const void *aBuf, int32_t aAmount) |
517 | 0 | { |
518 | 0 | TLSFilterTransaction *self = reinterpret_cast<TLSFilterTransaction *>(aFD->secret); |
519 | 0 | return self->FilterOutput(static_cast<const char *>(aBuf), aAmount); |
520 | 0 | } |
521 | | |
522 | | int32_t |
523 | | TLSFilterTransaction::FilterSend(PRFileDesc *aFD, const void *aBuf, int32_t aAmount, |
524 | | int , PRIntervalTime) |
525 | 0 | { |
526 | 0 | return FilterWrite(aFD, aBuf, aAmount); |
527 | 0 | } |
528 | | |
529 | | int32_t |
530 | | TLSFilterTransaction::FilterRead(PRFileDesc *aFD, void *aBuf, int32_t aAmount) |
531 | 0 | { |
532 | 0 | TLSFilterTransaction *self = reinterpret_cast<TLSFilterTransaction *>(aFD->secret); |
533 | 0 | return self->FilterInput(static_cast<char *>(aBuf), aAmount); |
534 | 0 | } |
535 | | |
536 | | int32_t |
537 | | TLSFilterTransaction::FilterRecv(PRFileDesc *aFD, void *aBuf, int32_t aAmount, |
538 | | int , PRIntervalTime) |
539 | 0 | { |
540 | 0 | return FilterRead(aFD, aBuf, aAmount); |
541 | 0 | } |
542 | | |
543 | | ///// |
544 | | // The other methods of TLSFilterTransaction just call mTransaction->method |
545 | | ///// |
546 | | |
547 | | void |
548 | | TLSFilterTransaction::SetConnection(nsAHttpConnection *aConnection) |
549 | 0 | { |
550 | 0 | if (!mTransaction) { |
551 | 0 | return; |
552 | 0 | } |
553 | 0 | |
554 | 0 | mTransaction->SetConnection(aConnection); |
555 | 0 | } |
556 | | |
557 | | nsAHttpConnection * |
558 | | TLSFilterTransaction::Connection() |
559 | 0 | { |
560 | 0 | if (!mTransaction) { |
561 | 0 | return nullptr; |
562 | 0 | } |
563 | 0 | return mTransaction->Connection(); |
564 | 0 | } |
565 | | |
566 | | void |
567 | | TLSFilterTransaction::GetSecurityCallbacks(nsIInterfaceRequestor **outCB) |
568 | 0 | { |
569 | 0 | if (!mTransaction) { |
570 | 0 | return; |
571 | 0 | } |
572 | 0 | mTransaction->GetSecurityCallbacks(outCB); |
573 | 0 | } |
574 | | |
575 | | void |
576 | | TLSFilterTransaction::OnTransportStatus(nsITransport* aTransport, |
577 | | nsresult aStatus, int64_t aProgress) |
578 | 0 | { |
579 | 0 | if (!mTransaction) { |
580 | 0 | return; |
581 | 0 | } |
582 | 0 | mTransaction->OnTransportStatus(aTransport, aStatus, aProgress); |
583 | 0 | } |
584 | | |
585 | | nsHttpConnectionInfo * |
586 | | TLSFilterTransaction::ConnectionInfo() |
587 | 0 | { |
588 | 0 | if (!mTransaction) { |
589 | 0 | return nullptr; |
590 | 0 | } |
591 | 0 | return mTransaction->ConnectionInfo(); |
592 | 0 | } |
593 | | |
594 | | bool |
595 | | TLSFilterTransaction::IsDone() |
596 | 0 | { |
597 | 0 | if (!mTransaction) { |
598 | 0 | return true; |
599 | 0 | } |
600 | 0 | return mTransaction->IsDone(); |
601 | 0 | } |
602 | | |
603 | | nsresult |
604 | | TLSFilterTransaction::Status() |
605 | 0 | { |
606 | 0 | if (!mTransaction) { |
607 | 0 | return NS_ERROR_UNEXPECTED; |
608 | 0 | } |
609 | 0 | |
610 | 0 | return mTransaction->Status(); |
611 | 0 | } |
612 | | |
613 | | uint32_t |
614 | | TLSFilterTransaction::Caps() |
615 | 0 | { |
616 | 0 | if (!mTransaction) { |
617 | 0 | return 0; |
618 | 0 | } |
619 | 0 | |
620 | 0 | return mTransaction->Caps(); |
621 | 0 | } |
622 | | |
623 | | void |
624 | | TLSFilterTransaction::SetDNSWasRefreshed() |
625 | 0 | { |
626 | 0 | if (!mTransaction) { |
627 | 0 | return; |
628 | 0 | } |
629 | 0 | |
630 | 0 | mTransaction->SetDNSWasRefreshed(); |
631 | 0 | } |
632 | | |
633 | | void |
634 | | TLSFilterTransaction::SetProxyConnectFailed() |
635 | 0 | { |
636 | 0 | if (!mTransaction) { |
637 | 0 | return; |
638 | 0 | } |
639 | 0 | |
640 | 0 | mTransaction->SetProxyConnectFailed(); |
641 | 0 | } |
642 | | |
643 | | nsHttpRequestHead * |
644 | | TLSFilterTransaction::RequestHead() |
645 | 0 | { |
646 | 0 | if (!mTransaction) { |
647 | 0 | return nullptr; |
648 | 0 | } |
649 | 0 | |
650 | 0 | return mTransaction->RequestHead(); |
651 | 0 | } |
652 | | |
653 | | uint32_t |
654 | | TLSFilterTransaction::Http1xTransactionCount() |
655 | 0 | { |
656 | 0 | if (!mTransaction) { |
657 | 0 | return 0; |
658 | 0 | } |
659 | 0 | |
660 | 0 | return mTransaction->Http1xTransactionCount(); |
661 | 0 | } |
662 | | |
663 | | nsresult |
664 | | TLSFilterTransaction::TakeSubTransactions( |
665 | | nsTArray<RefPtr<nsAHttpTransaction> > &outTransactions) |
666 | 0 | { |
667 | 0 | LOG(("TLSFilterTransaction::TakeSubTransactions [this=%p] mTransaction %p\n", |
668 | 0 | this, mTransaction.get())); |
669 | 0 |
|
670 | 0 | if (!mTransaction) { |
671 | 0 | return NS_ERROR_UNEXPECTED; |
672 | 0 | } |
673 | 0 | |
674 | 0 | if (mTransaction->TakeSubTransactions(outTransactions) == NS_ERROR_NOT_IMPLEMENTED) { |
675 | 0 | outTransactions.AppendElement(mTransaction); |
676 | 0 | } |
677 | 0 | mTransaction = nullptr; |
678 | 0 |
|
679 | 0 | return NS_OK; |
680 | 0 | } |
681 | | |
682 | | nsresult |
683 | | TLSFilterTransaction::SetProxiedTransaction(nsAHttpTransaction *aTrans) |
684 | 0 | { |
685 | 0 | LOG(("TLSFilterTransaction::SetProxiedTransaction [this=%p] aTrans=%p\n", |
686 | 0 | this, aTrans)); |
687 | 0 |
|
688 | 0 | mTransaction = aTrans; |
689 | 0 | nsCOMPtr<nsIInterfaceRequestor> callbacks; |
690 | 0 | mTransaction->GetSecurityCallbacks(getter_AddRefs(callbacks)); |
691 | 0 | nsCOMPtr<nsISSLSocketControl> secCtrl(do_QueryInterface(mSecInfo)); |
692 | 0 | if (secCtrl && callbacks) { |
693 | 0 | secCtrl->SetNotificationCallbacks(callbacks); |
694 | 0 | } |
695 | 0 |
|
696 | 0 | return NS_OK; |
697 | 0 | } |
698 | | |
699 | | bool |
700 | | TLSFilterTransaction::IsNullTransaction() |
701 | 0 | { |
702 | 0 | if (!mTransaction) { |
703 | 0 | return false; |
704 | 0 | } |
705 | 0 | return mTransaction->IsNullTransaction(); |
706 | 0 | } |
707 | | |
708 | | NullHttpTransaction * |
709 | | TLSFilterTransaction::QueryNullTransaction() |
710 | 0 | { |
711 | 0 | if (!mTransaction) { |
712 | 0 | return nullptr; |
713 | 0 | } |
714 | 0 | return mTransaction->QueryNullTransaction(); |
715 | 0 | } |
716 | | |
717 | | nsHttpTransaction * |
718 | | TLSFilterTransaction::QueryHttpTransaction() |
719 | 0 | { |
720 | 0 | if (!mTransaction) { |
721 | 0 | return nullptr; |
722 | 0 | } |
723 | 0 | return mTransaction->QueryHttpTransaction(); |
724 | 0 | } |
725 | | |
726 | | |
727 | | class SocketInWrapper : public nsIAsyncInputStream |
728 | | , public nsAHttpSegmentWriter |
729 | | { |
730 | | NS_DECL_THREADSAFE_ISUPPORTS |
731 | | NS_FORWARD_NSIASYNCINPUTSTREAM(mStream->) |
732 | | |
733 | | SocketInWrapper(nsIAsyncInputStream *aWrapped, TLSFilterTransaction *aFilter) |
734 | | : mStream(aWrapped) |
735 | | , mTLSFilter(aFilter) |
736 | 0 | { } |
737 | | |
738 | | NS_IMETHOD Close() override |
739 | 0 | { |
740 | 0 | mTLSFilter = nullptr; |
741 | 0 | return mStream->Close(); |
742 | 0 | } |
743 | | |
744 | | NS_IMETHOD Available(uint64_t *_retval) override |
745 | 0 | { |
746 | 0 | return mStream->Available(_retval); |
747 | 0 | } |
748 | | |
749 | | NS_IMETHOD IsNonBlocking(bool *_retval) override |
750 | 0 | { |
751 | 0 | return mStream->IsNonBlocking(_retval); |
752 | 0 | } |
753 | | |
754 | | NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, uint32_t aCount, uint32_t *_retval) override |
755 | 0 | { |
756 | 0 | return mStream->ReadSegments(aWriter, aClosure, aCount, _retval); |
757 | 0 | } |
758 | | |
759 | | // finally, ones that don't get forwarded :) |
760 | | NS_IMETHOD Read(char *aBuf, uint32_t aCount, uint32_t *_retval) override; |
761 | | virtual nsresult OnWriteSegment(char *segment, uint32_t count, uint32_t *countWritten) override; |
762 | | |
763 | | private: |
764 | 0 | virtual ~SocketInWrapper() = default;; |
765 | | |
766 | | nsCOMPtr<nsIAsyncInputStream> mStream; |
767 | | RefPtr<TLSFilterTransaction> mTLSFilter; |
768 | | }; |
769 | | |
770 | | nsresult |
771 | | SocketInWrapper::OnWriteSegment(char *segment, uint32_t count, uint32_t *countWritten) |
772 | 0 | { |
773 | 0 | LOG(("SocketInWrapper OnWriteSegment %d %p filter=%p\n", count, this, mTLSFilter.get())); |
774 | 0 |
|
775 | 0 | nsresult rv = mStream->Read(segment, count, countWritten); |
776 | 0 | LOG(("SocketInWrapper OnWriteSegment %p wrapped read %" PRIx32 " %d\n", |
777 | 0 | this, static_cast<uint32_t>(rv), *countWritten)); |
778 | 0 | return rv; |
779 | 0 | } |
780 | | |
781 | | NS_IMETHODIMP |
782 | | SocketInWrapper::Read(char *aBuf, uint32_t aCount, uint32_t *_retval) |
783 | 0 | { |
784 | 0 | LOG(("SocketInWrapper Read %d %p filter=%p\n", aCount, this, mTLSFilter.get())); |
785 | 0 |
|
786 | 0 | if (!mTLSFilter) { |
787 | 0 | return NS_ERROR_UNEXPECTED; // protect potentially dangling mTLSFilter |
788 | 0 | } |
789 | 0 | |
790 | 0 | // mTLSFilter->mSegmentWriter MUST be this at ctor time |
791 | 0 | return mTLSFilter->OnWriteSegment(aBuf, aCount, _retval); |
792 | 0 | } |
793 | | |
794 | | class SocketOutWrapper : public nsIAsyncOutputStream |
795 | | , public nsAHttpSegmentReader |
796 | | { |
797 | | NS_DECL_THREADSAFE_ISUPPORTS |
798 | | NS_FORWARD_NSIASYNCOUTPUTSTREAM(mStream->) |
799 | | |
800 | | SocketOutWrapper(nsIAsyncOutputStream *aWrapped, TLSFilterTransaction *aFilter) |
801 | | : mStream(aWrapped) |
802 | | , mTLSFilter(aFilter) |
803 | 0 | { } |
804 | | |
805 | | NS_IMETHOD Close() override |
806 | 0 | { |
807 | 0 | mTLSFilter = nullptr; |
808 | 0 | return mStream->Close(); |
809 | 0 | } |
810 | | |
811 | | NS_IMETHOD Flush() override |
812 | 0 | { |
813 | 0 | return mStream->Flush(); |
814 | 0 | } |
815 | | |
816 | | NS_IMETHOD IsNonBlocking(bool *_retval) override |
817 | 0 | { |
818 | 0 | return mStream->IsNonBlocking(_retval); |
819 | 0 | } |
820 | | |
821 | | NS_IMETHOD WriteSegments(nsReadSegmentFun aReader, void *aClosure, uint32_t aCount, uint32_t *_retval) override |
822 | 0 | { |
823 | 0 | return mStream->WriteSegments(aReader, aClosure, aCount, _retval); |
824 | 0 | } |
825 | | |
826 | | NS_IMETHOD WriteFrom(nsIInputStream *aFromStream, uint32_t aCount, uint32_t *_retval) override |
827 | 0 | { |
828 | 0 | return mStream->WriteFrom(aFromStream, aCount, _retval); |
829 | 0 | } |
830 | | |
831 | | // finally, ones that don't get forwarded :) |
832 | | NS_IMETHOD Write(const char *aBuf, uint32_t aCount, uint32_t *_retval) override; |
833 | | virtual nsresult OnReadSegment(const char *segment, uint32_t count, uint32_t *countRead) override; |
834 | | |
835 | | private: |
836 | 0 | virtual ~SocketOutWrapper() = default;; |
837 | | |
838 | | nsCOMPtr<nsIAsyncOutputStream> mStream; |
839 | | RefPtr<TLSFilterTransaction> mTLSFilter; |
840 | | }; |
841 | | |
842 | | nsresult |
843 | | SocketOutWrapper::OnReadSegment(const char *segment, uint32_t count, uint32_t *countWritten) |
844 | 0 | { |
845 | 0 | return mStream->Write(segment, count, countWritten); |
846 | 0 | } |
847 | | |
848 | | NS_IMETHODIMP |
849 | | SocketOutWrapper::Write(const char *aBuf, uint32_t aCount, uint32_t *_retval) |
850 | 0 | { |
851 | 0 | LOG(("SocketOutWrapper Write %d %p filter=%p\n", aCount, this, mTLSFilter.get())); |
852 | 0 |
|
853 | 0 | // mTLSFilter->mSegmentReader MUST be this at ctor time |
854 | 0 | if (!mTLSFilter) { |
855 | 0 | return NS_ERROR_UNEXPECTED; // protect potentially dangling mTLSFilter |
856 | 0 | } |
857 | 0 | |
858 | 0 | return mTLSFilter->OnReadSegment(aBuf, aCount, _retval); |
859 | 0 | } |
860 | | |
861 | | void |
862 | | TLSFilterTransaction::newIODriver(nsIAsyncInputStream *aSocketIn, |
863 | | nsIAsyncOutputStream *aSocketOut, |
864 | | nsIAsyncInputStream **outSocketIn, |
865 | | nsIAsyncOutputStream **outSocketOut) |
866 | 0 | { |
867 | 0 | SocketInWrapper *inputWrapper = new SocketInWrapper(aSocketIn, this); |
868 | 0 | mSegmentWriter = inputWrapper; |
869 | 0 | nsCOMPtr<nsIAsyncInputStream> newIn(inputWrapper); |
870 | 0 | newIn.forget(outSocketIn); |
871 | 0 |
|
872 | 0 | SocketOutWrapper *outputWrapper = new SocketOutWrapper(aSocketOut, this); |
873 | 0 | mSegmentReader = outputWrapper; |
874 | 0 | nsCOMPtr<nsIAsyncOutputStream> newOut(outputWrapper); |
875 | 0 | newOut.forget(outSocketOut); |
876 | 0 | } |
877 | | |
878 | | SpdyConnectTransaction * |
879 | | TLSFilterTransaction::QuerySpdyConnectTransaction() |
880 | 0 | { |
881 | 0 | if (!mTransaction) { |
882 | 0 | return nullptr; |
883 | 0 | } |
884 | 0 | return mTransaction->QuerySpdyConnectTransaction(); |
885 | 0 | } |
886 | | |
887 | | class SocketTransportShim : public nsISocketTransport |
888 | | { |
889 | | public: |
890 | | NS_DECL_THREADSAFE_ISUPPORTS |
891 | | NS_DECL_NSITRANSPORT |
892 | | NS_DECL_NSISOCKETTRANSPORT |
893 | | |
894 | | explicit SocketTransportShim(nsISocketTransport *aWrapped) |
895 | | : mWrapped(aWrapped) |
896 | 0 | {}; |
897 | | |
898 | | private: |
899 | 0 | virtual ~SocketTransportShim() = default;; |
900 | | |
901 | | nsCOMPtr<nsISocketTransport> mWrapped; |
902 | | }; |
903 | | |
904 | | class OutputStreamShim : public nsIAsyncOutputStream |
905 | | { |
906 | | public: |
907 | | NS_DECL_THREADSAFE_ISUPPORTS |
908 | | NS_DECL_NSIOUTPUTSTREAM |
909 | | NS_DECL_NSIASYNCOUTPUTSTREAM |
910 | | |
911 | | friend class SpdyConnectTransaction; |
912 | | |
913 | | explicit OutputStreamShim(SpdyConnectTransaction *aTrans) |
914 | | : mCallback(nullptr) |
915 | | , mStatus(NS_OK) |
916 | 0 | { |
917 | 0 | mWeakTrans = do_GetWeakReference(aTrans); |
918 | 0 | } |
919 | | |
920 | | private: |
921 | 0 | virtual ~OutputStreamShim() = default;; |
922 | | |
923 | | nsWeakPtr mWeakTrans; // SpdyConnectTransaction * |
924 | | nsIOutputStreamCallback *mCallback; |
925 | | nsresult mStatus; |
926 | | }; |
927 | | |
928 | | class InputStreamShim : public nsIAsyncInputStream |
929 | | { |
930 | | public: |
931 | | NS_DECL_THREADSAFE_ISUPPORTS |
932 | | NS_DECL_NSIINPUTSTREAM |
933 | | NS_DECL_NSIASYNCINPUTSTREAM |
934 | | |
935 | | friend class SpdyConnectTransaction; |
936 | | |
937 | | explicit InputStreamShim(SpdyConnectTransaction *aTrans) |
938 | | : mCallback(nullptr) |
939 | | , mStatus(NS_OK) |
940 | 0 | { |
941 | 0 | mWeakTrans = do_GetWeakReference(aTrans); |
942 | 0 | } |
943 | | |
944 | | private: |
945 | 0 | virtual ~InputStreamShim() = default;; |
946 | | |
947 | | nsWeakPtr mWeakTrans; // SpdyConnectTransaction * |
948 | | nsIInputStreamCallback *mCallback; |
949 | | nsresult mStatus; |
950 | | }; |
951 | | |
952 | | SpdyConnectTransaction::SpdyConnectTransaction(nsHttpConnectionInfo *ci, |
953 | | nsIInterfaceRequestor *callbacks, |
954 | | uint32_t caps, |
955 | | nsHttpTransaction *trans, |
956 | | nsAHttpConnection *session) |
957 | | : NullHttpTransaction(ci, callbacks, caps | NS_HTTP_ALLOW_KEEPALIVE) |
958 | | , mConnectStringOffset(0) |
959 | | , mSession(session) |
960 | | , mSegmentReader(nullptr) |
961 | | , mInputDataSize(0) |
962 | | , mInputDataUsed(0) |
963 | | , mInputDataOffset(0) |
964 | | , mOutputDataSize(0) |
965 | | , mOutputDataUsed(0) |
966 | | , mOutputDataOffset(0) |
967 | | , mForcePlainText(false) |
968 | 0 | { |
969 | 0 | LOG(("SpdyConnectTransaction ctor %p\n", this)); |
970 | 0 |
|
971 | 0 | mTimestampSyn = TimeStamp::Now(); |
972 | 0 | mRequestHead = new nsHttpRequestHead(); |
973 | 0 | DebugOnly<nsresult> rv = |
974 | 0 | nsHttpConnection::MakeConnectString(trans, mRequestHead, mConnectString); |
975 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
976 | 0 | mDrivingTransaction = trans; |
977 | 0 | } |
978 | | |
979 | | SpdyConnectTransaction::~SpdyConnectTransaction() |
980 | 0 | { |
981 | 0 | LOG(("SpdyConnectTransaction dtor %p\n", this)); |
982 | 0 |
|
983 | 0 | if (mDrivingTransaction) { |
984 | 0 | // requeue it I guess. This should be gone. |
985 | 0 | Unused << gHttpHandler->InitiateTransaction(mDrivingTransaction, |
986 | 0 | mDrivingTransaction->Priority()); |
987 | 0 | } |
988 | 0 | } |
989 | | |
990 | | void |
991 | | SpdyConnectTransaction::ForcePlainText() |
992 | 0 | { |
993 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
994 | 0 | MOZ_ASSERT(!mInputDataUsed && !mInputDataSize && !mInputDataOffset); |
995 | 0 | MOZ_ASSERT(!mForcePlainText); |
996 | 0 | MOZ_ASSERT(!mTunnelTransport, "call before mapstreamtohttpconnection"); |
997 | 0 |
|
998 | 0 | mForcePlainText = true; |
999 | 0 | } |
1000 | | |
1001 | | void |
1002 | | SpdyConnectTransaction::MapStreamToHttpConnection(nsISocketTransport *aTransport, |
1003 | | nsHttpConnectionInfo *aConnInfo) |
1004 | 0 | { |
1005 | 0 | mConnInfo = aConnInfo; |
1006 | 0 |
|
1007 | 0 | mTunnelTransport = new SocketTransportShim(aTransport); |
1008 | 0 | mTunnelStreamIn = new InputStreamShim(this); |
1009 | 0 | mTunnelStreamOut = new OutputStreamShim(this); |
1010 | 0 | mTunneledConn = new nsHttpConnection(); |
1011 | 0 |
|
1012 | 0 | // this new http connection has a specific hashkey (i.e. to a particular |
1013 | 0 | // host via the tunnel) and is associated with the tunnel streams |
1014 | 0 | LOG(("SpdyConnectTransaction new httpconnection %p %s\n", |
1015 | 0 | mTunneledConn.get(), aConnInfo->HashKey().get())); |
1016 | 0 |
|
1017 | 0 | nsCOMPtr<nsIInterfaceRequestor> callbacks; |
1018 | 0 | GetSecurityCallbacks(getter_AddRefs(callbacks)); |
1019 | 0 | mTunneledConn->SetTransactionCaps(Caps()); |
1020 | 0 | MOZ_ASSERT(aConnInfo->UsingHttpsProxy()); |
1021 | 0 | TimeDuration rtt = TimeStamp::Now() - mTimestampSyn; |
1022 | 0 | DebugOnly<nsresult> rv = |
1023 | 0 | mTunneledConn->Init(aConnInfo, |
1024 | 0 | gHttpHandler->ConnMgr()->MaxRequestDelay(), |
1025 | 0 | mTunnelTransport, mTunnelStreamIn, mTunnelStreamOut, |
1026 | 0 | true, callbacks, |
1027 | 0 | PR_MillisecondsToInterval( |
1028 | 0 | static_cast<uint32_t>(rtt.ToMilliseconds()))); |
1029 | 0 | MOZ_ASSERT(NS_SUCCEEDED(rv)); |
1030 | 0 | if (mForcePlainText) { |
1031 | 0 | mTunneledConn->ForcePlainText(); |
1032 | 0 | } else { |
1033 | 0 | mTunneledConn->SetupSecondaryTLS(); |
1034 | 0 | mTunneledConn->SetInSpdyTunnel(true); |
1035 | 0 | } |
1036 | 0 |
|
1037 | 0 | // make the originating transaction stick to the tunneled conn |
1038 | 0 | RefPtr<nsAHttpConnection> wrappedConn = |
1039 | 0 | gHttpHandler->ConnMgr()->MakeConnectionHandle(mTunneledConn); |
1040 | 0 | mDrivingTransaction->SetConnection(wrappedConn); |
1041 | 0 | mDrivingTransaction->MakeSticky(); |
1042 | 0 |
|
1043 | 0 | // jump the priority and start the dispatcher |
1044 | 0 | Unused << gHttpHandler->InitiateTransaction( |
1045 | 0 | mDrivingTransaction, nsISupportsPriority::PRIORITY_HIGHEST - 60); |
1046 | 0 | mDrivingTransaction = nullptr; |
1047 | 0 | } |
1048 | | |
1049 | | nsresult |
1050 | | SpdyConnectTransaction::Flush(uint32_t count, uint32_t *countRead) |
1051 | 0 | { |
1052 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
1053 | 0 | LOG(("SpdyConnectTransaction::Flush %p count %d avail %d\n", |
1054 | 0 | this, count, mOutputDataUsed - mOutputDataOffset)); |
1055 | 0 |
|
1056 | 0 | if (!mSegmentReader) { |
1057 | 0 | return NS_ERROR_UNEXPECTED; |
1058 | 0 | } |
1059 | 0 | |
1060 | 0 | *countRead = 0; |
1061 | 0 | count = std::min(count, (mOutputDataUsed - mOutputDataOffset)); |
1062 | 0 | if (count) { |
1063 | 0 | nsresult rv; |
1064 | 0 | rv = mSegmentReader->OnReadSegment(&mOutputData[mOutputDataOffset], |
1065 | 0 | count, countRead); |
1066 | 0 | if (NS_FAILED(rv) && (rv != NS_BASE_STREAM_WOULD_BLOCK)) { |
1067 | 0 | LOG(("SpdyConnectTransaction::Flush %p Error %" PRIx32 "\n", |
1068 | 0 | this, static_cast<uint32_t>(rv))); |
1069 | 0 | CreateShimError(rv); |
1070 | 0 | return rv; |
1071 | 0 | } |
1072 | 0 | } |
1073 | 0 |
|
1074 | 0 | mOutputDataOffset += *countRead; |
1075 | 0 | if (mOutputDataOffset == mOutputDataUsed) { |
1076 | 0 | mOutputDataOffset = mOutputDataUsed = 0; |
1077 | 0 | } |
1078 | 0 | if (!(*countRead)) { |
1079 | 0 | return NS_BASE_STREAM_WOULD_BLOCK; |
1080 | 0 | } |
1081 | 0 | |
1082 | 0 | if (mOutputDataUsed != mOutputDataOffset) { |
1083 | 0 | LOG(("SpdyConnectTransaction::Flush %p Incomplete %d\n", |
1084 | 0 | this, mOutputDataUsed - mOutputDataOffset)); |
1085 | 0 | mSession->TransactionHasDataToWrite(this); |
1086 | 0 | } |
1087 | 0 |
|
1088 | 0 | return NS_OK; |
1089 | 0 | } |
1090 | | |
1091 | | nsresult |
1092 | | SpdyConnectTransaction::ReadSegments(nsAHttpSegmentReader *reader, |
1093 | | uint32_t count, |
1094 | | uint32_t *countRead) |
1095 | 0 | { |
1096 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
1097 | 0 | LOG(("SpdyConnectTransaction::ReadSegments %p count %d conn %p\n", |
1098 | 0 | this, count, mTunneledConn.get())); |
1099 | 0 |
|
1100 | 0 | mSegmentReader = reader; |
1101 | 0 |
|
1102 | 0 | // spdy stream carrying tunnel is not setup yet. |
1103 | 0 | if (!mTunneledConn) { |
1104 | 0 | uint32_t toWrite = mConnectString.Length() - mConnectStringOffset; |
1105 | 0 | toWrite = std::min(toWrite, count); |
1106 | 0 | *countRead = toWrite; |
1107 | 0 | if (toWrite) { |
1108 | 0 | nsresult rv = mSegmentReader-> |
1109 | 0 | OnReadSegment(mConnectString.BeginReading() + mConnectStringOffset, |
1110 | 0 | toWrite, countRead); |
1111 | 0 | if (NS_FAILED(rv) && (rv != NS_BASE_STREAM_WOULD_BLOCK)) { |
1112 | 0 | LOG(("SpdyConnectTransaction::ReadSegments %p OnReadSegmentError %" PRIx32 "\n", |
1113 | 0 | this, static_cast<uint32_t>(rv))); |
1114 | 0 | CreateShimError(rv); |
1115 | 0 | } else { |
1116 | 0 | mConnectStringOffset += toWrite; |
1117 | 0 | if (mConnectString.Length() == mConnectStringOffset) { |
1118 | 0 | mConnectString.Truncate(); |
1119 | 0 | mConnectStringOffset = 0; |
1120 | 0 | } |
1121 | 0 | } |
1122 | 0 | return rv; |
1123 | 0 | } |
1124 | 0 | return NS_BASE_STREAM_WOULD_BLOCK; |
1125 | 0 | } |
1126 | 0 | |
1127 | 0 | if (mForcePlainText) { |
1128 | 0 | // this path just ignores sending the request so that we can |
1129 | 0 | // send a synthetic reply in writesegments() |
1130 | 0 | LOG(("SpdyConnectTransaciton::ReadSegments %p dropping %d output bytes " |
1131 | 0 | "due to synthetic reply\n", this, mOutputDataUsed - mOutputDataOffset)); |
1132 | 0 | *countRead = mOutputDataUsed - mOutputDataOffset; |
1133 | 0 | mOutputDataOffset = mOutputDataUsed = 0; |
1134 | 0 | mTunneledConn->DontReuse(); |
1135 | 0 | return NS_OK; |
1136 | 0 | } |
1137 | 0 |
|
1138 | 0 | *countRead = 0; |
1139 | 0 | Unused << Flush(count, countRead); |
1140 | 0 | if (!mTunnelStreamOut->mCallback) { |
1141 | 0 | return NS_BASE_STREAM_WOULD_BLOCK; |
1142 | 0 | } |
1143 | 0 | |
1144 | 0 | nsresult rv = |
1145 | 0 | mTunnelStreamOut->mCallback->OnOutputStreamReady(mTunnelStreamOut); |
1146 | 0 | if (NS_FAILED(rv)) { |
1147 | 0 | return rv; |
1148 | 0 | } |
1149 | 0 | |
1150 | 0 | uint32_t subtotal; |
1151 | 0 | count -= *countRead; |
1152 | 0 | rv = Flush(count, &subtotal); |
1153 | 0 | *countRead += subtotal; |
1154 | 0 | return rv; |
1155 | 0 | } |
1156 | | |
1157 | | void |
1158 | | SpdyConnectTransaction::CreateShimError(nsresult code) |
1159 | 0 | { |
1160 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
1161 | 0 | MOZ_ASSERT(NS_FAILED(code)); |
1162 | 0 |
|
1163 | 0 | if (mTunnelStreamOut && NS_SUCCEEDED(mTunnelStreamOut->mStatus)) { |
1164 | 0 | mTunnelStreamOut->mStatus = code; |
1165 | 0 | } |
1166 | 0 |
|
1167 | 0 | if (mTunnelStreamIn && NS_SUCCEEDED(mTunnelStreamIn->mStatus)) { |
1168 | 0 | mTunnelStreamIn->mStatus = code; |
1169 | 0 | } |
1170 | 0 |
|
1171 | 0 | if (mTunnelStreamIn && mTunnelStreamIn->mCallback) { |
1172 | 0 | mTunnelStreamIn->mCallback->OnInputStreamReady(mTunnelStreamIn); |
1173 | 0 | } |
1174 | 0 |
|
1175 | 0 | if (mTunnelStreamOut && mTunnelStreamOut->mCallback) { |
1176 | 0 | mTunnelStreamOut->mCallback->OnOutputStreamReady(mTunnelStreamOut); |
1177 | 0 | } |
1178 | 0 | } |
1179 | | |
1180 | | nsresult |
1181 | | SpdyConnectTransaction::WriteSegments(nsAHttpSegmentWriter *writer, |
1182 | | uint32_t count, |
1183 | | uint32_t *countWritten) |
1184 | 0 | { |
1185 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
1186 | 0 | LOG(("SpdyConnectTransaction::WriteSegments %p max=%d cb=%p\n", |
1187 | 0 | this, count, mTunneledConn ? mTunnelStreamIn->mCallback : nullptr)); |
1188 | 0 |
|
1189 | 0 | // first call into the tunnel stream to get the demux'd data out of the |
1190 | 0 | // spdy session. |
1191 | 0 | EnsureBuffer(mInputData, mInputDataUsed + count, mInputDataUsed, mInputDataSize); |
1192 | 0 | nsresult rv = writer->OnWriteSegment(&mInputData[mInputDataUsed], |
1193 | 0 | count, countWritten); |
1194 | 0 | if (NS_FAILED(rv)) { |
1195 | 0 | if (rv != NS_BASE_STREAM_WOULD_BLOCK) { |
1196 | 0 | LOG(("SpdyConnectTransaction::WriteSegments wrapped writer %p Error %" PRIx32 "\n", |
1197 | 0 | this, static_cast<uint32_t>(rv))); |
1198 | 0 | CreateShimError(rv); |
1199 | 0 | } |
1200 | 0 | return rv; |
1201 | 0 | } |
1202 | 0 | mInputDataUsed += *countWritten; |
1203 | 0 | LOG(("SpdyConnectTransaction %p %d new bytes [%d total] of ciphered data buffered\n", |
1204 | 0 | this, *countWritten, mInputDataUsed - mInputDataOffset)); |
1205 | 0 |
|
1206 | 0 | if (!mTunneledConn || !mTunnelStreamIn->mCallback) { |
1207 | 0 | return NS_BASE_STREAM_WOULD_BLOCK; |
1208 | 0 | } |
1209 | 0 | |
1210 | 0 | rv = mTunnelStreamIn->mCallback->OnInputStreamReady(mTunnelStreamIn); |
1211 | 0 | LOG(("SpdyConnectTransaction::WriteSegments %p " |
1212 | 0 | "after InputStreamReady callback %d total of ciphered data buffered rv=%" |
1213 | 0 | PRIx32 "\n", |
1214 | 0 | this, mInputDataUsed - mInputDataOffset, static_cast<uint32_t>(rv))); |
1215 | 0 | LOG(("SpdyConnectTransaction::WriteSegments %p " |
1216 | 0 | "goodput %p out %" PRId64 "\n", this, mTunneledConn.get(), |
1217 | 0 | mTunneledConn->ContentBytesWritten())); |
1218 | 0 | if (NS_SUCCEEDED(rv) && !mTunneledConn->ContentBytesWritten()) { |
1219 | 0 | mTunnelStreamOut->AsyncWait(mTunnelStreamOut->mCallback, 0, 0, nullptr); |
1220 | 0 | } |
1221 | 0 | return rv; |
1222 | 0 | } |
1223 | | |
1224 | | bool |
1225 | | SpdyConnectTransaction::ConnectedReadyForInput() |
1226 | 0 | { |
1227 | 0 | return mTunneledConn && mTunnelStreamIn->mCallback; |
1228 | 0 | } |
1229 | | |
1230 | | nsHttpRequestHead * |
1231 | | SpdyConnectTransaction::RequestHead() |
1232 | 0 | { |
1233 | 0 | return mRequestHead; |
1234 | 0 | } |
1235 | | |
1236 | | void |
1237 | | SpdyConnectTransaction::Close(nsresult code) |
1238 | 0 | { |
1239 | 0 | LOG(("SpdyConnectTransaction close %p %" PRIx32 "\n", this, static_cast<uint32_t>(code))); |
1240 | 0 |
|
1241 | 0 | NullHttpTransaction::Close(code); |
1242 | 0 | if (NS_FAILED(code) && (code != NS_BASE_STREAM_WOULD_BLOCK)) { |
1243 | 0 | CreateShimError(code); |
1244 | 0 | } else { |
1245 | 0 | CreateShimError(NS_BASE_STREAM_CLOSED); |
1246 | 0 | } |
1247 | 0 | } |
1248 | | |
1249 | | NS_IMETHODIMP |
1250 | | OutputStreamShim::AsyncWait(nsIOutputStreamCallback *callback, |
1251 | | unsigned int, unsigned int, nsIEventTarget *target) |
1252 | 0 | { |
1253 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
1254 | 0 | bool currentThread; |
1255 | 0 |
|
1256 | 0 | if (target && |
1257 | 0 | (NS_FAILED(target->IsOnCurrentThread(¤tThread)) || !currentThread)) { |
1258 | 0 | return NS_ERROR_FAILURE; |
1259 | 0 | } |
1260 | 0 | |
1261 | 0 | LOG(("OutputStreamShim::AsyncWait %p callback %p\n", this, callback)); |
1262 | 0 | mCallback = callback; |
1263 | 0 |
|
1264 | 0 | RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans)); |
1265 | 0 | if (!baseTrans) { |
1266 | 0 | return NS_ERROR_FAILURE; |
1267 | 0 | } |
1268 | 0 | SpdyConnectTransaction *trans = baseTrans->QuerySpdyConnectTransaction(); |
1269 | 0 | MOZ_ASSERT(trans); |
1270 | 0 | if (!trans) { |
1271 | 0 | return NS_ERROR_UNEXPECTED; |
1272 | 0 | } |
1273 | 0 | |
1274 | 0 | trans->mSession->TransactionHasDataToWrite(trans); |
1275 | 0 |
|
1276 | 0 | return NS_OK; |
1277 | 0 | } |
1278 | | |
1279 | | NS_IMETHODIMP |
1280 | | OutputStreamShim::CloseWithStatus(nsresult reason) |
1281 | 0 | { |
1282 | 0 | RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans)); |
1283 | 0 | if (!baseTrans) { |
1284 | 0 | return NS_ERROR_FAILURE; |
1285 | 0 | } |
1286 | 0 | SpdyConnectTransaction *trans = baseTrans->QuerySpdyConnectTransaction(); |
1287 | 0 | MOZ_ASSERT(trans); |
1288 | 0 | if (!trans) { |
1289 | 0 | return NS_ERROR_UNEXPECTED; |
1290 | 0 | } |
1291 | 0 | |
1292 | 0 | trans->mSession->CloseTransaction(trans, reason); |
1293 | 0 | return NS_OK; |
1294 | 0 | } |
1295 | | |
1296 | | NS_IMETHODIMP |
1297 | | OutputStreamShim::Close() |
1298 | 0 | { |
1299 | 0 | return CloseWithStatus(NS_OK); |
1300 | 0 | } |
1301 | | |
1302 | | NS_IMETHODIMP |
1303 | | OutputStreamShim::Flush() |
1304 | 0 | { |
1305 | 0 | RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans)); |
1306 | 0 | if (!baseTrans) { |
1307 | 0 | return NS_ERROR_FAILURE; |
1308 | 0 | } |
1309 | 0 | SpdyConnectTransaction *trans = baseTrans->QuerySpdyConnectTransaction(); |
1310 | 0 | MOZ_ASSERT(trans); |
1311 | 0 | if (!trans) { |
1312 | 0 | return NS_ERROR_UNEXPECTED; |
1313 | 0 | } |
1314 | 0 | |
1315 | 0 | uint32_t count = trans->mOutputDataUsed - trans->mOutputDataOffset; |
1316 | 0 | if (!count) { |
1317 | 0 | return NS_OK; |
1318 | 0 | } |
1319 | 0 | |
1320 | 0 | uint32_t countRead; |
1321 | 0 | nsresult rv = trans->Flush(count, &countRead); |
1322 | 0 | LOG(("OutputStreamShim::Flush %p before %d after %d\n", |
1323 | 0 | this, count, trans->mOutputDataUsed - trans->mOutputDataOffset)); |
1324 | 0 | return rv; |
1325 | 0 | } |
1326 | | |
1327 | | NS_IMETHODIMP |
1328 | | OutputStreamShim::Write(const char * aBuf, uint32_t aCount, uint32_t *_retval) |
1329 | 0 | { |
1330 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
1331 | 0 |
|
1332 | 0 | if (NS_FAILED(mStatus)) { |
1333 | 0 | return mStatus; |
1334 | 0 | } |
1335 | 0 | |
1336 | 0 | RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans)); |
1337 | 0 | if (!baseTrans) { |
1338 | 0 | return NS_ERROR_FAILURE; |
1339 | 0 | } |
1340 | 0 | SpdyConnectTransaction *trans = baseTrans->QuerySpdyConnectTransaction(); |
1341 | 0 | MOZ_ASSERT(trans); |
1342 | 0 | if (!trans) { |
1343 | 0 | return NS_ERROR_UNEXPECTED; |
1344 | 0 | } |
1345 | 0 | |
1346 | 0 | if ((trans->mOutputDataUsed + aCount) >= 512000) { |
1347 | 0 | *_retval = 0; |
1348 | 0 | // time for some flow control; |
1349 | 0 | return NS_BASE_STREAM_WOULD_BLOCK; |
1350 | 0 | } |
1351 | 0 | |
1352 | 0 | EnsureBuffer(trans->mOutputData, trans->mOutputDataUsed + aCount, |
1353 | 0 | trans->mOutputDataUsed, trans->mOutputDataSize); |
1354 | 0 | memcpy(&trans->mOutputData[trans->mOutputDataUsed], aBuf, aCount); |
1355 | 0 | trans->mOutputDataUsed += aCount; |
1356 | 0 | *_retval = aCount; |
1357 | 0 | LOG(("OutputStreamShim::Write %p new %d total %d\n", this, aCount, trans->mOutputDataUsed)); |
1358 | 0 |
|
1359 | 0 | trans->mSession->TransactionHasDataToWrite(trans); |
1360 | 0 |
|
1361 | 0 | return NS_OK; |
1362 | 0 | } |
1363 | | |
1364 | | NS_IMETHODIMP |
1365 | | OutputStreamShim::WriteFrom(nsIInputStream *aFromStream, uint32_t aCount, uint32_t *_retval) |
1366 | 0 | { |
1367 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
1368 | 0 | } |
1369 | | |
1370 | | NS_IMETHODIMP |
1371 | | OutputStreamShim::WriteSegments(nsReadSegmentFun aReader, void *aClosure, uint32_t aCount, uint32_t *_retval) |
1372 | 0 | { |
1373 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
1374 | 0 | } |
1375 | | |
1376 | | NS_IMETHODIMP |
1377 | | OutputStreamShim::IsNonBlocking(bool *_retval) |
1378 | 0 | { |
1379 | 0 | *_retval = true; |
1380 | 0 | return NS_OK; |
1381 | 0 | } |
1382 | | |
1383 | | NS_IMETHODIMP |
1384 | | InputStreamShim::AsyncWait(nsIInputStreamCallback *callback, |
1385 | | unsigned int, unsigned int, nsIEventTarget *target) |
1386 | 0 | { |
1387 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
1388 | 0 | bool currentThread; |
1389 | 0 |
|
1390 | 0 | if (target && |
1391 | 0 | (NS_FAILED(target->IsOnCurrentThread(¤tThread)) || !currentThread)) { |
1392 | 0 | return NS_ERROR_FAILURE; |
1393 | 0 | } |
1394 | 0 | |
1395 | 0 | LOG(("InputStreamShim::AsyncWait %p callback %p\n", this, callback)); |
1396 | 0 | mCallback = callback; |
1397 | 0 | return NS_OK; |
1398 | 0 | } |
1399 | | |
1400 | | NS_IMETHODIMP |
1401 | | InputStreamShim::CloseWithStatus(nsresult reason) |
1402 | 0 | { |
1403 | 0 | RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans)); |
1404 | 0 | if (!baseTrans) { |
1405 | 0 | return NS_ERROR_FAILURE; |
1406 | 0 | } |
1407 | 0 | SpdyConnectTransaction *trans = baseTrans->QuerySpdyConnectTransaction(); |
1408 | 0 | MOZ_ASSERT(trans); |
1409 | 0 | if (!trans) { |
1410 | 0 | return NS_ERROR_UNEXPECTED; |
1411 | 0 | } |
1412 | 0 | |
1413 | 0 | trans->mSession->CloseTransaction(trans, reason); |
1414 | 0 | return NS_OK; |
1415 | 0 | } |
1416 | | |
1417 | | NS_IMETHODIMP |
1418 | | InputStreamShim::Close() |
1419 | 0 | { |
1420 | 0 | return CloseWithStatus(NS_OK); |
1421 | 0 | } |
1422 | | |
1423 | | NS_IMETHODIMP |
1424 | | InputStreamShim::Available(uint64_t *_retval) |
1425 | 0 | { |
1426 | 0 | RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans)); |
1427 | 0 | if (!baseTrans) { |
1428 | 0 | return NS_ERROR_FAILURE; |
1429 | 0 | } |
1430 | 0 | SpdyConnectTransaction *trans = baseTrans->QuerySpdyConnectTransaction(); |
1431 | 0 | MOZ_ASSERT(trans); |
1432 | 0 | if (!trans) { |
1433 | 0 | return NS_ERROR_UNEXPECTED; |
1434 | 0 | } |
1435 | 0 | |
1436 | 0 | *_retval = trans->mInputDataUsed - trans->mInputDataOffset; |
1437 | 0 | return NS_OK; |
1438 | 0 | } |
1439 | | |
1440 | | NS_IMETHODIMP |
1441 | | InputStreamShim::Read(char *aBuf, uint32_t aCount, uint32_t *_retval) |
1442 | 0 | { |
1443 | 0 | MOZ_ASSERT(OnSocketThread(), "not on socket thread"); |
1444 | 0 |
|
1445 | 0 | if (NS_FAILED(mStatus)) { |
1446 | 0 | return mStatus; |
1447 | 0 | } |
1448 | 0 | |
1449 | 0 | RefPtr<NullHttpTransaction> baseTrans(do_QueryReferent(mWeakTrans)); |
1450 | 0 | if (!baseTrans) { |
1451 | 0 | return NS_ERROR_FAILURE; |
1452 | 0 | } |
1453 | 0 | SpdyConnectTransaction *trans = baseTrans->QuerySpdyConnectTransaction(); |
1454 | 0 | MOZ_ASSERT(trans); |
1455 | 0 | if (!trans) { |
1456 | 0 | return NS_ERROR_UNEXPECTED; |
1457 | 0 | } |
1458 | 0 | |
1459 | 0 | uint32_t avail = trans->mInputDataUsed - trans->mInputDataOffset; |
1460 | 0 | uint32_t tocopy = std::min(aCount, avail); |
1461 | 0 | *_retval = tocopy; |
1462 | 0 | memcpy(aBuf, &trans->mInputData[trans->mInputDataOffset], tocopy); |
1463 | 0 | trans->mInputDataOffset += tocopy; |
1464 | 0 | if (trans->mInputDataOffset == trans->mInputDataUsed) { |
1465 | 0 | trans->mInputDataOffset = trans->mInputDataUsed = 0; |
1466 | 0 | } |
1467 | 0 |
|
1468 | 0 | return tocopy ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK; |
1469 | 0 | } |
1470 | | |
1471 | | NS_IMETHODIMP |
1472 | | InputStreamShim::ReadSegments(nsWriteSegmentFun aWriter, void *aClosure, |
1473 | | uint32_t aCount, uint32_t *_retval) |
1474 | 0 | { |
1475 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
1476 | 0 | } |
1477 | | |
1478 | | NS_IMETHODIMP |
1479 | | InputStreamShim::IsNonBlocking(bool *_retval) |
1480 | 0 | { |
1481 | 0 | *_retval = true; |
1482 | 0 | return NS_OK; |
1483 | 0 | } |
1484 | | |
1485 | | NS_IMETHODIMP |
1486 | | SocketTransportShim::SetKeepaliveEnabled(bool aKeepaliveEnabled) |
1487 | 0 | { |
1488 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
1489 | 0 | } |
1490 | | |
1491 | | NS_IMETHODIMP |
1492 | | SocketTransportShim::SetKeepaliveVals(int32_t keepaliveIdleTime, int32_t keepaliveRetryInterval) |
1493 | 0 | { |
1494 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
1495 | 0 | } |
1496 | | |
1497 | | NS_IMETHODIMP |
1498 | | SocketTransportShim::SetSecurityCallbacks(nsIInterfaceRequestor *aSecurityCallbacks) |
1499 | 0 | { |
1500 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
1501 | 0 | } |
1502 | | |
1503 | | NS_IMETHODIMP |
1504 | | SocketTransportShim::OpenInputStream(uint32_t aFlags, uint32_t aSegmentSize, |
1505 | | uint32_t aSegmentCount, nsIInputStream * *_retval) |
1506 | 0 | { |
1507 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
1508 | 0 | } |
1509 | | |
1510 | | NS_IMETHODIMP |
1511 | | SocketTransportShim::OpenOutputStream(uint32_t aFlags, uint32_t aSegmentSize, |
1512 | | uint32_t aSegmentCount, nsIOutputStream * *_retval) |
1513 | 0 | { |
1514 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
1515 | 0 | } |
1516 | | |
1517 | | NS_IMETHODIMP |
1518 | | SocketTransportShim::Close(nsresult aReason) |
1519 | 0 | { |
1520 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
1521 | 0 | } |
1522 | | |
1523 | | NS_IMETHODIMP |
1524 | | SocketTransportShim::SetEventSink(nsITransportEventSink *aSink, nsIEventTarget *aEventTarget) |
1525 | 0 | { |
1526 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
1527 | 0 | } |
1528 | | |
1529 | | NS_IMETHODIMP |
1530 | | SocketTransportShim::Bind(NetAddr *aLocalAddr) |
1531 | 0 | { |
1532 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
1533 | 0 | } |
1534 | | |
1535 | | NS_IMETHODIMP |
1536 | | SocketTransportShim::GetFirstRetryError(nsresult *aFirstRetryError) |
1537 | 0 | { |
1538 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
1539 | 0 | } |
1540 | | |
1541 | | NS_IMETHODIMP |
1542 | | SocketTransportShim::GetEsniUsed(bool *aEsniUsed) |
1543 | 0 | { |
1544 | 0 | return NS_ERROR_NOT_IMPLEMENTED; |
1545 | 0 | } |
1546 | | |
1547 | | |
1548 | | #define FWD_TS_PTR(fx, ts) NS_IMETHODIMP \ |
1549 | 0 | SocketTransportShim::fx(ts *arg) { return mWrapped->fx(arg); } Unexecuted instantiation: mozilla::net::SocketTransportShim::GetKeepaliveEnabled(bool*) Unexecuted instantiation: mozilla::net::SocketTransportShim::GetSendBufferSize(unsigned int*) Unexecuted instantiation: mozilla::net::SocketTransportShim::GetPort(int*) Unexecuted instantiation: mozilla::net::SocketTransportShim::GetPeerAddr(mozilla::net::NetAddr*) Unexecuted instantiation: mozilla::net::SocketTransportShim::GetSelfAddr(mozilla::net::NetAddr*) Unexecuted instantiation: mozilla::net::SocketTransportShim::IsAlive(bool*) Unexecuted instantiation: mozilla::net::SocketTransportShim::GetConnectionFlags(unsigned int*) Unexecuted instantiation: mozilla::net::SocketTransportShim::GetTlsFlags(unsigned int*) Unexecuted instantiation: mozilla::net::SocketTransportShim::GetRecvBufferSize(unsigned int*) Unexecuted instantiation: mozilla::net::SocketTransportShim::GetResetIPFamilyPreference(bool*) |
1550 | | |
1551 | | #define FWD_TS_ADDREF(fx, ts) NS_IMETHODIMP \ |
1552 | 0 | SocketTransportShim::fx(ts **arg) { return mWrapped->fx(arg); } Unexecuted instantiation: mozilla::net::SocketTransportShim::GetScriptablePeerAddr(nsINetAddr**) Unexecuted instantiation: mozilla::net::SocketTransportShim::GetScriptableSelfAddr(nsINetAddr**) Unexecuted instantiation: mozilla::net::SocketTransportShim::GetSecurityInfo(nsISupports**) Unexecuted instantiation: mozilla::net::SocketTransportShim::GetSecurityCallbacks(nsIInterfaceRequestor**) |
1553 | | |
1554 | | #define FWD_TS(fx, ts) NS_IMETHODIMP \ |
1555 | 0 | SocketTransportShim::fx(ts arg) { return mWrapped->fx(arg); } Unexecuted instantiation: mozilla::net::SocketTransportShim::SetSendBufferSize(unsigned int) Unexecuted instantiation: mozilla::net::SocketTransportShim::SetConnectionFlags(unsigned int) Unexecuted instantiation: mozilla::net::SocketTransportShim::SetTlsFlags(unsigned int) Unexecuted instantiation: mozilla::net::SocketTransportShim::SetRecvBufferSize(unsigned int) |
1556 | | |
1557 | | FWD_TS_PTR(GetKeepaliveEnabled, bool); |
1558 | | FWD_TS_PTR(GetSendBufferSize, uint32_t); |
1559 | | FWD_TS(SetSendBufferSize, uint32_t); |
1560 | | FWD_TS_PTR(GetPort, int32_t); |
1561 | | FWD_TS_PTR(GetPeerAddr, mozilla::net::NetAddr); |
1562 | | FWD_TS_PTR(GetSelfAddr, mozilla::net::NetAddr); |
1563 | | FWD_TS_ADDREF(GetScriptablePeerAddr, nsINetAddr); |
1564 | | FWD_TS_ADDREF(GetScriptableSelfAddr, nsINetAddr); |
1565 | | FWD_TS_ADDREF(GetSecurityInfo, nsISupports); |
1566 | | FWD_TS_ADDREF(GetSecurityCallbacks, nsIInterfaceRequestor); |
1567 | | FWD_TS_PTR(IsAlive, bool); |
1568 | | FWD_TS_PTR(GetConnectionFlags, uint32_t); |
1569 | | FWD_TS(SetConnectionFlags, uint32_t); |
1570 | | FWD_TS_PTR(GetTlsFlags, uint32_t); |
1571 | | FWD_TS(SetTlsFlags, uint32_t); |
1572 | | FWD_TS_PTR(GetRecvBufferSize, uint32_t); |
1573 | | FWD_TS(SetRecvBufferSize, uint32_t); |
1574 | | FWD_TS_PTR(GetResetIPFamilyPreference, bool); |
1575 | | |
1576 | | nsresult |
1577 | | SocketTransportShim::GetOriginAttributes(mozilla::OriginAttributes* aOriginAttributes) |
1578 | 0 | { |
1579 | 0 | return mWrapped->GetOriginAttributes(aOriginAttributes); |
1580 | 0 | } |
1581 | | |
1582 | | nsresult |
1583 | | SocketTransportShim::SetOriginAttributes(const mozilla::OriginAttributes& aOriginAttributes) |
1584 | 0 | { |
1585 | 0 | return mWrapped->SetOriginAttributes(aOriginAttributes); |
1586 | 0 | } |
1587 | | |
1588 | | NS_IMETHODIMP |
1589 | | SocketTransportShim::GetScriptableOriginAttributes(JSContext* aCx, |
1590 | | JS::MutableHandle<JS::Value> aOriginAttributes) |
1591 | 0 | { |
1592 | 0 | return mWrapped->GetScriptableOriginAttributes(aCx, aOriginAttributes); |
1593 | 0 | } |
1594 | | |
1595 | | NS_IMETHODIMP |
1596 | | SocketTransportShim::SetScriptableOriginAttributes(JSContext* aCx, |
1597 | | JS::Handle<JS::Value> aOriginAttributes) |
1598 | 0 | { |
1599 | 0 | return mWrapped->SetScriptableOriginAttributes(aCx, aOriginAttributes); |
1600 | 0 | } |
1601 | | |
1602 | | NS_IMETHODIMP |
1603 | | SocketTransportShim::GetHost(nsACString & aHost) |
1604 | 0 | { |
1605 | 0 | return mWrapped->GetHost(aHost); |
1606 | 0 | } |
1607 | | |
1608 | | NS_IMETHODIMP |
1609 | | SocketTransportShim::GetTimeout(uint32_t aType, uint32_t *_retval) |
1610 | 0 | { |
1611 | 0 | return mWrapped->GetTimeout(aType, _retval); |
1612 | 0 | } |
1613 | | |
1614 | | NS_IMETHODIMP |
1615 | | SocketTransportShim::SetTimeout(uint32_t aType, uint32_t aValue) |
1616 | 0 | { |
1617 | 0 | return mWrapped->SetTimeout(aType, aValue); |
1618 | 0 | } |
1619 | | |
1620 | | NS_IMETHODIMP |
1621 | | SocketTransportShim::SetReuseAddrPort(bool aReuseAddrPort) |
1622 | 0 | { |
1623 | 0 | return mWrapped->SetReuseAddrPort(aReuseAddrPort); |
1624 | 0 | } |
1625 | | |
1626 | | NS_IMETHODIMP |
1627 | | SocketTransportShim::GetQoSBits(uint8_t *aQoSBits) |
1628 | 0 | { |
1629 | 0 | return mWrapped->GetQoSBits(aQoSBits); |
1630 | 0 | } |
1631 | | |
1632 | | NS_IMETHODIMP |
1633 | | SocketTransportShim::SetQoSBits(uint8_t aQoSBits) |
1634 | 0 | { |
1635 | 0 | return mWrapped->SetQoSBits(aQoSBits); |
1636 | 0 | } |
1637 | | |
1638 | | NS_IMETHODIMP |
1639 | | SocketTransportShim::SetFastOpenCallback(TCPFastOpen *aFastOpen) |
1640 | 0 | { |
1641 | 0 | return mWrapped->SetFastOpenCallback(aFastOpen); |
1642 | 0 | } |
1643 | | |
1644 | | NS_IMPL_ISUPPORTS(TLSFilterTransaction, nsITimerCallback, nsINamed) |
1645 | | NS_IMPL_ISUPPORTS(SocketTransportShim, nsISocketTransport, nsITransport) |
1646 | | NS_IMPL_ISUPPORTS(InputStreamShim, nsIInputStream, nsIAsyncInputStream) |
1647 | | NS_IMPL_ISUPPORTS(OutputStreamShim, nsIOutputStream, nsIAsyncOutputStream) |
1648 | | NS_IMPL_ISUPPORTS(SocketInWrapper, nsIAsyncInputStream) |
1649 | | NS_IMPL_ISUPPORTS(SocketOutWrapper, nsIAsyncOutputStream) |
1650 | | |
1651 | | } // namespace net |
1652 | | } // namespace mozilla |