/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HttpConnectionBase_h_
#define HttpConnectionBase_h_
#include "nsHttpConnectionInfo.h"
#include "nsAHttpTransaction.h"
#include "nsCOMPtr.h"
#include "nsProxyRelease.h"
#include "prinrval.h"
#include "mozilla/Mutex.h"
#include "ARefBase.h"
#include "TimingStruct.h"
#include "HttpTrafficAnalyzer.h"
#include "mozilla/net/DNS.h"
#include "mozilla/WeakPtr.h"
#include "nsHttpResponseHead.h"
#include "nsIAsyncInputStream.h"
#include "nsIAsyncOutputStream.h"
#include "nsIInterfaceRequestor.h"
#include "nsITimer.h"
class nsISocketTransport;
class nsITLSSocketControl;
namespace mozilla {
namespace net {
class ConnectionEntry;
class nsHttpHandler;
class ASpdySession;
class WebTransportSessionBase;
enum class ConnectionState : uint32_t {
HALF_OPEN =
0,
INITED,
TLS_HANDSHAKING,
ZERORTT,
TRANSFERING,
CLOSED
};
enum class ConnectionExperienceState : uint32_t {
Not_Experienced =
0,
First_Request_Sent = (
1 <<
0),
First_Response_Received = (
1 <<
1),
Experienced = (
1 <<
2),
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ConnectionExperienceState);
// 1dcc863e-db90-4652-a1fe-13fea0b54e46
#define HTTPCONNECTIONBASE_IID \
{
0x437e7d26,
0xa2fd,
0x49f2, {
0xb3,
0x7c,
0x84,
0x23,
0xf0,
0x94,
0x72,
0x36}}
//-----------------------------------------------------------------------------
// nsHttpConnection - represents a connection to a HTTP server (or proxy)
//
// NOTE: this objects lives on the socket thread only. it should not be
// accessed from any other thread.
//-----------------------------------------------------------------------------
class HttpConnectionBase : public nsSupportsWeakReference {
public:
NS_INLINE_DECL_STATIC_IID(HTTPCONNECTIONBASE_IID)
HttpConnectionBase();
// Activate causes the given transaction to be processed on this
// connection. It fails if there is already an existing transaction unless
// a multiplexing protocol such as SPDY is being used
[[nodiscard]] virtual nsresult Activate(nsAHttpTransaction*, uint32_t caps,
int32_t pri) =
0;
// Close the underlying socket transport.
virtual
void Close(nsresult reason,
bool aIsShutdown =
false) =
0;
virtual
bool CanReuse() =
0;
// can this connection be reused?
virtual
bool CanDirectlyActivate() =
0;
virtual
void DontReuse() =
0;
virtual nsAHttpTransaction* Transaction() =
0;
nsHttpConnectionInfo* ConnectionInfo() {
return mConnInfo; }
virtual
void CloseTransaction(nsAHttpTransaction*, nsresult,
bool aIsShutdown =
false) =
0;
[[nodiscard]] virtual nsresult OnHeadersAvailable(nsAHttpTransaction*,
nsHttpRequestHead*,
nsHttpResponseHead*,
bool* reset) =
0;
[[nodiscard]] virtual nsresult TakeTransport(nsISocketTransport**,
nsIAsyncInputStream**,
nsIAsyncOutputStream**) =
0;
virtual WebTransportSessionBase* GetWebTransportSession(
nsAHttpTransaction* aTransaction) {
return nullptr;
}
virtual
bool UsingSpdy() {
return false; }
virtual
bool UsingHttp3() {
return false; }
virtual
void SetTransactionCaps(uint32_t aCaps) { mTransactionCaps = aCaps; }
virtual
void PrintDiagnostics(nsCString& log) =
0;
// IsExperienced() returns true when the connection has started at least one
// non null HTTP transaction of any version.
bool IsExperienced() {
return mExperienced; }
virtual
bool TestJoinConnection(
const nsACString& hostname, int32_t port) =
0;
virtual
bool JoinConnection(
const nsACString& hostname, int32_t port) =
0;
// Return true when the socket this connection is using has not been
// authenticated using a client certificate. Before SSL negotiation
// has finished this returns false.
virtual
bool NoClientCertAuth()
const {
return true; }
// HTTP/2 websocket support
virtual ExtendedCONNECTSupport GetExtendedCONNECTSupport() {
return ExtendedCONNECTSupport::NO_SUPPORT;
}
void GetConnectionInfo(nsHttpConnectionInfo** ci) {
*ci = do_AddRef(mConnInfo).take();
}
virtual
void GetTLSSocketControl(nsITLSSocketControl** result) =
0;
[[nodiscard]] virtual nsresult ResumeSend() =
0;
[[nodiscard]] virtual nsresult ResumeRecv() =
0;
[[nodiscard]] virtual nsresult ForceSend() =
0;
[[nodiscard]] virtual nsresult ForceRecv() =
0;
virtual HttpVersion Version() =
0;
virtual
bool LastTransactionExpectedNoContent() =
0;
virtual
void SetLastTransactionExpectedNoContent(
bool) =
0;
virtual int64_t BytesWritten() =
0;
// includes TLS
void SetSecurityCallbacks(nsIInterfaceRequestor* aCallbacks);
already_AddRefed<nsIInterfaceRequestor> GetCallbacks() {
MutexAutoLock lock(mCallbacksLock);
return do_AddRef(mCallbacks.get());
}
// Call only from Init(), before the object is shared with other threads.
void InitCallbacks(nsIInterfaceRequestor* aCallbacks,
const char* aName) MOZ_NO_THREAD_SAFETY_ANALYSIS {
mCallbacks =
new nsMainThreadPtrHolder<nsIInterfaceRequestor>(
aName, aCallbacks,
false);
}
void SetTrafficCategory(HttpTrafficCategory);
void BootstrapTimings(TimingStruct times);
void SetDnsBootstrapTimings(TimeStamp domainLookupStart,
TimeStamp domainLookupEnd);
void SetConnectBootstrapTimings(TimeStamp connectStart,
TimeStamp tcpConnectEnd,
TimeStamp secureConnectionStart = TimeStamp(),
TimeStamp connectEnd = TimeStamp());
virtual
bool IsPersistent() =
0;
virtual
bool IsReused() =
0;
[[nodiscard]] virtual nsresult PushBack(
const char* data,
uint32_t length) =
0;
PRIntervalTime Rtt() {
return mRtt; }
virtual
void SetEvent(nsresult aStatus) =
0;
virtual nsISocketTransport* Transport() {
return nullptr; }
virtual nsresult GetSelfAddr(NetAddr* addr) =
0;
virtual nsresult GetPeerAddr(NetAddr* addr) =
0;
virtual
bool ResolvedByTRR() =
0;
virtual nsIRequest::TRRMode EffectiveTRRMode() =
0;
virtual TRRSkippedReason TRRSkipReason() =
0;
virtual
bool GetEchConfigUsed() =
0;
virtual PRIntervalTime LastWriteTime() =
0;
void ChangeConnectionState(ConnectionState aState);
ConnectionCloseReason CloseReason()
const {
return mCloseReason; }
void SetCloseReason(ConnectionCloseReason aReason) {
if (mCloseReason == ConnectionCloseReason::UNSET) {
mCloseReason = aReason;
}
}
void RecordConnectionCloseTelemetry(nsresult aReason);
void RecordConnectionAddressType();
bool IsProxyConnectInProgress() {
return mState == SETTING_UP_TUNNEL; }
virtual nsresult CreateTunnelStream(nsAHttpTransaction* httpTransaction,
HttpConnectionBase** aHttpConnection,
bool aIsExtendedCONNECT =
false) =
0;
virtual
void SetInTunnel() {};
const RefPtr<ProxyConnectResponseHead>& GetProxyConnectResponseHead()
const {
return mProxyConnectResponseHead;
}
void SetOwner(ConnectionEntry* aEntry);
ConnectionEntry* OwnerEntry()
const;
void SetIsRacing(
bool aValue) { mIsRacing = aValue; }
bool IsRacing()
const {
return mIsRacing; }
virtual
void SetDontExclude() {}
protected:
// The capabailities associated with the most recent transaction
uint32_t mTransactionCaps{
0};
RefPtr<nsHttpConnectionInfo> mConnInfo;
// Set when this connection is added to the active connections list,
// cleared when it is removed.
WeakPtr<ConnectionEntry> mOwnerEntry;
bool mExperienced{
false};
// Used to track whether this connection is serving the first request.
bool mHasFirstHttpTransaction{
false};
bool mBootstrappedTimingsSet{
false};
TimingStruct mBootstrappedTimings;
Mutex mCallbacksLock{
"nsHttpConnection::mCallbacksLock"};
nsMainThreadPtrHandle<nsIInterfaceRequestor> mCallbacks
MOZ_GUARDED_BY(mCallbacksLock);
nsTArray<HttpTrafficCategory> mTrafficCategory;
PRIntervalTime mRtt{
0};
nsresult mErrorBeforeConnect = NS_OK;
ConnectionState mConnectionState = ConnectionState::HALF_OPEN;
// Represent if the connection has served more than one request.
ConnectionExperienceState mExperienceState =
ConnectionExperienceState::Not_Experienced;
ConnectionCloseReason mCloseReason = ConnectionCloseReason::UNSET;
bool mAddressTypeReported{
false};
bool mIsRacing{
false};
// Tunnel related functions:
enum HttpConnectionState {
UNINITIALIZED,
SETTING_UP_TUNNEL,
REQUEST,
} mState{HttpConnectionState::UNINITIALIZED};
void ChangeState(HttpConnectionState newState);
bool TunnelSetupInProgress() {
return mState == SETTING_UP_TUNNEL; }
virtual
void SetTunnelSetupDone() {}
virtual nsresult SetupProxyConnectStream() {
return NS_OK; }
nsresult CheckTunnelIsNeeded(nsAHttpTransaction* aTransaction);
// Built once when the CONNECT tunnel is established and then shared by
// pointer with the transaction and channel. See bug 2045419.
RefPtr<ProxyConnectResponseHead> mProxyConnectResponseHead;
};
#define NS_DECL_HTTPCONNECTIONBASE \
[[nodiscard]] nsresult Activate(nsAHttpTransaction*, uint32_t, int32_t) \
override; \
[[nodiscard]] nsresult OnHeadersAvailable( \
nsAHttpTransaction*, nsHttpRequestHead*, nsHttpResponseHead*, \
bool* reset) override; \
[[nodiscard]] nsresult TakeTransport( \
nsISocketTransport**, nsIAsyncInputStream**, nsIAsyncOutputStream**) \
override; \
void Close(nsresult,
bool aIsShutdown =
false) override; \
bool CanReuse() override; \
bool CanDirectlyActivate() override; \
void DontReuse() override; \
void CloseTransaction(nsAHttpTransaction*, nsresult, \
bool aIsShutdown =
false) override; \
void PrintDiagnostics(nsCString&) override; \
bool TestJoinConnection(
const nsACString&, int32_t) override; \
bool JoinConnection(
const nsACString&, int32_t) override; \
void GetTLSSocketControl(nsITLSSocketControl** result) override; \
[[nodiscard]] nsresult ResumeSend() override; \
[[nodiscard]] nsresult ResumeRecv() override; \
[[nodiscard]] nsresult ForceSend() override; \
[[nodiscard]] nsresult ForceRecv() override; \
HttpVersion Version() override; \
bool LastTransactionExpectedNoContent() override; \
void SetLastTransactionExpectedNoContent(
bool val) override; \
bool IsPersistent() override; \
bool IsReused() override; \
[[nodiscard]] nsresult PushBack(
const char* data, uint32_t length) override; \
void SetEvent(nsresult aStatus) override; \
virtual nsAHttpTransaction* Transaction() override; \
PRIntervalTime LastWriteTime() override;
}
// namespace net
}
// namespace mozilla
#endif // HttpConnectionBase_h_