Http2StreamTunnel.cpp (21074B)
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 // 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() 15 16 #include "nsHttpHandler.h" 17 #include "Http2StreamTunnel.h" 18 #include "nsHttpConnectionInfo.h" 19 #include "nsQueryObject.h" 20 #include "nsProxyRelease.h" 21 #include "mozilla/glean/NetwerkProtocolHttpMetrics.h" 22 #include "Http2Session.h" 23 24 namespace mozilla::net { 25 26 NS_IMPL_ADDREF_INHERITED(Http2StreamTunnel, Http2StreamBase) 27 NS_IMPL_RELEASE_INHERITED(Http2StreamTunnel, Http2StreamBase) 28 29 NS_INTERFACE_MAP_BEGIN(Http2StreamTunnel) 30 NS_INTERFACE_MAP_ENTRY(nsITransport) 31 NS_INTERFACE_MAP_ENTRY_CONCRETE(Http2StreamTunnel) 32 NS_INTERFACE_MAP_ENTRY(nsITransport) 33 NS_INTERFACE_MAP_ENTRY(nsISocketTransport) 34 NS_INTERFACE_MAP_END 35 36 Http2StreamTunnel::Http2StreamTunnel(Http2Session* session, int32_t priority, 37 uint64_t bcId, 38 nsHttpConnectionInfo* aConnectionInfo) 39 : Http2StreamBase(0, session, priority, bcId), 40 mConnectionInfo(aConnectionInfo) {} 41 42 Http2StreamTunnel::~Http2StreamTunnel() { ClearTransactionsBlockedOnTunnel(); } 43 44 void Http2StreamTunnel::HandleResponseHeaders(nsACString& aHeadersOut, 45 int32_t httpResponseCode) {} 46 47 // TODO We do not need this. Fix in bug 1772212. 48 void Http2StreamTunnel::ClearTransactionsBlockedOnTunnel() { 49 nsresult rv = gHttpHandler->ConnMgr()->ProcessPendingQ(mConnectionInfo); 50 if (NS_FAILED(rv)) { 51 LOG3( 52 ("Http2StreamTunnel::ClearTransactionsBlockedOnTunnel %p\n" 53 " ProcessPendingQ failed: %" PRIX32, 54 this, static_cast<uint32_t>(rv))); 55 } 56 } 57 58 NS_IMETHODIMP 59 Http2StreamTunnel::SetKeepaliveEnabled(bool aKeepaliveEnabled) { 60 return NS_ERROR_NOT_IMPLEMENTED; 61 } 62 63 NS_IMETHODIMP 64 Http2StreamTunnel::SetKeepaliveVals(int32_t keepaliveIdleTime, 65 int32_t keepaliveRetryInterval) { 66 return NS_ERROR_NOT_IMPLEMENTED; 67 } 68 69 NS_IMETHODIMP 70 Http2StreamTunnel::GetSecurityCallbacks( 71 nsIInterfaceRequestor** aSecurityCallbacks) { 72 return mSocketTransport->GetSecurityCallbacks(aSecurityCallbacks); 73 } 74 75 NS_IMETHODIMP 76 Http2StreamTunnel::SetSecurityCallbacks( 77 nsIInterfaceRequestor* aSecurityCallbacks) { 78 return NS_OK; 79 } 80 81 NS_IMETHODIMP 82 Http2StreamTunnel::OpenInputStream(uint32_t aFlags, uint32_t aSegmentSize, 83 uint32_t aSegmentCount, 84 nsIInputStream** _retval) { 85 return NS_ERROR_NOT_IMPLEMENTED; 86 } 87 88 NS_IMETHODIMP 89 Http2StreamTunnel::OpenOutputStream(uint32_t aFlags, uint32_t aSegmentSize, 90 uint32_t aSegmentCount, 91 nsIOutputStream** _retval) { 92 return NS_ERROR_NOT_IMPLEMENTED; 93 } 94 95 void Http2StreamTunnel::CloseStream(nsresult aReason) { 96 LOG(("Http2StreamTunnel::CloseStream this=%p", this)); 97 RefPtr<Http2Session> session = Session(); 98 if (NS_SUCCEEDED(mCondition)) { 99 mSession = nullptr; 100 // Let the session pickup that the stream has been closed. 101 mCondition = aReason; 102 if (NS_SUCCEEDED(aReason)) { 103 aReason = NS_BASE_STREAM_CLOSED; 104 } 105 mOutput->OnSocketReady(aReason); 106 mInput->OnSocketReady(aReason); 107 } 108 mClosed = true; 109 } 110 111 NS_IMETHODIMP 112 Http2StreamTunnel::Close(nsresult aReason) { 113 LOG(("Http2StreamTunnel::Close this=%p", this)); 114 RefPtr<Http2Session> session = Session(); 115 if (NS_SUCCEEDED(mCondition)) { 116 if (NS_SUCCEEDED(aReason)) { 117 aReason = NS_BASE_STREAM_CLOSED; 118 } 119 mOutput->CloseWithStatus(aReason); 120 mInput->CloseWithStatus(aReason); 121 // Let the session pickup that the stream has been closed. 122 mCondition = aReason; 123 // Clear the session in the end to make sure that CleanupStream() can be 124 // called in CloseWithStatus(). 125 mSession = nullptr; 126 } 127 return NS_OK; 128 } 129 130 NS_IMETHODIMP 131 Http2StreamTunnel::SetEventSink(nsITransportEventSink* aSink, 132 nsIEventTarget* aEventTarget) { 133 return NS_OK; 134 } 135 136 NS_IMETHODIMP 137 Http2StreamTunnel::Bind(NetAddr* aLocalAddr) { 138 return NS_ERROR_NOT_IMPLEMENTED; 139 } 140 141 NS_IMETHODIMP 142 Http2StreamTunnel::GetEchConfigUsed(bool* aEchConfigUsed) { 143 return NS_ERROR_NOT_IMPLEMENTED; 144 } 145 146 NS_IMETHODIMP 147 Http2StreamTunnel::SetEchConfig(const nsACString& aEchConfig) { 148 return NS_ERROR_NOT_IMPLEMENTED; 149 } 150 151 NS_IMETHODIMP 152 Http2StreamTunnel::ResolvedByTRR(bool* aResolvedByTRR) { 153 return NS_ERROR_NOT_IMPLEMENTED; 154 } 155 156 NS_IMETHODIMP Http2StreamTunnel::GetEffectiveTRRMode( 157 nsIRequest::TRRMode* aEffectiveTRRMode) { 158 return NS_ERROR_NOT_IMPLEMENTED; 159 } 160 161 NS_IMETHODIMP Http2StreamTunnel::GetTrrSkipReason( 162 nsITRRSkipReason::value* aTrrSkipReason) { 163 return NS_ERROR_NOT_IMPLEMENTED; 164 } 165 166 NS_IMETHODIMP 167 Http2StreamTunnel::IsAlive(bool* aAlive) { 168 RefPtr<Http2Session> session = Session(); 169 if (mSocketTransport && session) { 170 return mSocketTransport->IsAlive(aAlive); 171 } 172 *aAlive = false; 173 return NS_OK; 174 } 175 176 #define FWD_TS_T_PTR(fx, ts) \ 177 NS_IMETHODIMP \ 178 Http2StreamTunnel::fx(ts* arg) { return mSocketTransport->fx(arg); } 179 180 #define FWD_TS_T_ADDREF(fx, ts) \ 181 NS_IMETHODIMP \ 182 Http2StreamTunnel::fx(ts** arg) { return mSocketTransport->fx(arg); } 183 184 #define FWD_TS_T(fx, ts) \ 185 NS_IMETHODIMP \ 186 Http2StreamTunnel::fx(ts arg) { return mSocketTransport->fx(arg); } 187 188 FWD_TS_T_PTR(GetKeepaliveEnabled, bool); 189 FWD_TS_T_PTR(GetSendBufferSize, uint32_t); 190 FWD_TS_T(SetSendBufferSize, uint32_t); 191 FWD_TS_T_PTR(GetPort, int32_t); 192 FWD_TS_T_PTR(GetPeerAddr, mozilla::net::NetAddr); 193 FWD_TS_T_PTR(GetSelfAddr, mozilla::net::NetAddr); 194 FWD_TS_T_ADDREF(GetScriptablePeerAddr, nsINetAddr); 195 FWD_TS_T_ADDREF(GetScriptableSelfAddr, nsINetAddr); 196 FWD_TS_T_ADDREF(GetTlsSocketControl, nsITLSSocketControl); 197 FWD_TS_T_PTR(GetConnectionFlags, uint32_t); 198 FWD_TS_T(SetConnectionFlags, uint32_t); 199 FWD_TS_T(SetIsPrivate, bool); 200 FWD_TS_T_PTR(GetTlsFlags, uint32_t); 201 FWD_TS_T(SetTlsFlags, uint32_t); 202 FWD_TS_T_PTR(GetRecvBufferSize, uint32_t); 203 FWD_TS_T(SetRecvBufferSize, uint32_t); 204 FWD_TS_T_PTR(GetResetIPFamilyPreference, bool); 205 206 nsresult Http2StreamTunnel::GetOriginAttributes( 207 mozilla::OriginAttributes* aOriginAttributes) { 208 return mSocketTransport->GetOriginAttributes(aOriginAttributes); 209 } 210 211 nsresult Http2StreamTunnel::SetOriginAttributes( 212 const mozilla::OriginAttributes& aOriginAttributes) { 213 return mSocketTransport->SetOriginAttributes(aOriginAttributes); 214 } 215 216 NS_IMETHODIMP 217 Http2StreamTunnel::GetScriptableOriginAttributes( 218 JSContext* aCx, JS::MutableHandle<JS::Value> aOriginAttributes) { 219 return mSocketTransport->GetScriptableOriginAttributes(aCx, 220 aOriginAttributes); 221 } 222 223 NS_IMETHODIMP 224 Http2StreamTunnel::SetScriptableOriginAttributes( 225 JSContext* aCx, JS::Handle<JS::Value> aOriginAttributes) { 226 return mSocketTransport->SetScriptableOriginAttributes(aCx, 227 aOriginAttributes); 228 } 229 230 NS_IMETHODIMP 231 Http2StreamTunnel::GetHost(nsACString& aHost) { 232 return mSocketTransport->GetHost(aHost); 233 } 234 235 NS_IMETHODIMP 236 Http2StreamTunnel::GetTimeout(uint32_t aType, uint32_t* _retval) { 237 return mSocketTransport->GetTimeout(aType, _retval); 238 } 239 240 NS_IMETHODIMP 241 Http2StreamTunnel::SetTimeout(uint32_t aType, uint32_t aValue) { 242 return mSocketTransport->SetTimeout(aType, aValue); 243 } 244 245 NS_IMETHODIMP 246 Http2StreamTunnel::SetReuseAddrPort(bool aReuseAddrPort) { 247 return mSocketTransport->SetReuseAddrPort(aReuseAddrPort); 248 } 249 250 NS_IMETHODIMP 251 Http2StreamTunnel::SetLinger(bool aPolarity, int16_t aTimeout) { 252 return mSocketTransport->SetLinger(aPolarity, aTimeout); 253 } 254 255 NS_IMETHODIMP 256 Http2StreamTunnel::GetQoSBits(uint8_t* aQoSBits) { 257 return mSocketTransport->GetQoSBits(aQoSBits); 258 } 259 260 NS_IMETHODIMP 261 Http2StreamTunnel::SetQoSBits(uint8_t aQoSBits) { 262 return mSocketTransport->SetQoSBits(aQoSBits); 263 } 264 265 NS_IMETHODIMP 266 Http2StreamTunnel::GetRetryDnsIfPossible(bool* aRetry) { 267 return mSocketTransport->GetRetryDnsIfPossible(aRetry); 268 } 269 270 NS_IMETHODIMP 271 Http2StreamTunnel::GetStatus(nsresult* aStatus) { 272 return mSocketTransport->GetStatus(aStatus); 273 } 274 275 already_AddRefed<nsHttpConnection> Http2StreamTunnel::CreateHttpConnection( 276 nsAHttpTransaction* httpTransaction, nsIInterfaceRequestor* aCallbacks, 277 PRIntervalTime aRtt, bool aIsExtendedCONNECT) { 278 mInput = new InputStreamTunnel(this); 279 mOutput = new OutputStreamTunnel(this); 280 RefPtr<nsHttpConnection> conn = new nsHttpConnection(); 281 282 conn->SetTransactionCaps(httpTransaction->Caps()); 283 nsresult rv = 284 conn->Init(httpTransaction->ConnectionInfo(), 285 gHttpHandler->ConnMgr()->MaxRequestDelay(), this, mInput, 286 mOutput, true, NS_OK, aCallbacks, aRtt, aIsExtendedCONNECT); 287 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv)); 288 mTransaction = httpTransaction; 289 return conn.forget(); 290 } 291 292 nsresult Http2StreamTunnel::CallToReadData(uint32_t count, 293 uint32_t* countRead) { 294 LOG(("Http2StreamTunnel::CallToReadData this=%p", this)); 295 return mOutput->OnSocketReady(NS_OK); 296 } 297 298 nsresult Http2StreamTunnel::CallToWriteData(uint32_t count, 299 uint32_t* countWritten) { 300 LOG(("Http2StreamTunnel::CallToWriteData this=%p", this)); 301 if (!mInput->HasCallback()) { 302 return NS_BASE_STREAM_WOULD_BLOCK; 303 } 304 return mInput->OnSocketReady(NS_OK); 305 } 306 307 nsresult Http2StreamTunnel::GenerateHeaders(nsCString& aCompressedData, 308 uint8_t& firstFrameFlags) { 309 nsAutoCString authorityHeader; 310 authorityHeader = mConnectionInfo->GetOrigin(); 311 authorityHeader.Append(':'); 312 authorityHeader.AppendInt(mConnectionInfo->OriginPort()); 313 314 RefPtr<Http2Session> session = Session(); 315 316 LOG3(("Http2StreamTunnel %p Stream ID 0x%X [session=%p] for %s\n", this, 317 mStreamID, session.get(), authorityHeader.get())); 318 319 mRequestBodyLenRemaining = 0x0fffffffffffffffULL; 320 321 nsresult rv = session->Compressor()->EncodeHeaderBlock( 322 mFlatHttpRequestHeaders, "CONNECT"_ns, EmptyCString(), authorityHeader, 323 EmptyCString(), EmptyCString(), true, aCompressedData, true); 324 NS_ENSURE_SUCCESS(rv, rv); 325 326 return NS_OK; 327 } 328 329 OutputStreamTunnel::OutputStreamTunnel(Http2StreamTunnel* aStream) 330 : mWeakStream(aStream) {} 331 332 OutputStreamTunnel::~OutputStreamTunnel() = default; 333 334 nsresult OutputStreamTunnel::OnSocketReady(nsresult condition) { 335 LOG(("OutputStreamTunnel::OnSocketReady [this=%p cond=%" PRIx32 336 " callback=%p]\n", 337 this, static_cast<uint32_t>(condition), mCallback.get())); 338 339 MOZ_ASSERT(OnSocketThread(), "not on socket thread"); 340 341 nsCOMPtr<nsIOutputStreamCallback> callback; 342 343 // update condition, but be careful not to erase an already 344 // existing error condition. 345 if (NS_SUCCEEDED(mCondition)) { 346 mCondition = condition; 347 } 348 callback = std::move(mCallback); 349 350 nsresult rv = NS_OK; 351 if (callback) { 352 rv = callback->OnOutputStreamReady(this); 353 MaybeSetRequestDone(callback); 354 } 355 356 return rv; 357 } 358 359 void OutputStreamTunnel::MaybeSetRequestDone( 360 nsIOutputStreamCallback* aCallback) { 361 RefPtr<nsHttpConnection> conn = do_QueryObject(aCallback); 362 if (!conn) { 363 return; 364 } 365 366 RefPtr<Http2StreamTunnel> tunnel; 367 nsresult rv = GetStream(getter_AddRefs(tunnel)); 368 if (NS_FAILED(rv)) { 369 return; 370 } 371 372 if (conn->RequestDone()) { 373 tunnel->SetRequestDone(); 374 } 375 } 376 377 NS_IMPL_ISUPPORTS(OutputStreamTunnel, nsIOutputStream, nsIAsyncOutputStream) 378 379 NS_IMETHODIMP 380 OutputStreamTunnel::Close() { return CloseWithStatus(NS_BASE_STREAM_CLOSED); } 381 382 NS_IMETHODIMP 383 OutputStreamTunnel::Flush() { return NS_OK; } 384 385 NS_IMETHODIMP 386 OutputStreamTunnel::StreamStatus() { return mCondition; } 387 388 NS_IMETHODIMP 389 OutputStreamTunnel::Write(const char* buf, uint32_t count, 390 uint32_t* countWritten) { 391 LOG(("OutputStreamTunnel::Write [this=%p count=%u]\n", this, count)); 392 393 *countWritten = 0; 394 if (NS_FAILED(mCondition)) { 395 return mCondition; 396 } 397 398 RefPtr<Http2StreamTunnel> tunnel; 399 nsresult rv = GetStream(getter_AddRefs(tunnel)); 400 if (NS_FAILED(rv)) { 401 return rv; 402 } 403 404 return tunnel->OnReadSegment(buf, count, countWritten); 405 } 406 407 NS_IMETHODIMP 408 OutputStreamTunnel::WriteSegments(nsReadSegmentFun reader, void* closure, 409 uint32_t count, uint32_t* countRead) { 410 // stream is unbuffered 411 return NS_ERROR_NOT_IMPLEMENTED; 412 } 413 414 NS_IMETHODIMP 415 OutputStreamTunnel::WriteFrom(nsIInputStream* stream, uint32_t count, 416 uint32_t* countRead) { 417 return NS_ERROR_NOT_IMPLEMENTED; 418 } 419 420 NS_IMETHODIMP 421 OutputStreamTunnel::IsNonBlocking(bool* nonblocking) { 422 *nonblocking = true; 423 return NS_OK; 424 } 425 426 NS_IMETHODIMP 427 OutputStreamTunnel::CloseWithStatus(nsresult reason) { 428 LOG(("OutputStreamTunnel::CloseWithStatus [this=%p reason=%" PRIx32 "]\n", 429 this, static_cast<uint32_t>(reason))); 430 mCondition = reason; 431 432 RefPtr<Http2StreamTunnel> tunnel = mWeakStream.get(); 433 mWeakStream = nullptr; 434 if (!tunnel) { 435 return NS_OK; 436 } 437 RefPtr<Http2Session> session = tunnel->Session(); 438 if (!session) { 439 return NS_OK; 440 } 441 session->CleanupStream(tunnel, reason, Http2Session::CANCEL_ERROR); 442 return NS_OK; 443 } 444 445 NS_IMETHODIMP 446 OutputStreamTunnel::AsyncWait(nsIOutputStreamCallback* callback, uint32_t flags, 447 uint32_t amount, nsIEventTarget* target) { 448 LOG(("OutputStreamTunnel::AsyncWait [this=%p]\n", this)); 449 450 // The following parametr are not used: 451 MOZ_ASSERT(!flags); 452 MOZ_ASSERT(!amount); 453 (void)target; 454 455 RefPtr<OutputStreamTunnel> self(this); 456 if (NS_FAILED(mCondition)) { 457 (void)NS_DispatchToCurrentThread(NS_NewRunnableFunction( 458 "OutputStreamTunnel::CallOnSocketReady", 459 [self{std::move(self)}]() { self->OnSocketReady(NS_OK); })); 460 } else if (callback) { 461 // Inform the proxy connection that the inner connetion wants to 462 // read data. 463 RefPtr<Http2StreamTunnel> tunnel; 464 nsresult rv = GetStream(getter_AddRefs(tunnel)); 465 if (NS_FAILED(rv)) { 466 return rv; 467 } 468 RefPtr<Http2Session> session; 469 rv = GetSession(getter_AddRefs(session)); 470 if (NS_FAILED(rv)) { 471 return rv; 472 } 473 session->TransactionHasDataToWrite(tunnel); 474 } 475 476 mCallback = callback; 477 return NS_OK; 478 } 479 480 InputStreamTunnel::InputStreamTunnel(Http2StreamTunnel* aStream) 481 : mWeakStream(aStream) {} 482 483 InputStreamTunnel::~InputStreamTunnel() = default; 484 485 nsresult InputStreamTunnel::OnSocketReady(nsresult condition) { 486 LOG(("InputStreamTunnel::OnSocketReady [this=%p cond=%" PRIx32 "]\n", this, 487 static_cast<uint32_t>(condition))); 488 489 MOZ_ASSERT(OnSocketThread(), "not on socket thread"); 490 491 nsCOMPtr<nsIInputStreamCallback> callback; 492 493 // update condition, but be careful not to erase an already 494 // existing error condition. 495 if (NS_SUCCEEDED(mCondition)) { 496 mCondition = condition; 497 } 498 callback = std::move(mCallback); 499 500 return callback ? callback->OnInputStreamReady(this) : NS_OK; 501 } 502 503 NS_IMPL_ISUPPORTS(InputStreamTunnel, nsIInputStream, nsIAsyncInputStream) 504 505 NS_IMETHODIMP 506 InputStreamTunnel::Close() { return CloseWithStatus(NS_BASE_STREAM_CLOSED); } 507 508 NS_IMETHODIMP 509 InputStreamTunnel::Available(uint64_t* avail) { 510 LOG(("InputStreamTunnel::Available [this=%p]\n", this)); 511 512 if (NS_FAILED(mCondition)) { 513 return mCondition; 514 } 515 516 return NS_ERROR_FAILURE; 517 } 518 519 NS_IMETHODIMP 520 InputStreamTunnel::StreamStatus() { 521 LOG(("InputStreamTunnel::StreamStatus [this=%p]\n", this)); 522 523 return mCondition; 524 } 525 526 NS_IMETHODIMP 527 InputStreamTunnel::Read(char* buf, uint32_t count, uint32_t* countRead) { 528 LOG(("InputStreamTunnel::Read [this=%p count=%u]\n", this, count)); 529 530 *countRead = 0; 531 532 if (NS_FAILED(mCondition)) { 533 return mCondition; 534 } 535 536 RefPtr<Http2StreamTunnel> tunnel; 537 nsresult rv = GetStream(getter_AddRefs(tunnel)); 538 if (NS_FAILED(rv)) { 539 return rv; 540 } 541 542 return tunnel->OnWriteSegment(buf, count, countRead); 543 } 544 545 NS_IMETHODIMP 546 InputStreamTunnel::ReadSegments(nsWriteSegmentFun writer, void* closure, 547 uint32_t count, uint32_t* countRead) { 548 // socket stream is unbuffered 549 return NS_ERROR_NOT_IMPLEMENTED; 550 } 551 552 NS_IMETHODIMP 553 InputStreamTunnel::IsNonBlocking(bool* nonblocking) { 554 *nonblocking = true; 555 return NS_OK; 556 } 557 558 NS_IMETHODIMP 559 InputStreamTunnel::CloseWithStatus(nsresult reason) { 560 LOG(("InputStreamTunnel::CloseWithStatus [this=%p reason=%" PRIx32 "]\n", 561 this, static_cast<uint32_t>(reason))); 562 mCondition = reason; 563 564 RefPtr<Http2StreamTunnel> tunnel = mWeakStream.get(); 565 mWeakStream = nullptr; 566 if (!tunnel) { 567 return NS_OK; 568 } 569 RefPtr<Http2Session> session = tunnel->Session(); 570 if (!session) { 571 return NS_OK; 572 } 573 session->CleanupStream(tunnel, reason, Http2Session::CANCEL_ERROR); 574 return NS_OK; 575 } 576 577 NS_IMETHODIMP 578 InputStreamTunnel::AsyncWait(nsIInputStreamCallback* callback, uint32_t flags, 579 uint32_t amount, nsIEventTarget* target) { 580 LOG(("InputStreamTunnel::AsyncWait [this=%p mCondition=%x]\n", this, 581 static_cast<uint32_t>(mCondition))); 582 583 // The following parametr are not used: 584 MOZ_ASSERT(!flags); 585 MOZ_ASSERT(!amount); 586 (void)target; 587 588 RefPtr<InputStreamTunnel> self(this); 589 if (NS_FAILED(mCondition)) { 590 (void)NS_DispatchToCurrentThread(NS_NewRunnableFunction( 591 "InputStreamTunnel::CallOnSocketReady", 592 [self{std::move(self)}]() { self->OnSocketReady(NS_OK); })); 593 } else if (callback) { 594 // Inform the proxy connection that the inner connetion wants to 595 // read data. 596 RefPtr<Http2StreamTunnel> tunnel; 597 nsresult rv = GetStream(getter_AddRefs(tunnel)); 598 if (NS_FAILED(rv)) { 599 return rv; 600 } 601 RefPtr<Http2Session> session; 602 rv = GetSession(getter_AddRefs(session)); 603 if (NS_FAILED(rv)) { 604 return rv; 605 } 606 if (tunnel->DataBuffered()) { 607 session->TransactionHasDataToRecv(tunnel); 608 } 609 } 610 611 mCallback = callback; 612 return NS_OK; 613 } 614 615 nsresult OutputStreamTunnel::GetStream(Http2StreamTunnel** aStream) { 616 RefPtr<Http2StreamTunnel> tunnel = mWeakStream.get(); 617 MOZ_ASSERT(tunnel); 618 if (!tunnel) { 619 return NS_ERROR_UNEXPECTED; 620 } 621 622 tunnel.forget(aStream); 623 return NS_OK; 624 } 625 626 nsresult OutputStreamTunnel::GetSession(Http2Session** aSession) { 627 RefPtr<Http2StreamTunnel> tunnel; 628 nsresult rv = GetStream(getter_AddRefs(tunnel)); 629 if (NS_FAILED(rv)) { 630 return rv; 631 } 632 RefPtr<Http2Session> session = tunnel->Session(); 633 MOZ_ASSERT(session); 634 if (!session) { 635 return NS_ERROR_UNEXPECTED; 636 } 637 638 session.forget(aSession); 639 return NS_OK; 640 } 641 642 nsresult InputStreamTunnel::GetStream(Http2StreamTunnel** aStream) { 643 RefPtr<Http2StreamTunnel> tunnel = mWeakStream.get(); 644 MOZ_ASSERT(tunnel); 645 if (!tunnel) { 646 return NS_ERROR_UNEXPECTED; 647 } 648 649 tunnel.forget(aStream); 650 return NS_OK; 651 } 652 653 nsresult InputStreamTunnel::GetSession(Http2Session** aSession) { 654 RefPtr<Http2StreamTunnel> tunnel; 655 nsresult rv = GetStream(getter_AddRefs(tunnel)); 656 if (NS_FAILED(rv)) { 657 return rv; 658 } 659 RefPtr<Http2Session> session = tunnel->Session(); 660 if (!session) { 661 return NS_ERROR_UNEXPECTED; 662 } 663 664 session.forget(aSession); 665 return NS_OK; 666 } 667 668 Http2StreamWebSocket::Http2StreamWebSocket( 669 Http2Session* session, int32_t priority, uint64_t bcId, 670 nsHttpConnectionInfo* aConnectionInfo) 671 : Http2StreamTunnel(session, priority, bcId, aConnectionInfo) { 672 LOG(("Http2StreamWebSocket ctor:%p", this)); 673 } 674 675 Http2StreamWebSocket::~Http2StreamWebSocket() { 676 LOG(("Http2StreamWebSocket dtor:%p", this)); 677 } 678 679 nsresult Http2StreamWebSocket::GenerateHeaders(nsCString& aCompressedData, 680 uint8_t& firstFrameFlags) { 681 nsHttpRequestHead* head = mTransaction->RequestHead(); 682 683 nsAutoCString authorityHeader; 684 nsresult rv = head->GetHeader(nsHttp::Host, authorityHeader); 685 NS_ENSURE_SUCCESS(rv, rv); 686 687 RefPtr<Http2Session> session = Session(); 688 LOG3(("Http2StreamWebSocket %p Stream ID 0x%X [session=%p] for %s\n", this, 689 mStreamID, session.get(), authorityHeader.get())); 690 691 nsDependentCString scheme(head->IsHTTPS() ? "https" : "http"); 692 nsAutoCString path; 693 head->Path(path); 694 695 rv = session->Compressor()->EncodeHeaderBlock( 696 mFlatHttpRequestHeaders, "CONNECT"_ns, path, authorityHeader, scheme, 697 "websocket"_ns, false, aCompressedData, true); 698 NS_ENSURE_SUCCESS(rv, rv); 699 700 mRequestBodyLenRemaining = 0x0fffffffffffffffULL; 701 702 return NS_OK; 703 } 704 705 void Http2StreamWebSocket::CloseStream(nsresult aReason) { 706 LOG(("Http2StreamWebSocket::CloseStream this=%p aReason=%x", this, 707 static_cast<uint32_t>(aReason))); 708 if (mTransaction) { 709 mTransaction->Close(aReason); 710 mTransaction = nullptr; 711 } 712 Http2StreamTunnel::CloseStream(aReason); 713 } 714 715 } // namespace mozilla::net