Http3StreamTunnel.cpp (23637B)
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 "nsHttpHandler.h" 11 #include "Http3StreamTunnel.h" 12 #include "Http3Session.h" 13 #include "nsQueryObject.h" 14 15 namespace mozilla::net { 16 17 //----------------------------------------------------------------------------- 18 // Http3TransportLayer::InputStreamTunnel impl 19 //----------------------------------------------------------------------------- 20 21 NS_IMPL_QUERY_INTERFACE(Http3TransportLayer::InputStreamTunnel, nsIInputStream, 22 nsIAsyncInputStream) 23 24 NS_IMETHODIMP_(MozExternalRefCountType) 25 Http3TransportLayer::InputStreamTunnel::AddRef() { 26 return mTransport->AddRef(); 27 } 28 29 NS_IMETHODIMP_(MozExternalRefCountType) 30 Http3TransportLayer::InputStreamTunnel::Release() { 31 return mTransport->Release(); 32 } 33 34 Http3TransportLayer::InputStreamTunnel::InputStreamTunnel( 35 Http3TransportLayer* aTransport) 36 : mTransport(aTransport) {} 37 38 NS_IMETHODIMP 39 Http3TransportLayer::InputStreamTunnel::Close() { 40 LOG(("Http3TransportLayer::InputStreamTunnel::Close [this=%p]\n", this)); 41 return CloseWithStatus(NS_BASE_STREAM_CLOSED); 42 } 43 44 NS_IMETHODIMP Http3TransportLayer::InputStreamTunnel::Available( 45 uint64_t* avail) { 46 LOG(("Http3TransportLayer::InputStreamTunnel::Available [this=%p]\n", this)); 47 48 if (NS_FAILED(mCondition)) { 49 return mCondition; 50 } 51 52 return NS_ERROR_FAILURE; 53 } 54 55 NS_IMETHODIMP Http3TransportLayer::InputStreamTunnel::StreamStatus() { 56 LOG(("Http3TransportLayer::InputStreamTunnel::StreamStatus [this=%p]\n", 57 this)); 58 return mCondition; 59 } 60 61 NS_IMETHODIMP 62 Http3TransportLayer::InputStreamTunnel::Read(char* buf, uint32_t count, 63 uint32_t* countRead) { 64 LOG(("Http3TransportLayer::InputStreamTunnel::Read [this=%p]\n", this)); 65 66 *countRead = 0; 67 68 if (NS_FAILED(mCondition)) { 69 return mCondition; 70 } 71 72 RefPtr<Http3StreamTunnel> tunnel = mTransport->GetStream(); 73 if (!tunnel) { 74 return NS_ERROR_UNEXPECTED; 75 } 76 77 return tunnel->OnWriteSegment(buf, count, countRead); 78 } 79 80 NS_IMETHODIMP 81 Http3TransportLayer::InputStreamTunnel::ReadSegments(nsWriteSegmentFun writer, 82 void* closure, 83 uint32_t count, 84 uint32_t* countRead) { 85 return NS_ERROR_NOT_IMPLEMENTED; 86 } 87 88 NS_IMETHODIMP 89 Http3TransportLayer::InputStreamTunnel::IsNonBlocking(bool* nonblocking) { 90 *nonblocking = true; 91 return NS_OK; 92 } 93 94 NS_IMETHODIMP 95 Http3TransportLayer::InputStreamTunnel::CloseWithStatus(nsresult reason) { 96 LOG( 97 ("Http3TransportLayer::InputStreamTunnel::CloseWithStatus [this=%p " 98 "reason=%" PRIx32 "]\n", 99 this, static_cast<uint32_t>(reason))); 100 mCondition = reason; 101 102 RefPtr<Http3StreamTunnel> tunnel = mTransport->GetStream(); 103 if (!tunnel) { 104 return NS_OK; 105 } 106 107 tunnel->CleanupStream(reason); 108 return NS_OK; 109 } 110 111 nsresult Http3TransportLayer::InputStreamTunnel::OnSocketReady( 112 nsresult condition) { 113 LOG(("InputStreamTunnel::OnSocketReady [this=%p cond=%" PRIx32 "]\n", this, 114 static_cast<uint32_t>(condition))); 115 116 nsCOMPtr<nsIInputStreamCallback> callback; 117 118 // update condition, but be careful not to erase an already 119 // existing error condition. 120 if (NS_SUCCEEDED(mCondition)) { 121 mCondition = condition; 122 } 123 callback = std::move(mCallback); 124 125 return callback ? callback->OnInputStreamReady(this) : NS_OK; 126 } 127 128 NS_IMETHODIMP 129 Http3TransportLayer::InputStreamTunnel::AsyncWait( 130 nsIInputStreamCallback* callback, uint32_t flags, uint32_t amount, 131 nsIEventTarget* target) { 132 LOG( 133 ("Http3TransportLayer::InputStreamTunnel::AsyncWait [this=%p, " 134 "callback=%p]\n", 135 this, callback)); 136 // The following parameters are not used: 137 MOZ_ASSERT(!flags); 138 MOZ_ASSERT(!amount); 139 (void)target; 140 141 RefPtr<InputStreamTunnel> self(this); 142 if (NS_FAILED(mCondition)) { 143 (void)NS_DispatchToCurrentThread(NS_NewRunnableFunction( 144 "InputStreamTunnel::CallOnSocketReady", 145 [self{std::move(self)}]() { self->OnSocketReady(self->mCondition); })); 146 } else if (callback) { 147 RefPtr<Http3StreamTunnel> tunnel = mTransport->GetStream(); 148 if (!tunnel) { 149 return NS_ERROR_UNEXPECTED; 150 } 151 tunnel->HasDataToRead(); 152 } 153 154 mCallback = callback; 155 return NS_OK; 156 } 157 158 //----------------------------------------------------------------------------- 159 // Http3TransportLayer::OutputStreamTunnel impl 160 //----------------------------------------------------------------------------- 161 162 NS_IMPL_QUERY_INTERFACE(Http3TransportLayer::OutputStreamTunnel, 163 nsIOutputStream, nsIAsyncOutputStream) 164 165 NS_IMETHODIMP_(MozExternalRefCountType) 166 Http3TransportLayer::OutputStreamTunnel::AddRef() { 167 return mTransport->AddRef(); 168 } 169 170 NS_IMETHODIMP_(MozExternalRefCountType) 171 Http3TransportLayer::OutputStreamTunnel::Release() { 172 return mTransport->Release(); 173 } 174 175 Http3TransportLayer::OutputStreamTunnel::OutputStreamTunnel( 176 Http3TransportLayer* aTransport) 177 : mTransport(aTransport) {} 178 179 NS_IMETHODIMP 180 Http3TransportLayer::OutputStreamTunnel::Close() { 181 LOG(("Http3TransportLayer::OutputStreamTunnel::Close [this=%p]\n", this)); 182 return CloseWithStatus(NS_BASE_STREAM_CLOSED); 183 } 184 185 NS_IMETHODIMP 186 Http3TransportLayer::OutputStreamTunnel::Flush() { 187 LOG(("Http3TransportLayer::OutputStreamTunnel::Flush [this=%p]\n", this)); 188 return NS_OK; 189 } 190 191 NS_IMETHODIMP 192 Http3TransportLayer::OutputStreamTunnel::StreamStatus() { 193 LOG(("TLSTransportLayerOutputStream::StreamStatus [this=%p]\n", this)); 194 return mCondition; 195 } 196 197 NS_IMETHODIMP 198 Http3TransportLayer::OutputStreamTunnel::Write(const char* buf, uint32_t count, 199 uint32_t* countWritten) { 200 LOG(("Http3TransportLayer::OutputStreamTunnel::Write [this=%p count=%u]\n", 201 this, count)); 202 *countWritten = 0; 203 if (NS_FAILED(mCondition)) { 204 return mCondition; 205 } 206 207 RefPtr<Http3StreamTunnel> tunnel = mTransport->GetStream(); 208 if (!tunnel) { 209 return NS_ERROR_UNEXPECTED; 210 } 211 212 tunnel->HasDataToWrite(); 213 return tunnel->OnReadSegment(buf, count, countWritten); 214 } 215 216 NS_IMETHODIMP 217 Http3TransportLayer::OutputStreamTunnel::WriteSegments(nsReadSegmentFun reader, 218 void* closure, 219 uint32_t count, 220 uint32_t* countRead) { 221 return NS_ERROR_NOT_IMPLEMENTED; 222 } 223 224 NS_IMETHODIMP 225 Http3TransportLayer::OutputStreamTunnel::WriteFrom(nsIInputStream* stream, 226 uint32_t count, 227 uint32_t* countRead) { 228 return NS_ERROR_NOT_IMPLEMENTED; 229 } 230 231 NS_IMETHODIMP 232 Http3TransportLayer::OutputStreamTunnel::IsNonBlocking(bool* nonblocking) { 233 *nonblocking = true; 234 return NS_OK; 235 } 236 237 NS_IMETHODIMP 238 Http3TransportLayer::OutputStreamTunnel::CloseWithStatus(nsresult reason) { 239 LOG(("OutputStreamTunnel::CloseWithStatus [this=%p reason=%" PRIx32 "]\n", 240 this, static_cast<uint32_t>(reason))); 241 mCondition = reason; 242 243 RefPtr<Http3StreamTunnel> tunnel = mTransport->GetStream(); 244 if (!tunnel) { 245 return NS_OK; 246 } 247 248 tunnel->CleanupStream(reason); 249 return NS_OK; 250 } 251 252 nsresult Http3TransportLayer::OutputStreamTunnel::OnSocketReady( 253 nsresult condition) { 254 LOG(("OutputStreamTunnel::OnSocketReady [this=%p cond=%" PRIx32 255 " callback=%p]\n", 256 this, static_cast<uint32_t>(condition), mCallback.get())); 257 258 nsCOMPtr<nsIOutputStreamCallback> callback; 259 260 // update condition, but be careful not to erase an already 261 // existing error condition. 262 if (NS_SUCCEEDED(mCondition)) { 263 mCondition = condition; 264 } 265 callback = std::move(mCallback); 266 267 nsresult rv = NS_OK; 268 if (callback) { 269 rv = callback->OnOutputStreamReady(this); 270 MaybeSetRequestDone(callback); 271 } 272 273 return rv; 274 } 275 276 void Http3TransportLayer::OutputStreamTunnel::MaybeSetRequestDone( 277 nsIOutputStreamCallback* aCallback) { 278 RefPtr<nsHttpConnection> conn = do_QueryObject(aCallback); 279 if (!conn) { 280 return; 281 } 282 283 RefPtr<Http3StreamTunnel> tunnel = mTransport->GetStream(); 284 if (!tunnel) { 285 return; 286 } 287 288 if (conn->RequestDone()) { 289 tunnel->SetRequestDone(); 290 } 291 } 292 293 NS_IMETHODIMP 294 Http3TransportLayer::OutputStreamTunnel::AsyncWait( 295 nsIOutputStreamCallback* callback, uint32_t flags, uint32_t amount, 296 nsIEventTarget* target) { 297 LOG(("OutputStreamTunnel::AsyncWait [this=%p]\n", this)); 298 299 // The following parameters are not used: 300 MOZ_ASSERT(!flags); 301 MOZ_ASSERT(!amount); 302 (void)target; 303 304 RefPtr<OutputStreamTunnel> self(this); 305 if (NS_FAILED(mCondition)) { 306 (void)NS_DispatchToCurrentThread(NS_NewRunnableFunction( 307 "OutputStreamTunnel::CallOnSocketReady", 308 [self{std::move(self)}]() { self->OnSocketReady(self->mCondition); })); 309 } else if (callback) { 310 // Inform the proxy connection that the inner connetion wants to 311 // read data. 312 RefPtr<Http3StreamTunnel> tunnel = mTransport->GetStream(); 313 if (!tunnel) { 314 return NS_ERROR_UNEXPECTED; 315 } 316 tunnel->HasDataToWrite(); 317 } 318 319 mCallback = callback; 320 return NS_OK; 321 } 322 323 //----------------------------------------------------------------------------- 324 // Http3TransportLayer impl 325 //----------------------------------------------------------------------------- 326 327 NS_IMPL_ISUPPORTS(Http3TransportLayer, nsISocketTransport, nsITransport, 328 nsIInputStreamCallback, nsIOutputStreamCallback) 329 330 Http3TransportLayer::Http3TransportLayer(Http3StreamTunnel* aStream) 331 : mStream(aStream), mInput(this), mOutput(this) { 332 LOG(("Http3TransportLayer ctor %p", this)); 333 } 334 335 Http3TransportLayer::~Http3TransportLayer() { 336 LOG(("Http3TransportLayer dtor %p", this)); 337 } 338 339 already_AddRefed<Http3StreamTunnel> Http3TransportLayer::GetStream() { 340 RefPtr<Http3StreamTunnel> stream = mStream; 341 return stream.forget(); 342 } 343 344 nsIAsyncInputStream* Http3TransportLayer::GetInput() { return &mInput; } 345 346 nsIAsyncOutputStream* Http3TransportLayer::GetOutput() { return &mOutput; } 347 348 nsresult Http3TransportLayer::CallToReadData() { 349 LOG(("Http3TransportLayer::CallToReadData this=%p", this)); 350 return mOutput.OnSocketReady(NS_OK); 351 } 352 353 nsresult Http3TransportLayer::CallToWriteData() { 354 LOG(("Http3TransportLayer::CallToWriteData this=%p", this)); 355 if (!mInput.HasCallback()) { 356 return NS_BASE_STREAM_WOULD_BLOCK; 357 } 358 return mInput.OnSocketReady(NS_OK); 359 } 360 361 NS_IMETHODIMP 362 Http3TransportLayer::OnInputStreamReady(nsIAsyncInputStream* in) { 363 return NS_OK; 364 } 365 366 NS_IMETHODIMP 367 Http3TransportLayer::OnOutputStreamReady(nsIAsyncOutputStream* out) { 368 return NS_OK; 369 } 370 371 NS_IMETHODIMP 372 Http3TransportLayer::SetKeepaliveEnabled(bool aKeepaliveEnabled) { 373 return NS_ERROR_NOT_IMPLEMENTED; 374 } 375 376 NS_IMETHODIMP 377 Http3TransportLayer::SetKeepaliveVals(int32_t keepaliveIdleTime, 378 int32_t keepaliveRetryInterval) { 379 return NS_ERROR_NOT_IMPLEMENTED; 380 } 381 382 NS_IMETHODIMP 383 Http3TransportLayer::GetSecurityCallbacks( 384 nsIInterfaceRequestor** aSecurityCallbacks) { 385 return NS_ERROR_NOT_IMPLEMENTED; 386 } 387 388 NS_IMETHODIMP 389 Http3TransportLayer::SetSecurityCallbacks( 390 nsIInterfaceRequestor* aSecurityCallbacks) { 391 return NS_OK; 392 } 393 394 NS_IMETHODIMP 395 Http3TransportLayer::OpenInputStream(uint32_t aFlags, uint32_t aSegmentSize, 396 uint32_t aSegmentCount, 397 nsIInputStream** _retval) { 398 return NS_ERROR_NOT_IMPLEMENTED; 399 } 400 401 NS_IMETHODIMP 402 Http3TransportLayer::OpenOutputStream(uint32_t aFlags, uint32_t aSegmentSize, 403 uint32_t aSegmentCount, 404 nsIOutputStream** _retval) { 405 return NS_ERROR_NOT_IMPLEMENTED; 406 } 407 408 NS_IMETHODIMP 409 Http3TransportLayer::Close(nsresult aReason) { 410 LOG(("Http3TransportLayer::Close [this=%p reason=%" PRIx32 "]\n", this, 411 static_cast<uint32_t>(aReason))); 412 if (NS_SUCCEEDED(mCondition)) { 413 if (NS_SUCCEEDED(aReason)) { 414 aReason = NS_BASE_STREAM_CLOSED; 415 } 416 mOutput.CloseWithStatus(aReason); 417 mInput.CloseWithStatus(aReason); 418 // Let the session pickup that the stream has been closed. 419 mCondition = aReason; 420 } 421 return NS_OK; 422 } 423 424 void Http3TransportLayer::OnStreamClosed(nsresult aReason) { 425 LOG(("Http3TransportLayer::OnStreamClosed this=%p", this)); 426 if (NS_SUCCEEDED(mCondition)) { 427 if (NS_SUCCEEDED(aReason)) { 428 aReason = NS_BASE_STREAM_CLOSED; 429 } 430 mOutput.OnSocketReady(aReason); 431 mInput.OnSocketReady(aReason); 432 mCondition = aReason; 433 } 434 } 435 436 NS_IMETHODIMP 437 Http3TransportLayer::SetEventSink(nsITransportEventSink* aSink, 438 nsIEventTarget* aEventTarget) { 439 return NS_OK; 440 } 441 442 NS_IMETHODIMP 443 Http3TransportLayer::Bind(NetAddr* aLocalAddr) { 444 return NS_ERROR_NOT_IMPLEMENTED; 445 } 446 447 NS_IMETHODIMP 448 Http3TransportLayer::GetEchConfigUsed(bool* aEchConfigUsed) { 449 return NS_ERROR_NOT_IMPLEMENTED; 450 } 451 452 NS_IMETHODIMP 453 Http3TransportLayer::SetEchConfig(const nsACString& aEchConfig) { 454 return NS_ERROR_NOT_IMPLEMENTED; 455 } 456 457 NS_IMETHODIMP 458 Http3TransportLayer::ResolvedByTRR(bool* aResolvedByTRR) { 459 return NS_ERROR_NOT_IMPLEMENTED; 460 } 461 462 NS_IMETHODIMP Http3TransportLayer::GetEffectiveTRRMode( 463 nsIRequest::TRRMode* aEffectiveTRRMode) { 464 return NS_ERROR_NOT_IMPLEMENTED; 465 } 466 467 NS_IMETHODIMP Http3TransportLayer::GetTrrSkipReason( 468 nsITRRSkipReason::value* aTrrSkipReason) { 469 return NS_ERROR_NOT_IMPLEMENTED; 470 } 471 472 #define FWD_H3ST_PTR(fx, ts) \ 473 NS_IMETHODIMP \ 474 Http3TransportLayer::fx(ts* arg) { return NS_OK; } 475 476 #define FWD_H3ST_ADDREF(fx, ts) \ 477 NS_IMETHODIMP \ 478 Http3TransportLayer::fx(ts** arg) { return NS_OK; } 479 480 #define FWD_H3ST(fx, ts) \ 481 NS_IMETHODIMP \ 482 Http3TransportLayer::fx(ts arg) { return NS_OK; } 483 484 FWD_H3ST_PTR(GetKeepaliveEnabled, bool); 485 FWD_H3ST_PTR(GetSendBufferSize, uint32_t); 486 FWD_H3ST(SetSendBufferSize, uint32_t); 487 FWD_H3ST_PTR(GetPort, int32_t); 488 FWD_H3ST_PTR(GetSelfAddr, mozilla::net::NetAddr); 489 FWD_H3ST_ADDREF(GetScriptablePeerAddr, nsINetAddr); 490 FWD_H3ST_ADDREF(GetScriptableSelfAddr, nsINetAddr); 491 FWD_H3ST_PTR(GetConnectionFlags, uint32_t); 492 FWD_H3ST(SetConnectionFlags, uint32_t); 493 FWD_H3ST(SetIsPrivate, bool); 494 FWD_H3ST_PTR(GetTlsFlags, uint32_t); 495 FWD_H3ST(SetTlsFlags, uint32_t); 496 FWD_H3ST_PTR(GetRecvBufferSize, uint32_t); 497 FWD_H3ST(SetRecvBufferSize, uint32_t); 498 FWD_H3ST_PTR(GetResetIPFamilyPreference, bool); 499 500 nsresult Http3TransportLayer::IsAlive(bool* aAlive) { 501 *aAlive = true; 502 return NS_OK; 503 } 504 505 nsresult Http3TransportLayer::GetPeerAddr(NetAddr* addr) { 506 // TODO: what address we should use? 507 NetAddr peerAddr; 508 peerAddr.InitFromString("127.0.0.1"_ns); 509 *addr = peerAddr; 510 return NS_OK; 511 } 512 513 nsresult Http3TransportLayer::GetTlsSocketControl( 514 nsITLSSocketControl** tlsSocketControl) { 515 return NS_OK; 516 } 517 518 nsresult Http3TransportLayer::GetOriginAttributes( 519 mozilla::OriginAttributes* aOriginAttributes) { 520 return NS_OK; 521 } 522 523 nsresult Http3TransportLayer::SetOriginAttributes( 524 const mozilla::OriginAttributes& aOriginAttributes) { 525 return NS_OK; 526 } 527 528 NS_IMETHODIMP 529 Http3TransportLayer::GetScriptableOriginAttributes( 530 JSContext* aCx, JS::MutableHandle<JS::Value> aOriginAttributes) { 531 return NS_OK; 532 } 533 534 NS_IMETHODIMP 535 Http3TransportLayer::SetScriptableOriginAttributes( 536 JSContext* aCx, JS::Handle<JS::Value> aOriginAttributes) { 537 return NS_OK; 538 } 539 540 NS_IMETHODIMP 541 Http3TransportLayer::GetHost(nsACString& aHost) { return NS_OK; } 542 543 NS_IMETHODIMP 544 Http3TransportLayer::GetTimeout(uint32_t aType, uint32_t* _retval) { 545 return NS_OK; 546 } 547 548 NS_IMETHODIMP 549 Http3TransportLayer::SetTimeout(uint32_t aType, uint32_t aValue) { 550 return NS_OK; 551 } 552 553 NS_IMETHODIMP 554 Http3TransportLayer::SetReuseAddrPort(bool aReuseAddrPort) { return NS_OK; } 555 556 NS_IMETHODIMP 557 Http3TransportLayer::SetLinger(bool aPolarity, int16_t aTimeout) { 558 return NS_OK; 559 } 560 561 NS_IMETHODIMP 562 Http3TransportLayer::GetQoSBits(uint8_t* aQoSBits) { return NS_OK; } 563 564 NS_IMETHODIMP 565 Http3TransportLayer::SetQoSBits(uint8_t aQoSBits) { return NS_OK; } 566 567 NS_IMETHODIMP 568 Http3TransportLayer::GetRetryDnsIfPossible(bool* aRetry) { return NS_OK; } 569 570 NS_IMETHODIMP 571 Http3TransportLayer::GetStatus(nsresult* aStatus) { 572 *aStatus = mCondition; 573 return NS_OK; 574 } 575 576 //----------------------------------------------------------------------------- 577 // Http3StreamTunnel impl 578 //----------------------------------------------------------------------------- 579 580 Http3StreamTunnel::Http3StreamTunnel(nsAHttpTransaction* aTrans, 581 Http3Session* aSession, 582 uint64_t aCurrentBrowserId) 583 : Http3Stream(aTrans, aSession, ClassOfService(), aCurrentBrowserId) { 584 LOG(("Http3StreamTunnel ctor %p", this)); 585 } 586 587 Http3StreamTunnel::~Http3StreamTunnel() { 588 LOG(("Http3StreamTunnel dtor %p", this)); 589 } 590 591 nsresult Http3StreamTunnel::TryActivating() { 592 nsProxyInfo* info = mTransaction->ConnectionInfo()->ProxyInfo(); 593 if (!info) { 594 return NS_ERROR_UNEXPECTED; 595 } 596 597 nsAutoCString host; 598 DebugOnly<nsresult> rv{}; 599 rv = nsHttpHandler::GenerateHostPort( 600 nsDependentCString(mTransaction->ConnectionInfo()->Origin()), 601 mTransaction->ConnectionInfo()->OriginPort(), host); 602 MOZ_ASSERT(NS_SUCCEEDED(rv)); 603 604 LOG(("Http3StreamTunnel::TryActivating [auth=%s]", host.get())); 605 return mSession->TryActivating("CONNECT"_ns, ""_ns, host, ""_ns, 606 mFlatHttpRequestHeaders, &mStreamId, this); 607 } 608 609 void Http3StreamTunnel::Close(nsresult aResult) { 610 LOG(("Http3StreamTunnel::Close %p", this)); 611 if (mClosed) { 612 return; 613 } 614 mClosed = true; 615 616 mRecvState = RECV_DONE; 617 mSendState = SEND_DONE; 618 619 mSession = nullptr; 620 621 if (mTransaction) { 622 mTransaction->Close(aResult); 623 } 624 625 if (mTransport) { 626 mTransport->OnStreamClosed(aResult); 627 mTransport = nullptr; 628 } 629 } 630 631 nsresult Http3StreamTunnel::ReadSegments() { 632 LOG(("Http3StreamTunnel::ReadSegments %p mSendState=%d mRecvState=%d", this, 633 mSendState, mRecvState)); 634 if (mRecvState == RECV_DONE) { 635 // Don't transmit any request frames if the peer cannot respond or respone 636 // is already done. 637 LOG3( 638 ("Http3StreamTunnel %p ReadSegments request stream aborted due to" 639 " response side closure\n", 640 this)); 641 return NS_ERROR_ABORT; 642 } 643 644 if (mSendState == SEND_DONE) { 645 return NS_OK; 646 } 647 648 if (!mTransport) { 649 return NS_ERROR_UNEXPECTED; 650 } 651 652 nsresult rv = mTransport->CallToReadData(); 653 654 if (mSendState == WAITING_TO_ACTIVATE && 655 (NS_SUCCEEDED(rv) || rv == NS_BASE_STREAM_WOULD_BLOCK)) { 656 LOG3(("Http3StreamTunnel %p ReadSegments forcing OnReadSegment call\n", 657 this)); 658 uint32_t wasted = 0; 659 nsresult rv2 = OnReadSegment("", 0, &wasted); 660 661 LOG3((" OnReadSegment returned 0x%08" PRIx32, static_cast<uint32_t>(rv2))); 662 } 663 664 return rv; 665 } 666 667 nsresult Http3StreamTunnel::BufferInput() { 668 char buf[SimpleBufferPage::kSimpleBufferPageSize]; 669 uint32_t countWritten; 670 nsresult rv = mSession->ReadResponseData( 671 mStreamId, buf, SimpleBufferPage::kSimpleBufferPageSize, &countWritten, 672 &mFin); 673 if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) { 674 return rv; 675 } 676 LOG(("Http3StreamTunnel::BufferInput %p countWritten=%d mFin=%d", this, 677 countWritten, mFin)); 678 if (countWritten == 0) { 679 if (mFin) { 680 mRecvState = RECV_DONE; 681 rv = NS_BASE_STREAM_CLOSED; 682 } else { 683 rv = NS_BASE_STREAM_WOULD_BLOCK; 684 } 685 } else { 686 mTotalRead += countWritten; 687 if (mFin) { 688 mRecvState = RECEIVED_FIN; 689 } 690 } 691 if (NS_SUCCEEDED(rv)) { 692 rv = mSimpleBuffer.Write(buf, countWritten); 693 if (NS_FAILED(rv)) { 694 MOZ_ASSERT(rv == NS_ERROR_OUT_OF_MEMORY); 695 return NS_ERROR_OUT_OF_MEMORY; 696 } 697 } 698 return rv; 699 } 700 701 nsresult Http3StreamTunnel::WriteSegments() { 702 LOG(("Http3StreamTunnel::WriteSegments [this=%p]", this)); 703 if (mRecvState == RECV_DONE) { 704 return NS_OK; 705 } 706 707 if (!mTransport) { 708 return NS_ERROR_UNEXPECTED; 709 } 710 711 nsresult rv = NS_OK; 712 bool again = true; 713 714 do { 715 mSocketInCondition = NS_OK; 716 rv = mTransport->CallToWriteData(); 717 if (mRecvState == RECV_DONE) { 718 return NS_ERROR_UNEXPECTED; 719 } 720 721 // When CallToWriteData() returns NS_BASE_STREAM_WOULD_BLOCK, it means the 722 // consumer can't accept data at the moment. We need to read the data into a 723 // buffer so it won't block other streams. 724 if (rv == NS_BASE_STREAM_WOULD_BLOCK) { 725 rv = BufferInput(); 726 } 727 728 if (mRecvState == RECEIVED_FIN) { 729 rv = NS_BASE_STREAM_CLOSED; 730 mRecvState = RECV_DONE; 731 } 732 733 if (NS_FAILED(rv)) { 734 if (rv == NS_BASE_STREAM_WOULD_BLOCK) { 735 rv = NS_OK; 736 } 737 again = false; 738 } else if (NS_FAILED(mSocketInCondition)) { 739 if (mSocketInCondition != NS_BASE_STREAM_WOULD_BLOCK) { 740 rv = mSocketInCondition; 741 } 742 again = false; 743 } 744 } while (again && gHttpHandler->Active()); 745 746 return rv; 747 } 748 749 nsresult Http3StreamTunnel::OnWriteSegment(char* buf, uint32_t count, 750 uint32_t* countWritten) { 751 LOG(("Http3StreamTunnel::OnWriteSegment [this=%p, state=%d", this, 752 mRecvState)); 753 // Sometimes we have read data from the network and stored it in a pipe 754 // so that other streams can proceed when the gecko caller is not processing 755 // data events fast enough and flow control hasn't caught up yet. This 756 // gets the stored data out of that pipe 757 if (mSimpleBuffer.Available()) { 758 *countWritten = mSimpleBuffer.Read(buf, count); 759 MOZ_ASSERT(*countWritten); 760 LOG3( 761 ("Http3StreamTunnel::OnWriteSegment read from flow " 762 "control buffer %p %d", 763 this, *countWritten)); 764 return NS_OK; 765 } 766 767 return Http3Stream::OnWriteSegment(buf, count, countWritten); 768 } 769 770 void Http3StreamTunnel::SetRequestDone() { 771 LOG(("Http3StreamTunnel::SetRequestDone %p", this)); 772 } 773 774 void Http3StreamTunnel::HasDataToWrite() { 775 mSession->StreamHasDataToWrite(this); 776 } 777 778 void Http3StreamTunnel::HasDataToRead() { 779 // We can't always call ConnectSlowConsumer(), because it triggers 780 // ForceRecv(), 781 // which posts a runnable to call WriteSegments() again. When we already have 782 // data buffered, this is fine. The consumer can read data from the buffer. 783 // However, if no data is buffered, doing this would create a busy loop that 784 // continuously waits for data. 785 if (mSimpleBuffer.Available()) { 786 mSession->ConnectSlowConsumer(this); 787 } 788 } 789 790 already_AddRefed<nsHttpConnection> Http3StreamTunnel::CreateHttpConnection( 791 nsIInterfaceRequestor* aCallbacks, PRIntervalTime aRtt, 792 bool aIsExtendedCONNECT) { 793 mTransport = new Http3TransportLayer(this); 794 RefPtr<nsHttpConnection> conn = new nsHttpConnection(); 795 796 conn->SetTransactionCaps(mTransaction->Caps()); 797 nsresult rv = 798 conn->Init(mTransaction->ConnectionInfo(), 799 gHttpHandler->ConnMgr()->MaxRequestDelay(), mTransport, 800 mTransport->GetInput(), mTransport->GetOutput(), true, NS_OK, 801 aCallbacks, aRtt, aIsExtendedCONNECT); 802 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); 803 return conn.forget(); 804 } 805 806 void Http3StreamTunnel::CleanupStream(nsresult aReason) { 807 if (mSession) { 808 LOG(("Http3StreamTunnel::CleanupStream %p", this)); 809 mSession->CloseStream(this, aReason); 810 } 811 } 812 813 } // namespace mozilla::net