зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1754737 - Add some structure to nsHttpConnection: r=necko-reviewers,kershaw
- nsHttpConnection now has states. Currently only proxy setup phase is added to the states. - The states are used in nsHttpConnection::OnSocketWritable tto make the code more understandable. - Some pieces of selfcontained code are extracted from nsHttpConnection::OnHeadersAvailable, i.e. HandleTunnelResponse and HandleWebSocketResponse Differential Revision: https://phabricator.services.mozilla.com/D138714
This commit is contained in:
Родитель
8673dcf418
Коммит
0248b17c59
|
@ -161,6 +161,12 @@ nsresult nsHttpConnection::Init(
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsHttpConnection::ChangeState(HttpConnectionState newState) {
|
||||
LOG(("nsHttpConnection::ChanfeState %d -> %d [this=%p]", mState, newState,
|
||||
this));
|
||||
mState = newState;
|
||||
}
|
||||
|
||||
nsresult nsHttpConnection::TryTakeSubTransactions(
|
||||
nsTArray<RefPtr<nsAHttpTransaction> >& list) {
|
||||
nsresult rv = mTransaction->TakeSubTransactions(list);
|
||||
|
@ -315,11 +321,7 @@ void nsHttpConnection::StartSpdy(nsISSLSocketControl* sslControl,
|
|||
("nsHttpConnection::StartSpdy %p Connecting To a HTTP/2 "
|
||||
"Proxy and Need Connect",
|
||||
this));
|
||||
MOZ_ASSERT(mProxyConnectStream);
|
||||
|
||||
mProxyConnectStream = nullptr;
|
||||
mCompletedProxyConnect = true;
|
||||
mProxyConnectInProgress = false;
|
||||
SetTunnelSetupDone();
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
@ -658,13 +660,8 @@ nsresult nsHttpConnection::Activate(nsAHttpTransaction* trans, uint32_t caps,
|
|||
|
||||
// need to handle HTTP CONNECT tunnels if this is the first time if
|
||||
// we are tunneling through a proxy
|
||||
nsresult rv = NS_OK;
|
||||
if (mTransaction->ConnectionInfo()->UsingConnect() &&
|
||||
!mCompletedProxyConnect) {
|
||||
rv = SetupProxyConnect();
|
||||
if (NS_FAILED(rv)) goto failed_activation;
|
||||
mProxyConnectInProgress = true;
|
||||
}
|
||||
nsresult rv = CheckTunnelIsNeeded();
|
||||
if (NS_FAILED(rv)) goto failed_activation;
|
||||
|
||||
// Clear the per activation counter
|
||||
mCurrentBytesRead = 0;
|
||||
|
@ -1200,77 +1197,101 @@ nsresult nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction* trans,
|
|||
--mRemainingConnectionUses;
|
||||
}
|
||||
|
||||
switch (mState) {
|
||||
case HttpConnectionState::SETTING_UP_TUNNEL:
|
||||
HandleTunnelResponse(responseStatus, reset);
|
||||
break;
|
||||
default:
|
||||
if (requestHead->HasHeader(nsHttp::Upgrade)) {
|
||||
HandleWebSocketResponse(requestHead, responseHead, responseStatus);
|
||||
} else if (responseStatus == 101) {
|
||||
// We got an 101 but we are not asking of a WebSsocket?
|
||||
Close(NS_ERROR_ABORT);
|
||||
}
|
||||
}
|
||||
|
||||
mLastHttpResponseVersion = responseHead->Version();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsHttpConnection::HandleTunnelResponse(uint16_t responseStatus,
|
||||
bool* reset) {
|
||||
MOZ_ASSERT(TunnelSetupInProgress());
|
||||
MOZ_ASSERT(mProxyConnectStream);
|
||||
MOZ_ASSERT(mUsingSpdyVersion == SpdyVersion::NONE,
|
||||
"SPDY NPN Complete while using proxy connect stream");
|
||||
// If we're doing a proxy connect, we need to check whether or not
|
||||
// it was successful. If so, we have to reset the transaction and step-up
|
||||
// the socket connection if using SSL. Finally, we have to wake up the
|
||||
// socket write request.
|
||||
bool itWasProxyConnect = !!mProxyConnectStream;
|
||||
if (mProxyConnectStream) {
|
||||
MOZ_ASSERT(mUsingSpdyVersion == SpdyVersion::NONE,
|
||||
"SPDY NPN Complete while using proxy connect stream");
|
||||
mProxyConnectStream = nullptr;
|
||||
bool isHttps = mTransaction ? mTransaction->ConnectionInfo()->EndToEndSSL()
|
||||
: mConnInfo->EndToEndSSL();
|
||||
bool onlyConnect = mTransactionCaps & NS_HTTP_CONNECT_ONLY;
|
||||
|
||||
mTransaction->OnProxyConnectComplete(responseStatus);
|
||||
if (responseStatus == 200) {
|
||||
LOG(("proxy CONNECT succeeded! endtoendssl=%d onlyconnect=%d\n", isHttps,
|
||||
onlyConnect));
|
||||
// If we're only connecting, we don't need to reset the transaction
|
||||
// state. We need to upgrade the socket now without doing the actual
|
||||
// http request.
|
||||
if (!onlyConnect) {
|
||||
*reset = true;
|
||||
}
|
||||
nsresult rv;
|
||||
// CONNECT only flag doesn't do the tls setup. https here only
|
||||
// ensures a proxy tunnel was used not that tls is setup.
|
||||
if (isHttps) {
|
||||
if (!onlyConnect) {
|
||||
if (mConnInfo->UsingHttpsProxy()) {
|
||||
LOG(("%p new TLSFilterTransaction %s %d\n", this,
|
||||
mConnInfo->Origin(), mConnInfo->OriginPort()));
|
||||
SetupSecondaryTLS();
|
||||
}
|
||||
|
||||
rv = InitSSLParams(false, true);
|
||||
LOG(("InitSSLParams [rv=%" PRIx32 "]\n", static_cast<uint32_t>(rv)));
|
||||
} else {
|
||||
// We have an https protocol but the CONNECT only flag was
|
||||
// specified. The consumer only wants a raw socket to the
|
||||
// proxy. We have to mark this as complete to finish the
|
||||
// transaction and be upgraded. OnSocketReadable() uses this
|
||||
// to detect an inactive tunnel and blocks completion.
|
||||
mNPNComplete = true;
|
||||
}
|
||||
}
|
||||
mCompletedProxyConnect = true;
|
||||
mProxyConnectInProgress = false;
|
||||
rv = mSocketOut->AsyncWait(this, 0, 0, nullptr);
|
||||
// XXX what if this fails -- need to handle this error
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "mSocketOut->AsyncWait failed");
|
||||
} else {
|
||||
LOG(("proxy CONNECT failed! endtoendssl=%d onlyconnect=%d\n", isHttps,
|
||||
onlyConnect));
|
||||
mTransaction->SetProxyConnectFailed();
|
||||
}
|
||||
if (responseStatus == 200) {
|
||||
ChangeState(HttpConnectionState::TUNNEL_DONE);
|
||||
}
|
||||
mProxyConnectStream = nullptr;
|
||||
bool isHttps = mTransaction ? mTransaction->ConnectionInfo()->EndToEndSSL()
|
||||
: mConnInfo->EndToEndSSL();
|
||||
bool onlyConnect = mTransactionCaps & NS_HTTP_CONNECT_ONLY;
|
||||
|
||||
nsAutoCString upgradeReq;
|
||||
bool hasUpgradeReq =
|
||||
NS_SUCCEEDED(requestHead->GetHeader(nsHttp::Upgrade, upgradeReq));
|
||||
mTransaction->OnProxyConnectComplete(responseStatus);
|
||||
if (responseStatus == 200) {
|
||||
LOG(("proxy CONNECT succeeded! endtoendssl=%d onlyconnect=%d\n", isHttps,
|
||||
onlyConnect));
|
||||
// If we're only connecting, we don't need to reset the transaction
|
||||
// state. We need to upgrade the socket now without doing the actual
|
||||
// http request.
|
||||
if (!onlyConnect) {
|
||||
*reset = true;
|
||||
}
|
||||
nsresult rv;
|
||||
// CONNECT only flag doesn't do the tls setup. https here only
|
||||
// ensures a proxy tunnel was used not that tls is setup.
|
||||
if (isHttps) {
|
||||
if (!onlyConnect) {
|
||||
if (mConnInfo->UsingHttpsProxy()) {
|
||||
LOG(("%p new TLSFilterTransaction %s %d\n", this, mConnInfo->Origin(),
|
||||
mConnInfo->OriginPort()));
|
||||
SetupSecondaryTLS();
|
||||
}
|
||||
|
||||
rv = InitSSLParams(false, true);
|
||||
LOG(("InitSSLParams [rv=%" PRIx32 "]\n", static_cast<uint32_t>(rv)));
|
||||
} else {
|
||||
// We have an https protocol but the CONNECT only flag was
|
||||
// specified. The consumer only wants a raw socket to the
|
||||
// proxy. We have to mark this as complete to finish the
|
||||
// transaction and be upgraded. OnSocketReadable() uses this
|
||||
// to detect an inactive tunnel and blocks completion.
|
||||
mNPNComplete = true;
|
||||
}
|
||||
}
|
||||
rv = mSocketOut->AsyncWait(this, 0, 0, nullptr);
|
||||
// XXX what if this fails -- need to handle this error
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "mSocketOut->AsyncWait failed");
|
||||
} else {
|
||||
LOG(("proxy CONNECT failed! endtoendssl=%d onlyconnect=%d\n", isHttps,
|
||||
onlyConnect));
|
||||
mTransaction->SetProxyConnectFailed();
|
||||
}
|
||||
}
|
||||
|
||||
void nsHttpConnection::HandleWebSocketResponse(nsHttpRequestHead* requestHead,
|
||||
nsHttpResponseHead* responseHead,
|
||||
uint16_t responseStatus) {
|
||||
// Don't use persistent connection for Upgrade unless there's an auth failure:
|
||||
// some proxies expect to see auth response on persistent connection.
|
||||
// Also allow persistent conn for h2, as we don't want to waste connections
|
||||
// for multiplexed upgrades.
|
||||
if (!itWasProxyConnect && hasUpgradeReq && responseStatus != 401 &&
|
||||
responseStatus != 407 && !mSpdySession) {
|
||||
if (responseStatus != 401 && responseStatus != 407 && !mSpdySession) {
|
||||
LOG(("HTTP Upgrade in play - disable keepalive for http/1.x\n"));
|
||||
DontReuse();
|
||||
}
|
||||
|
||||
if (responseStatus == 101) {
|
||||
nsAutoCString upgradeReq;
|
||||
bool hasUpgradeReq =
|
||||
NS_SUCCEEDED(requestHead->GetHeader(nsHttp::Upgrade, upgradeReq));
|
||||
nsAutoCString upgradeResp;
|
||||
bool hasUpgradeResp =
|
||||
NS_SUCCEEDED(responseHead->GetHeader(nsHttp::Upgrade, upgradeResp));
|
||||
|
@ -1286,10 +1307,6 @@ nsresult nsHttpConnection::OnHeadersAvailable(nsAHttpTransaction* trans,
|
|||
LOG(("HTTP Upgrade Response to %s\n", upgradeResp.get()));
|
||||
}
|
||||
}
|
||||
|
||||
mLastHttpResponseVersion = responseHead->Version();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool nsHttpConnection::IsReused() {
|
||||
|
@ -1692,14 +1709,6 @@ void nsHttpConnection::CloseTransaction(nsAHttpTransaction* trans,
|
|||
mIsReused = true;
|
||||
}
|
||||
|
||||
nsresult nsHttpConnection::ReadFromStream(nsIInputStream* input, void* closure,
|
||||
const char* buf, uint32_t offset,
|
||||
uint32_t count, uint32_t* countRead) {
|
||||
// thunk for nsIInputStream instance
|
||||
nsHttpConnection* conn = (nsHttpConnection*)closure;
|
||||
return conn->OnReadSegment(buf, count, countRead);
|
||||
}
|
||||
|
||||
bool nsHttpConnection::CheckCanWrite0RTTData() {
|
||||
MOZ_ASSERT(EarlyDataAvailable());
|
||||
nsCOMPtr<nsISupports> securityInfo;
|
||||
|
@ -1764,7 +1773,7 @@ nsresult nsHttpConnection::OnReadSegment(const char* buf, uint32_t count,
|
|||
} else {
|
||||
mLastWriteTime = PR_IntervalNow();
|
||||
mSocketOutCondition = NS_OK; // reset condition
|
||||
if (!mProxyConnectInProgress) mTotalBytesWritten += *countRead;
|
||||
if (!TunnelSetupInProgress()) mTotalBytesWritten += *countRead;
|
||||
}
|
||||
|
||||
return mSocketOutCondition;
|
||||
|
@ -1784,7 +1793,7 @@ nsresult nsHttpConnection::OnSocketWritable() {
|
|||
uint32_t writeAttempts = 0;
|
||||
|
||||
if (mTransactionCaps & NS_HTTP_CONNECT_ONLY) {
|
||||
if (!mCompletedProxyConnect && !mProxyConnectStream) {
|
||||
if (!TunnelUsed()) {
|
||||
// A CONNECT has been requested for this connection but will never
|
||||
// be performed. This should never happen.
|
||||
MOZ_ASSERT(false, "proxy connect will never happen");
|
||||
|
@ -1792,7 +1801,7 @@ nsresult nsHttpConnection::OnSocketWritable() {
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mCompletedProxyConnect) {
|
||||
if (TunnelCompleted()) {
|
||||
// Don't need to check this each write attempt since it is only
|
||||
// updated after OnSocketWritable completes.
|
||||
// We've already done primary tls (if needed) and sent our CONNECT.
|
||||
|
@ -1808,50 +1817,51 @@ nsresult nsHttpConnection::OnSocketWritable() {
|
|||
rv = mSocketOutCondition = NS_OK;
|
||||
transactionBytes = 0;
|
||||
|
||||
// The SSL handshake must be completed before the
|
||||
// transaction->readsegments() processing can proceed because we need to
|
||||
// know how to format the request differently for http/1, http/2, spdy,
|
||||
// etc.. and that is negotiated with NPN/ALPN in the SSL handshake.
|
||||
if (mConnInfo->UsingHttpsProxy() && !EnsureNPNComplete()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(!EarlyDataAvailable());
|
||||
mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
} else if (mProxyConnectStream) {
|
||||
// If we're need an HTTP/1 CONNECT tunnel through a proxy
|
||||
// send it before doing the SSL handshake
|
||||
LOG((" writing CONNECT request stream\n"));
|
||||
rv = mProxyConnectStream->ReadSegments(ReadFromStream, this,
|
||||
nsIOService::gDefaultSegmentSize,
|
||||
&transactionBytes);
|
||||
} else if (!EnsureNPNComplete() &&
|
||||
(!EarlyDataUsed() || mTlsHandshakeComplitionPending)) {
|
||||
// The handshake is not done and we cannot write 0RTT data or nss has
|
||||
// already finished 0RTT data.
|
||||
mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
} else if (!mTransaction) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
LOG((" No Transaction In OnSocketWritable\n"));
|
||||
} else if (NS_SUCCEEDED(rv)) {
|
||||
// for non spdy sessions let the connection manager know
|
||||
if (!mReportedSpdy && mNPNComplete) {
|
||||
mReportedSpdy = true;
|
||||
MOZ_ASSERT(!mEverUsedSpdy);
|
||||
gHttpHandler->ConnMgr()->ReportSpdyConnection(this, false);
|
||||
}
|
||||
|
||||
LOG((" writing transaction request stream\n"));
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mProxyConnectInProgress || !EarlyDataAvailable());
|
||||
mProxyConnectInProgress = false;
|
||||
rv = mTransaction->ReadSegmentsAgain(
|
||||
this, nsIOService::gDefaultSegmentSize, &transactionBytes, &again);
|
||||
if (EarlyDataUsed()) {
|
||||
mContentBytesWritten0RTT += transactionBytes;
|
||||
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
// If an error happens while writting 0RTT data, restart
|
||||
// the transactiions without 0RTT.
|
||||
FinishNPNSetup(false, true);
|
||||
switch (mState) {
|
||||
case HttpConnectionState::SETTING_UP_TUNNEL:
|
||||
if (mConnInfo->UsingHttpsProxy() && !EnsureNPNComplete()) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(!EarlyDataAvailable());
|
||||
mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
} else {
|
||||
rv = SendConnectRequest(this, &transactionBytes);
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
// The SSL handshake must be completed before the
|
||||
// transaction->readsegments() processing can proceed because we need to
|
||||
// know how to format the request differently for http/1, http/2, spdy,
|
||||
// etc.. and that is negotiated with NPN/ALPN in the SSL handshake.
|
||||
if (!EnsureNPNComplete() &&
|
||||
(!EarlyDataUsed() || mTlsHandshakeComplitionPending)) {
|
||||
// The handshake is not done and we cannot write 0RTT data or nss has
|
||||
// already finished 0RTT data.
|
||||
mSocketOutCondition = NS_BASE_STREAM_WOULD_BLOCK;
|
||||
} else if (!mTransaction) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
LOG((" No Transaction In OnSocketWritable\n"));
|
||||
} else if (NS_SUCCEEDED(rv)) {
|
||||
// for non spdy sessions let the connection manager know
|
||||
if (!mReportedSpdy && mNPNComplete) {
|
||||
mReportedSpdy = true;
|
||||
MOZ_ASSERT(!mEverUsedSpdy);
|
||||
gHttpHandler->ConnMgr()->ReportSpdyConnection(this, false);
|
||||
}
|
||||
|
||||
LOG((" writing transaction request stream\n"));
|
||||
rv = mTransaction->ReadSegmentsAgain(this,
|
||||
nsIOService::gDefaultSegmentSize,
|
||||
&transactionBytes, &again);
|
||||
if (EarlyDataUsed()) {
|
||||
mContentBytesWritten0RTT += transactionBytes;
|
||||
if (NS_FAILED(rv) && rv != NS_BASE_STREAM_WOULD_BLOCK) {
|
||||
// If an error happens while writting 0RTT data, restart
|
||||
// the transactiions without 0RTT.
|
||||
FinishNPNSetup(false, true);
|
||||
}
|
||||
} else {
|
||||
mContentBytesWritten += transactionBytes;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mContentBytesWritten += transactionBytes;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1955,8 +1965,7 @@ nsresult nsHttpConnection::OnSocketReadable() {
|
|||
// Reset mResponseTimeoutEnabled to stop response timeout checks.
|
||||
mResponseTimeoutEnabled = false;
|
||||
|
||||
if ((mTransactionCaps & NS_HTTP_CONNECT_ONLY) && !mCompletedProxyConnect &&
|
||||
!mProxyConnectStream) {
|
||||
if ((mTransactionCaps & NS_HTTP_CONNECT_ONLY) && !TunnelUsed()) {
|
||||
// A CONNECT has been requested for this connection but will never
|
||||
// be performed. This should never happen.
|
||||
MOZ_ASSERT(false, "proxy connect will never happen");
|
||||
|
@ -1981,7 +1990,7 @@ nsresult nsHttpConnection::OnSocketReadable() {
|
|||
bool again = true;
|
||||
|
||||
do {
|
||||
if (!mProxyConnectInProgress && !EnsureNPNComplete()) {
|
||||
if (!TunnelSetupInProgress() && !EnsureNPNComplete()) {
|
||||
// Unless we are setting up a tunnel via CONNECT, prevent reading
|
||||
// from the socket until the results of NPN
|
||||
// negotiation are known (which is determined from the write path).
|
||||
|
@ -2070,9 +2079,7 @@ void nsHttpConnection::SetInSpdyTunnel(bool arg) {
|
|||
mInSpdyTunnel = arg;
|
||||
|
||||
// don't setup another tunnel :)
|
||||
mProxyConnectStream = nullptr;
|
||||
mCompletedProxyConnect = true;
|
||||
mProxyConnectInProgress = false;
|
||||
SetTunnelSetupDone();
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -2126,7 +2133,6 @@ nsresult nsHttpConnection::MakeConnectString(nsAHttpTransaction* trans,
|
|||
rv = request->SetHeader(nsHttp::Proxy_Authorization, val);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
if ((trans->Caps() & NS_HTTP_CONNECT_ONLY) &&
|
||||
NS_SUCCEEDED(trans->RequestHead()->GetHeader(nsHttp::Upgrade, val))) {
|
||||
// rfc7639 proposes using the ALPN header to indicate the protocol used
|
||||
|
@ -2151,22 +2157,6 @@ nsresult nsHttpConnection::MakeConnectString(nsAHttpTransaction* trans,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsHttpConnection::SetupProxyConnect() {
|
||||
LOG(("nsHttpConnection::SetupProxyConnect [this=%p]\n", this));
|
||||
NS_ENSURE_TRUE(!mProxyConnectStream, NS_ERROR_ALREADY_INITIALIZED);
|
||||
MOZ_ASSERT(mUsingSpdyVersion == SpdyVersion::NONE,
|
||||
"SPDY NPN Complete while using proxy connect stream");
|
||||
|
||||
nsAutoCString buf;
|
||||
nsHttpRequestHead request;
|
||||
nsresult rv = MakeConnectString(mTransaction, &request, buf, false);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return NS_NewCStringInputStream(getter_AddRefs(mProxyConnectStream),
|
||||
std::move(buf));
|
||||
}
|
||||
|
||||
nsresult nsHttpConnection::StartShortLivedTCPKeepalives() {
|
||||
if (mUsingSpdyVersion != SpdyVersion::NONE) {
|
||||
return NS_OK;
|
||||
|
@ -2503,7 +2493,7 @@ bool nsHttpConnection::CanAcceptWebsocket() {
|
|||
}
|
||||
|
||||
bool nsHttpConnection::IsProxyConnectInProgress() {
|
||||
return mProxyConnectInProgress;
|
||||
return mState == SETTING_UP_TUNNEL;
|
||||
}
|
||||
|
||||
bool nsHttpConnection::LastTransactionExpectedNoContent() {
|
||||
|
@ -2694,5 +2684,72 @@ void nsHttpConnection::HandshakeDoneInternal() {
|
|||
return;
|
||||
}
|
||||
|
||||
void nsHttpConnection::SetTunnelSetupDone() {
|
||||
MOZ_ASSERT(mProxyConnectStream);
|
||||
MOZ_ASSERT(mState == HttpConnectionState::SETTING_UP_TUNNEL);
|
||||
|
||||
ChangeState(HttpConnectionState::TUNNEL_DONE);
|
||||
mProxyConnectStream = nullptr;
|
||||
}
|
||||
|
||||
nsresult nsHttpConnection::CheckTunnelIsNeeded() {
|
||||
switch (mState) {
|
||||
case HttpConnectionState::UNINITIALIZED: {
|
||||
// This is is called first time. Check if we need a tunnel.
|
||||
if (!mTransaction->ConnectionInfo()->UsingConnect()) {
|
||||
ChangeState(HttpConnectionState::TUNNEL_NOT_USED);
|
||||
return NS_OK;
|
||||
}
|
||||
ChangeState(HttpConnectionState::SETTING_UP_TUNNEL);
|
||||
}
|
||||
[[fallthrough]];
|
||||
case HttpConnectionState::SETTING_UP_TUNNEL: {
|
||||
// When a nsHttpConnection is in this state that means that an
|
||||
// authentication was needed and we are resending a CONNECT
|
||||
// request. This request will include authentication headers.
|
||||
nsresult rv = SetupProxyConnectStream();
|
||||
if (NS_FAILED(rv)) {
|
||||
ChangeState(HttpConnectionState::UNINITIALIZED);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
case HttpConnectionState::TUNNEL_DONE:
|
||||
case HttpConnectionState::TUNNEL_NOT_USED:
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult nsHttpConnection::SetupProxyConnectStream() {
|
||||
LOG(("nsHttpConnection::SetupStream\n"));
|
||||
NS_ENSURE_TRUE(!mProxyConnectStream, NS_ERROR_ALREADY_INITIALIZED);
|
||||
MOZ_ASSERT(mState == HttpConnectionState::SETTING_UP_TUNNEL);
|
||||
|
||||
nsAutoCString buf;
|
||||
nsHttpRequestHead request;
|
||||
nsresult rv = MakeConnectString(mTransaction, &request, buf, false);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = NS_NewCStringInputStream(getter_AddRefs(mProxyConnectStream),
|
||||
std::move(buf));
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult nsHttpConnection::ReadFromStream(nsIInputStream* input, void* closure,
|
||||
const char* buf, uint32_t offset,
|
||||
uint32_t count, uint32_t* countRead) {
|
||||
// thunk for nsIInputStream instance
|
||||
nsHttpConnection* conn = (nsHttpConnection*)closure;
|
||||
return conn->OnReadSegment(buf, count, countRead);
|
||||
}
|
||||
|
||||
nsresult nsHttpConnection::SendConnectRequest(void* closure,
|
||||
uint32_t* transactionBytes) {
|
||||
LOG((" writing CONNECT request stream\n"));
|
||||
return mProxyConnectStream->ReadSegments(ReadFromStream, closure,
|
||||
nsIOService::gDefaultSegmentSize,
|
||||
transactionBytes);
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -124,10 +124,6 @@ class nsHttpConnection final : public HttpConnectionBase,
|
|||
|
||||
friend class HttpConnectionForceIO;
|
||||
|
||||
[[nodiscard]] static nsresult ReadFromStream(nsIInputStream*, void*,
|
||||
const char*, uint32_t, uint32_t,
|
||||
uint32_t*);
|
||||
|
||||
// When a persistent connection is in the connection manager idle
|
||||
// connection pool, the nsHttpConnection still reads errors and hangups
|
||||
// on the socket so that it can be proactively released if the server
|
||||
|
@ -160,10 +156,6 @@ class nsHttpConnection final : public HttpConnectionBase,
|
|||
|
||||
int64_t ContentBytesWritten() { return mContentBytesWritten; }
|
||||
|
||||
[[nodiscard]] static nsresult MakeConnectString(nsAHttpTransaction* trans,
|
||||
nsHttpRequestHead* request,
|
||||
nsACString& result,
|
||||
bool h2ws);
|
||||
void SetupSecondaryTLS(nsAHttpTransaction* aSpdyConnectTransaction = nullptr);
|
||||
void SetInSpdyTunnel(bool arg);
|
||||
|
||||
|
@ -197,7 +189,40 @@ class nsHttpConnection final : public HttpConnectionBase,
|
|||
|
||||
bool IsForWebSocket() { return mForWebSocket; }
|
||||
|
||||
// The following functions are related to setting up a tunnel.
|
||||
[[nodiscard]] static nsresult MakeConnectString(nsAHttpTransaction* trans,
|
||||
nsHttpRequestHead* request,
|
||||
nsACString& result,
|
||||
bool h2ws);
|
||||
[[nodiscard]] static nsresult ReadFromStream(nsIInputStream*, void*,
|
||||
const char*, uint32_t, uint32_t,
|
||||
uint32_t*);
|
||||
|
||||
private:
|
||||
enum HttpConnectionState {
|
||||
UNINITIALIZED,
|
||||
SETTING_UP_TUNNEL,
|
||||
TUNNEL_DONE,
|
||||
TUNNEL_NOT_USED,
|
||||
} mState{HttpConnectionState::UNINITIALIZED};
|
||||
void ChangeState(HttpConnectionState newState);
|
||||
|
||||
// Tunnel retated functions:
|
||||
bool TunnelSetupInProgress() { return mState == SETTING_UP_TUNNEL; }
|
||||
bool TunnelUsed() {
|
||||
return mState == SETTING_UP_TUNNEL || mState == TUNNEL_DONE;
|
||||
}
|
||||
bool TunnelCompleted() { return mState == TUNNEL_DONE; }
|
||||
void SetTunnelSetupDone();
|
||||
nsresult CheckTunnelIsNeeded();
|
||||
nsresult SetupProxyConnectStream();
|
||||
nsresult SendConnectRequest(void* closure, uint32_t* transactionBytes);
|
||||
|
||||
void HandleTunnelResponse(uint16_t responseStatus, bool* reset);
|
||||
void HandleWebSocketResponse(nsHttpRequestHead* requestHead,
|
||||
nsHttpResponseHead* responseHead,
|
||||
uint16_t responseStatus);
|
||||
|
||||
// Value (set in mTCPKeepaliveConfig) indicates which set of prefs to use.
|
||||
enum TCPKeepaliveConfig {
|
||||
kTCPKeepaliveDisabled = 0,
|
||||
|
@ -214,8 +239,6 @@ class nsHttpConnection final : public HttpConnectionBase,
|
|||
[[nodiscard]] nsresult OnSocketWritable();
|
||||
[[nodiscard]] nsresult OnSocketReadable();
|
||||
|
||||
[[nodiscard]] nsresult SetupProxyConnect();
|
||||
|
||||
PRIntervalTime IdleTime();
|
||||
bool IsAlive();
|
||||
|
||||
|
@ -263,9 +286,6 @@ class nsHttpConnection final : public HttpConnectionBase,
|
|||
nsresult mSocketInCondition{NS_ERROR_NOT_INITIALIZED};
|
||||
nsresult mSocketOutCondition{NS_ERROR_NOT_INITIALIZED};
|
||||
|
||||
nsCOMPtr<nsIInputStream> mProxyConnectStream;
|
||||
nsCOMPtr<nsIInputStream> mRequestStream;
|
||||
|
||||
RefPtr<TLSFilterTransaction> mTLSFilter;
|
||||
nsWeakPtr mWeakTrans; // SpdyConnectTransaction *
|
||||
|
||||
|
@ -296,10 +316,8 @@ class nsHttpConnection final : public HttpConnectionBase,
|
|||
bool mKeepAliveMask{true};
|
||||
bool mDontReuse{false};
|
||||
bool mIsReused{false};
|
||||
bool mCompletedProxyConnect{false};
|
||||
bool mLastTransactionExpectedNoContent{false};
|
||||
bool mIdleMonitoring{false};
|
||||
bool mProxyConnectInProgress{false};
|
||||
bool mInSpdyTunnel{false};
|
||||
bool mForcePlainText{false};
|
||||
|
||||
|
@ -390,6 +408,8 @@ class nsHttpConnection final : public HttpConnectionBase,
|
|||
private:
|
||||
bool mThroughCaptivePortal;
|
||||
int64_t mTotalBytesWritten = 0; // does not include CONNECT tunnel
|
||||
|
||||
nsCOMPtr<nsIInputStream> mProxyConnectStream;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsHttpConnection, NS_HTTPCONNECTION_IID)
|
||||
|
|
Загрузка…
Ссылка в новой задаче