mirror of
https://github.com/classilla/tenfourfox.git
synced 2024-06-06 22:29:34 +00:00
#594: M1322373
This commit is contained in:
parent
d7c27ac739
commit
d0b344ece9
|
@ -36,7 +36,8 @@ ASpdySession::~ASpdySession()
|
||||||
|
|
||||||
ASpdySession *
|
ASpdySession *
|
||||||
ASpdySession::NewSpdySession(uint32_t version,
|
ASpdySession::NewSpdySession(uint32_t version,
|
||||||
nsISocketTransport *aTransport)
|
nsISocketTransport *aTransport,
|
||||||
|
bool attemptingEarlyData)
|
||||||
{
|
{
|
||||||
// This is a necko only interface, so we can enforce version
|
// This is a necko only interface, so we can enforce version
|
||||||
// requests as a precondition
|
// requests as a precondition
|
||||||
|
@ -49,12 +50,12 @@ ASpdySession::NewSpdySession(uint32_t version,
|
||||||
// from a list provided in the SERVER HELLO filtered by our acceptable
|
// from a list provided in the SERVER HELLO filtered by our acceptable
|
||||||
// versions, so there is no risk of the server ignoring our prefs.
|
// versions, so there is no risk of the server ignoring our prefs.
|
||||||
|
|
||||||
Telemetry::Accumulate(Telemetry::SPDY_VERSION2, version);
|
//Telemetry::Accumulate(Telemetry::SPDY_VERSION2, version);
|
||||||
|
|
||||||
if (version == SPDY_VERSION_31) {
|
if (version == SPDY_VERSION_31) {
|
||||||
return new SpdySession31(aTransport);
|
return new SpdySession31(aTransport);
|
||||||
} else if (version == HTTP_VERSION_2) {
|
} else if (version == HTTP_VERSION_2) {
|
||||||
return new Http2Session(aTransport, version);
|
return new Http2Session(aTransport, version, attemptingEarlyData);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -28,8 +28,9 @@ public:
|
||||||
virtual PRIntervalTime IdleTime() = 0;
|
virtual PRIntervalTime IdleTime() = 0;
|
||||||
virtual uint32_t ReadTimeoutTick(PRIntervalTime now) = 0;
|
virtual uint32_t ReadTimeoutTick(PRIntervalTime now) = 0;
|
||||||
virtual void DontReuse() = 0;
|
virtual void DontReuse() = 0;
|
||||||
|
virtual uint32_t SpdyVersion() = 0;
|
||||||
|
|
||||||
static ASpdySession *NewSpdySession(uint32_t version, nsISocketTransport *);
|
static ASpdySession *NewSpdySession(uint32_t version, nsISocketTransport *, bool);
|
||||||
|
|
||||||
// MaybeReTunnel() is called by the connection manager when it cannot
|
// MaybeReTunnel() is called by the connection manager when it cannot
|
||||||
// dispatch a tunneled transaction. That might be because the tunnels it
|
// dispatch a tunneled transaction. That might be because the tunnels it
|
||||||
|
|
|
@ -63,7 +63,7 @@ do { \
|
||||||
return NS_ERROR_ILLEGAL_VALUE; \
|
return NS_ERROR_ILLEGAL_VALUE; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t version)
|
Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t version, bool attemptingEarlyData)
|
||||||
: mSocketTransport(aSocketTransport)
|
: mSocketTransport(aSocketTransport)
|
||||||
, mSegmentReader(nullptr)
|
, mSegmentReader(nullptr)
|
||||||
, mSegmentWriter(nullptr)
|
, mSegmentWriter(nullptr)
|
||||||
|
@ -110,6 +110,7 @@ Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t versio
|
||||||
, mWaitingForSettingsAck(false)
|
, mWaitingForSettingsAck(false)
|
||||||
, mGoAwayOnPush(false)
|
, mGoAwayOnPush(false)
|
||||||
, mUseH2Deps(false)
|
, mUseH2Deps(false)
|
||||||
|
, mAttemptingEarlyData(attemptingEarlyData)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
MOZ_ASSERT(PR_GetCurrentThread() == gSocketThread);
|
||||||
|
|
||||||
|
@ -510,6 +511,12 @@ Http2Session::SetWriteCallbacks()
|
||||||
void
|
void
|
||||||
Http2Session::RealignOutputQueue()
|
Http2Session::RealignOutputQueue()
|
||||||
{
|
{
|
||||||
|
if (mAttemptingEarlyData) {
|
||||||
|
// We can't realign right now, because we may need what's in there if early
|
||||||
|
// data fails.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mOutputQueueUsed -= mOutputQueueSent;
|
mOutputQueueUsed -= mOutputQueueSent;
|
||||||
memmove(mOutputQueueBuffer.get(),
|
memmove(mOutputQueueBuffer.get(),
|
||||||
mOutputQueueBuffer.get() + mOutputQueueSent,
|
mOutputQueueBuffer.get() + mOutputQueueSent,
|
||||||
|
@ -527,6 +534,14 @@ Http2Session::FlushOutputQueue()
|
||||||
uint32_t countRead;
|
uint32_t countRead;
|
||||||
uint32_t avail = mOutputQueueUsed - mOutputQueueSent;
|
uint32_t avail = mOutputQueueUsed - mOutputQueueSent;
|
||||||
|
|
||||||
|
if (!avail && mAttemptingEarlyData) {
|
||||||
|
// This is kind of a hack, but there are cases where we'll have already
|
||||||
|
// written the data we want whlie doing early data, but we get called again
|
||||||
|
// with a reader, and we need to avoid calling the reader when there's
|
||||||
|
// nothing for it to read.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
rv = mSegmentReader->
|
rv = mSegmentReader->
|
||||||
OnReadSegment(mOutputQueueBuffer.get() + mOutputQueueSent, avail,
|
OnReadSegment(mOutputQueueBuffer.get() + mOutputQueueSent, avail,
|
||||||
&countRead);
|
&countRead);
|
||||||
|
@ -537,14 +552,18 @@ Http2Session::FlushOutputQueue()
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
mOutputQueueSent += countRead;
|
||||||
|
|
||||||
|
if (mAttemptingEarlyData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (countRead == avail) {
|
if (countRead == avail) {
|
||||||
mOutputQueueUsed = 0;
|
mOutputQueueUsed = 0;
|
||||||
mOutputQueueSent = 0;
|
mOutputQueueSent = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mOutputQueueSent += countRead;
|
|
||||||
|
|
||||||
// If the output queue is close to filling up and we have sent out a good
|
// If the output queue is close to filling up and we have sent out a good
|
||||||
// chunk of data from the beginning then realign it.
|
// chunk of data from the beginning then realign it.
|
||||||
|
|
||||||
|
@ -562,6 +581,12 @@ Http2Session::DontReuse()
|
||||||
Close(NS_OK);
|
Close(NS_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
Http2Session::SpdyVersion()
|
||||||
|
{
|
||||||
|
return HTTP_VERSION_2;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t
|
uint32_t
|
||||||
Http2Session::GetWriteQueueSize()
|
Http2Session::GetWriteQueueSize()
|
||||||
{
|
{
|
||||||
|
@ -2316,7 +2341,36 @@ Http2Session::ReadSegmentsAgain(nsAHttpSegmentReader *reader,
|
||||||
ResumeRecv();
|
ResumeRecv();
|
||||||
}
|
}
|
||||||
SetWriteCallbacks();
|
SetWriteCallbacks();
|
||||||
return NS_BASE_STREAM_WOULD_BLOCK;
|
if (mAttemptingEarlyData) {
|
||||||
|
// We can still try to send our preamble as early-data
|
||||||
|
*countRead = mOutputQueueUsed - mOutputQueueSent;
|
||||||
|
}
|
||||||
|
return *countRead ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t earlyDataUsed = 0;
|
||||||
|
if (mAttemptingEarlyData) {
|
||||||
|
if (!stream->Do0RTT()) {
|
||||||
|
LOG3(("Http2Session %p will not get early data from Http2Stream %p 0x%X",
|
||||||
|
this, stream, stream->StreamID()));
|
||||||
|
FlushOutputQueue();
|
||||||
|
SetWriteCallbacks();
|
||||||
|
// We can still send our preamble
|
||||||
|
*countRead = mOutputQueueUsed - mOutputQueueSent;
|
||||||
|
return *countRead ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m0RTTStreams.Contains(stream->StreamID())) {
|
||||||
|
m0RTTStreams.AppendElement(stream->StreamID());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to adjust this to only take as much as we can fit in with the
|
||||||
|
// preamble/settings/priority stuff
|
||||||
|
count -= (mOutputQueueUsed - mOutputQueueSent);
|
||||||
|
|
||||||
|
// Keep track of this to add it into countRead later, as
|
||||||
|
// stream->ReadSegments will likely change the value of mOutputQueueUsed.
|
||||||
|
earlyDataUsed = mOutputQueueUsed - mOutputQueueSent;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG3(("Http2Session %p will write from Http2Stream %p 0x%X "
|
LOG3(("Http2Session %p will write from Http2Stream %p 0x%X "
|
||||||
|
@ -2325,6 +2379,13 @@ Http2Session::ReadSegmentsAgain(nsAHttpSegmentReader *reader,
|
||||||
|
|
||||||
rv = stream->ReadSegments(this, count, countRead);
|
rv = stream->ReadSegments(this, count, countRead);
|
||||||
|
|
||||||
|
if (earlyDataUsed) {
|
||||||
|
// Do this here because countRead could get reset somewhere down the rabbit
|
||||||
|
// hole of stream->ReadSegments, and we want to make sure we return the
|
||||||
|
// proper value to our caller.
|
||||||
|
*countRead += earlyDataUsed;
|
||||||
|
}
|
||||||
|
|
||||||
// Not every permutation of stream->ReadSegents produces data (and therefore
|
// Not every permutation of stream->ReadSegents produces data (and therefore
|
||||||
// tries to flush the output queue) - SENDING_FIN_STREAM can be an example
|
// tries to flush the output queue) - SENDING_FIN_STREAM can be an example
|
||||||
// of that. But we might still have old data buffered that would be good
|
// of that. But we might still have old data buffered that would be good
|
||||||
|
@ -2873,6 +2934,58 @@ Http2Session::WriteSegments(nsAHttpSegmentWriter *writer,
|
||||||
return WriteSegmentsAgain(writer, count, countWritten, &again);
|
return WriteSegmentsAgain(writer, count, countWritten, &again);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
Http2Session::Finish0RTT(bool aRestart, bool aAlpnChanged)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mAttemptingEarlyData);
|
||||||
|
LOG3(("Http2Session::Finish0RTT %p aRestart=%d aAlpnChanged=%d", this,
|
||||||
|
aRestart, aAlpnChanged));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m0RTTStreams.Length(); ++i) {
|
||||||
|
// Instead of passing (aRestart, aAlpnChanged) here, we use aAlpnChanged for
|
||||||
|
// both arguments because as long as the alpn token stayed the same, we can
|
||||||
|
// just reuse what we have in our buffer to send instead of having to have
|
||||||
|
// the transaction rewind and read it all over again. We only need to rewind
|
||||||
|
// the transaction if we're switching to a new protocol, because our buffer
|
||||||
|
// won't get used in that case.
|
||||||
|
Http2Stream *stream = mStreamIDHash.Get(m0RTTStreams[i]);
|
||||||
|
if (stream) {
|
||||||
|
stream->Finish0RTT(aAlpnChanged, aAlpnChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aRestart) {
|
||||||
|
// 0RTT failed
|
||||||
|
if (aAlpnChanged) {
|
||||||
|
// This is a slightly more involved case - we need to get all our streams/
|
||||||
|
// transactions back in the queue so they can restart as http/1
|
||||||
|
|
||||||
|
// These must be set this way to ensure we gracefully restart all streams
|
||||||
|
mGoAwayID = 0;
|
||||||
|
mCleanShutdown = true;
|
||||||
|
|
||||||
|
// Close takes care of the rest of our work for us. The reason code here
|
||||||
|
// doesn't matter, as we aren't actually going to send a GOAWAY frame, but
|
||||||
|
// we use NS_ERROR_NET_RESET as it's closest to the truth.
|
||||||
|
Close(NS_ERROR_NET_RESET);
|
||||||
|
} else {
|
||||||
|
// This is the easy case - early data failed, but we're speaking h2, so
|
||||||
|
// we just need to rewind to the beginning of the preamble and try again.
|
||||||
|
mOutputQueueSent = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 0RTT succeeded
|
||||||
|
// Make sure we look for any incoming data in repsonse to our early data.
|
||||||
|
ResumeRecv();
|
||||||
|
}
|
||||||
|
|
||||||
|
mAttemptingEarlyData = false;
|
||||||
|
m0RTTStreams.Clear();
|
||||||
|
RealignOutputQueue();
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
Http2Session::ProcessConnectedPush(Http2Stream *pushConnectedStream,
|
Http2Session::ProcessConnectedPush(Http2Stream *pushConnectedStream,
|
||||||
nsAHttpSegmentWriter * writer,
|
nsAHttpSegmentWriter * writer,
|
||||||
|
@ -3080,7 +3193,9 @@ Http2Session::Close(nsresult aReason)
|
||||||
} else {
|
} else {
|
||||||
goAwayReason = INTERNAL_ERROR;
|
goAwayReason = INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
GenerateGoAway(goAwayReason);
|
if (!mAttemptingEarlyData) {
|
||||||
|
GenerateGoAway(goAwayReason);
|
||||||
|
}
|
||||||
mConnection = nullptr;
|
mConnection = nullptr;
|
||||||
mSegmentReader = nullptr;
|
mSegmentReader = nullptr;
|
||||||
mSegmentWriter = nullptr;
|
mSegmentWriter = nullptr;
|
||||||
|
@ -3181,7 +3296,7 @@ Http2Session::OnReadSegment(const char *buf,
|
||||||
nsresult
|
nsresult
|
||||||
Http2Session::CommitToSegmentSize(uint32_t count, bool forceCommitment)
|
Http2Session::CommitToSegmentSize(uint32_t count, bool forceCommitment)
|
||||||
{
|
{
|
||||||
if (mOutputQueueUsed)
|
if (mOutputQueueUsed && !mAttemptingEarlyData)
|
||||||
FlushOutputQueue();
|
FlushOutputQueue();
|
||||||
|
|
||||||
// would there be enough room to buffer this if needed?
|
// would there be enough room to buffer this if needed?
|
||||||
|
@ -3500,12 +3615,18 @@ Http2Session::ALPNCallback(nsISupports *securityInfo)
|
||||||
nsresult
|
nsresult
|
||||||
Http2Session::ConfirmTLSProfile()
|
Http2Session::ConfirmTLSProfile()
|
||||||
{
|
{
|
||||||
if (mTLSProfileConfirmed)
|
if (mTLSProfileConfirmed) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
LOG3(("Http2Session::ConfirmTLSProfile %p mConnection=%p\n",
|
LOG3(("Http2Session::ConfirmTLSProfile %p mConnection=%p\n",
|
||||||
this, mConnection.get()));
|
this, mConnection.get()));
|
||||||
|
|
||||||
|
if (mAttemptingEarlyData) {
|
||||||
|
LOG3(("Http2Session::ConfirmTLSProfile %p temporarily passing due to early data\n", this));
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
if (!gHttpHandler->EnforceHttp2TlsProfile()) {
|
if (!gHttpHandler->EnforceHttp2TlsProfile()) {
|
||||||
LOG3(("Http2Session::ConfirmTLSProfile %p passed due to configuration bypass\n", this));
|
LOG3(("Http2Session::ConfirmTLSProfile %p passed due to configuration bypass\n", this));
|
||||||
mTLSProfileConfirmed = true;
|
mTLSProfileConfirmed = true;
|
||||||
|
|
|
@ -43,12 +43,13 @@ public:
|
||||||
NS_DECL_NSAHTTPSEGMENTREADER
|
NS_DECL_NSAHTTPSEGMENTREADER
|
||||||
NS_DECL_NSAHTTPSEGMENTWRITER
|
NS_DECL_NSAHTTPSEGMENTWRITER
|
||||||
|
|
||||||
Http2Session(nsISocketTransport *, uint32_t version);
|
Http2Session(nsISocketTransport *, uint32_t version, bool attemptingEarlyData);
|
||||||
|
|
||||||
bool AddStream(nsAHttpTransaction *, int32_t,
|
bool AddStream(nsAHttpTransaction *, int32_t,
|
||||||
bool, nsIInterfaceRequestor *) override;
|
bool, nsIInterfaceRequestor *) override;
|
||||||
bool CanReuse() override { return !mShouldGoAway && !mClosed; }
|
bool CanReuse() override { return !mShouldGoAway && !mClosed; }
|
||||||
bool RoomForMoreStreams() override;
|
bool RoomForMoreStreams() override;
|
||||||
|
uint32_t SpdyVersion() override;
|
||||||
|
|
||||||
// When the connection is active this is called up to once every 1 second
|
// When the connection is active this is called up to once every 1 second
|
||||||
// return the interval (in seconds) that the connection next wants to
|
// return the interval (in seconds) that the connection next wants to
|
||||||
|
@ -235,6 +236,8 @@ public:
|
||||||
// overload of nsAHttpTransaction
|
// overload of nsAHttpTransaction
|
||||||
nsresult ReadSegmentsAgain(nsAHttpSegmentReader *, uint32_t, uint32_t *, bool *) override final;
|
nsresult ReadSegmentsAgain(nsAHttpSegmentReader *, uint32_t, uint32_t *, bool *) override final;
|
||||||
nsresult WriteSegmentsAgain(nsAHttpSegmentWriter *, uint32_t , uint32_t *, bool *) override final;
|
nsresult WriteSegmentsAgain(nsAHttpSegmentWriter *, uint32_t , uint32_t *, bool *) override final;
|
||||||
|
bool Do0RTT() override final { return true; }
|
||||||
|
nsresult Finish0RTT(bool aRestart, bool aAlpnChanged) override final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -505,6 +508,10 @@ private:
|
||||||
|
|
||||||
bool mUseH2Deps;
|
bool mUseH2Deps;
|
||||||
|
|
||||||
|
bool mAttemptingEarlyData;
|
||||||
|
// The ID(s) of the stream(s) that we are getting 0RTT data from.
|
||||||
|
nsTArray<uint32_t> m0RTTStreams;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// connect tunnels
|
/// connect tunnels
|
||||||
void DispatchOnTunnel(nsAHttpTransaction *, nsIInterfaceRequestor *);
|
void DispatchOnTunnel(nsAHttpTransaction *, nsIInterfaceRequestor *);
|
||||||
|
|
|
@ -70,6 +70,7 @@ Http2Stream::Http2Stream(nsAHttpTransaction *httpTransaction,
|
||||||
, mTotalSent(0)
|
, mTotalSent(0)
|
||||||
, mTotalRead(0)
|
, mTotalRead(0)
|
||||||
, mPushSource(nullptr)
|
, mPushSource(nullptr)
|
||||||
|
, mAttempting0RTT(false)
|
||||||
, mIsTunnel(false)
|
, mIsTunnel(false)
|
||||||
, mPlainTextTunnel(false)
|
, mPlainTextTunnel(false)
|
||||||
{
|
{
|
||||||
|
@ -950,7 +951,9 @@ Http2Stream::TransmitFrame(const char *buf,
|
||||||
*countUsed += mTxStreamFrameSize;
|
*countUsed += mTxStreamFrameSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
mSession->FlushOutputQueue();
|
if (!mAttempting0RTT) {
|
||||||
|
mSession->FlushOutputQueue();
|
||||||
|
}
|
||||||
|
|
||||||
// calling this will trigger waiting_for if mRequestBodyLenRemaining is 0
|
// calling this will trigger waiting_for if mRequestBodyLenRemaining is 0
|
||||||
UpdateTransportSendEvents(mTxInlineFrameUsed + mTxStreamFrameSize);
|
UpdateTransportSendEvents(mTxInlineFrameUsed + mTxStreamFrameSize);
|
||||||
|
@ -1485,6 +1488,26 @@ Http2Stream::MapStreamToHttpConnection()
|
||||||
mTransaction->ConnectionInfo());
|
mTransaction->ConnectionInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// mirror nsAHttpTransaction
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool
|
||||||
|
Http2Stream::Do0RTT()
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mTransaction);
|
||||||
|
mAttempting0RTT = true;
|
||||||
|
return mTransaction->Do0RTT();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
Http2Stream::Finish0RTT(bool aRestart, bool aAlpnChanged)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mTransaction);
|
||||||
|
mAttempting0RTT = false;
|
||||||
|
return mTransaction->Finish0RTT(aRestart, aAlpnChanged);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace net
|
} // namespace net
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
|
|
|
@ -154,6 +154,10 @@ public:
|
||||||
const nsACString &origin,
|
const nsACString &origin,
|
||||||
RefPtr<nsStandardURL> &url);
|
RefPtr<nsStandardURL> &url);
|
||||||
|
|
||||||
|
// Mirrors nsAHttpTransaction
|
||||||
|
bool Do0RTT();
|
||||||
|
nsresult Finish0RTT(bool aRestart, bool aAlpnIgnored);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void CreatePushHashKey(const nsCString &scheme,
|
static void CreatePushHashKey(const nsCString &scheme,
|
||||||
const nsCString &hostHeader,
|
const nsCString &hostHeader,
|
||||||
|
@ -328,6 +332,8 @@ private:
|
||||||
nsCOMPtr<nsIInputStream> mInputBufferIn;
|
nsCOMPtr<nsIInputStream> mInputBufferIn;
|
||||||
nsCOMPtr<nsIOutputStream> mInputBufferOut;
|
nsCOMPtr<nsIOutputStream> mInputBufferOut;
|
||||||
|
|
||||||
|
bool mAttempting0RTT;
|
||||||
|
|
||||||
/// connect tunnels
|
/// connect tunnels
|
||||||
public:
|
public:
|
||||||
bool IsTunnel() { return mIsTunnel; }
|
bool IsTunnel() { return mIsTunnel; }
|
||||||
|
|
|
@ -46,6 +46,7 @@ public:
|
||||||
bool, nsIInterfaceRequestor *) override;
|
bool, nsIInterfaceRequestor *) override;
|
||||||
bool CanReuse() override { return !mShouldGoAway && !mClosed; }
|
bool CanReuse() override { return !mShouldGoAway && !mClosed; }
|
||||||
bool RoomForMoreStreams() override;
|
bool RoomForMoreStreams() override;
|
||||||
|
uint32_t SpdyVersion() override { return SPDY_VERSION_31; }
|
||||||
|
|
||||||
// When the connection is active this is called up to once every 1 second
|
// When the connection is active this is called up to once every 1 second
|
||||||
// return the interval (in seconds) that the connection next wants to
|
// return the interval (in seconds) that the connection next wants to
|
||||||
|
|
|
@ -216,8 +216,11 @@ public:
|
||||||
// If aRestart parameter is true we need to restart the transaction,
|
// If aRestart parameter is true we need to restart the transaction,
|
||||||
// otherwise the erly-data has been accepted and we can continue the
|
// otherwise the erly-data has been accepted and we can continue the
|
||||||
// transaction.
|
// transaction.
|
||||||
|
// If aAlpnChanged is true (and we were assuming http/2), we'll need to take
|
||||||
|
// the transactions out of the session, rewind them all, and start them back
|
||||||
|
// over as http/1 transactions
|
||||||
// The function will return success or failure of the transaction restart.
|
// The function will return success or failure of the transaction restart.
|
||||||
virtual nsresult Finish0RTT(bool aRestart) {
|
virtual nsresult Finish0RTT(bool aRestart, bool aAlpnChanged) {
|
||||||
return NS_ERROR_NOT_IMPLEMENTED;
|
return NS_ERROR_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -82,6 +82,7 @@ nsHttpConnection::nsHttpConnection()
|
||||||
, m0RTTChecked(false)
|
, m0RTTChecked(false)
|
||||||
, mWaitingFor0RTTResponse(false)
|
, mWaitingFor0RTTResponse(false)
|
||||||
, mContentBytesWritten0RTT(0)
|
, mContentBytesWritten0RTT(0)
|
||||||
|
, mDid0RTTSpdy(false)
|
||||||
{
|
{
|
||||||
LOG(("Creating nsHttpConnection @%p\n", this));
|
LOG(("Creating nsHttpConnection @%p\n", this));
|
||||||
|
|
||||||
|
@ -157,15 +158,114 @@ nsHttpConnection::Init(nsHttpConnectionInfo *info,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsHttpConnection::TryTakeSubTransactions(nsTArray<RefPtr<nsAHttpTransaction> > &list)
|
||||||
|
{
|
||||||
|
nsresult rv = mTransaction->TakeSubTransactions(list);
|
||||||
|
|
||||||
|
if (rv == NS_ERROR_ALREADY_OPENED) {
|
||||||
|
// Has the interface for TakeSubTransactions() changed?
|
||||||
|
LOG(("TakeSubTransactions somehow called after "
|
||||||
|
"nsAHttpTransaction began processing\n"));
|
||||||
|
MOZ_ASSERT(false,
|
||||||
|
"TakeSubTransactions somehow called after "
|
||||||
|
"nsAHttpTransaction began processing");
|
||||||
|
mTransaction->Close(NS_ERROR_ABORT);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
|
||||||
|
// Has the interface for TakeSubTransactions() changed?
|
||||||
|
LOG(("unexpected rv from nnsAHttpTransaction::TakeSubTransactions()"));
|
||||||
|
MOZ_ASSERT(false,
|
||||||
|
"unexpected result from "
|
||||||
|
"nsAHttpTransaction::TakeSubTransactions()");
|
||||||
|
mTransaction->Close(NS_ERROR_ABORT);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsHttpConnection::MoveTransactionsToSpdy(nsresult status, nsTArray<RefPtr<nsAHttpTransaction> > &list)
|
||||||
|
{
|
||||||
|
if (NS_FAILED(status)) { // includes NS_ERROR_NOT_IMPLEMENTED
|
||||||
|
MOZ_ASSERT(list.IsEmpty(), "sub transaction list not empty");
|
||||||
|
|
||||||
|
// This is ok - treat mTransaction as a single real request.
|
||||||
|
// Wrap the old http transaction into the new spdy session
|
||||||
|
// as the first stream.
|
||||||
|
LOG(("nsHttpConnection::MoveTransactionsToSpdy moves single transaction %p "
|
||||||
|
"into SpdySession %p\n", mTransaction.get(), mSpdySession.get()));
|
||||||
|
nsresult rv = AddTransaction(mTransaction, mPriority);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int32_t count = list.Length();
|
||||||
|
|
||||||
|
LOG(("nsHttpConnection::MoveTransactionsToSpdy moving transaction list len=%d "
|
||||||
|
"into SpdySession %p\n", count, mSpdySession.get()));
|
||||||
|
|
||||||
|
if (!count) {
|
||||||
|
mTransaction->Close(NS_ERROR_ABORT);
|
||||||
|
return NS_ERROR_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int32_t index = 0; index < count; ++index) {
|
||||||
|
nsresult rv = AddTransaction(list[index], mPriority);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsHttpConnection::Start0RTTSpdy(uint8_t spdyVersion)
|
||||||
|
{
|
||||||
|
LOG(("nsHttpConnection::Start0RTTSpdy [this=%p]", this));
|
||||||
|
mDid0RTTSpdy = true;
|
||||||
|
mUsingSpdyVersion = spdyVersion;
|
||||||
|
mSpdySession = ASpdySession::NewSpdySession(spdyVersion, mSocketTransport,
|
||||||
|
true);
|
||||||
|
|
||||||
|
nsTArray<RefPtr<nsAHttpTransaction> > list;
|
||||||
|
nsresult rv = TryTakeSubTransactions(list);
|
||||||
|
if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
|
||||||
|
LOG(("nsHttpConnection::Start0RTTSpdy [this=%p] failed taking "
|
||||||
|
"subtransactions rv=%" PRIx32 , this, static_cast<uint32_t>(rv)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = MoveTransactionsToSpdy(rv, list);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
LOG(("nsHttpConnection::Start0RTTSpdy [this=%p] failed moving "
|
||||||
|
"transactions rv=%" PRIx32 , this, static_cast<uint32_t>(rv)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTransaction = mSpdySession;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nsHttpConnection::StartSpdy(uint8_t spdyVersion)
|
nsHttpConnection::StartSpdy(uint8_t spdyVersion)
|
||||||
{
|
{
|
||||||
LOG(("nsHttpConnection::StartSpdy [this=%p]\n", this));
|
LOG(("nsHttpConnection::StartSpdy [this=%p, mDid0RTTSpdy=%d]\n", this, mDid0RTTSpdy));
|
||||||
|
|
||||||
MOZ_ASSERT(!mSpdySession);
|
MOZ_ASSERT(!mSpdySession || mDid0RTTSpdy);
|
||||||
|
|
||||||
mUsingSpdyVersion = spdyVersion;
|
mUsingSpdyVersion = spdyVersion;
|
||||||
mEverUsedSpdy = true;
|
mEverUsedSpdy = true;
|
||||||
|
// see also bug 865314 for backbugs
|
||||||
|
// https://hg.mozilla.org/mozilla-central/rev/b1e8d6cf54e6
|
||||||
|
if (!mDid0RTTSpdy) {
|
||||||
|
mSpdySession = ASpdySession::NewSpdySession(spdyVersion,
|
||||||
|
mSocketTransport, false);
|
||||||
|
}
|
||||||
|
|
||||||
if (!mReportedSpdy) {
|
if (!mReportedSpdy) {
|
||||||
mReportedSpdy = true;
|
mReportedSpdy = true;
|
||||||
|
@ -183,27 +283,12 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion)
|
||||||
// pack them all into a new spdy session.
|
// pack them all into a new spdy session.
|
||||||
|
|
||||||
nsTArray<RefPtr<nsAHttpTransaction> > list;
|
nsTArray<RefPtr<nsAHttpTransaction> > list;
|
||||||
nsresult rv = mTransaction->TakeSubTransactions(list);
|
nsresult rv = NS_OK;
|
||||||
|
if (!mDid0RTTSpdy) {
|
||||||
if (rv == NS_ERROR_ALREADY_OPENED) {
|
rv = TryTakeSubTransactions(list);
|
||||||
// Has the interface for TakeSubTransactions() changed?
|
if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
|
||||||
LOG(("TakeSubTransactions somehow called after "
|
return;
|
||||||
"nsAHttpTransaction began processing\n"));
|
}
|
||||||
MOZ_ASSERT(false,
|
|
||||||
"TakeSubTransactions somehow called after "
|
|
||||||
"nsAHttpTransaction began processing");
|
|
||||||
mTransaction->Close(NS_ERROR_ABORT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) {
|
|
||||||
// Has the interface for TakeSubTransactions() changed?
|
|
||||||
LOG(("unexpected rv from nnsAHttpTransaction::TakeSubTransactions()"));
|
|
||||||
MOZ_ASSERT(false,
|
|
||||||
"unexpected result from "
|
|
||||||
"nsAHttpTransaction::TakeSubTransactions()");
|
|
||||||
mTransaction->Close(NS_ERROR_ABORT);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NeedSpdyTunnel()) {
|
if (NeedSpdyTunnel()) {
|
||||||
|
@ -216,7 +301,6 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion)
|
||||||
mProxyConnectInProgress = false;
|
mProxyConnectInProgress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mSpdySession = ASpdySession::NewSpdySession(spdyVersion, mSocketTransport);
|
|
||||||
bool spdyProxy = mConnInfo->UsingHttpsProxy() && !mTLSFilter;
|
bool spdyProxy = mConnInfo->UsingHttpsProxy() && !mTLSFilter;
|
||||||
if (spdyProxy) {
|
if (spdyProxy) {
|
||||||
RefPtr<nsHttpConnectionInfo> wildCardProxyCi;
|
RefPtr<nsHttpConnectionInfo> wildCardProxyCi;
|
||||||
|
@ -226,35 +310,11 @@ nsHttpConnection::StartSpdy(uint8_t spdyVersion)
|
||||||
mConnInfo = wildCardProxyCi;
|
mConnInfo = wildCardProxyCi;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NS_FAILED(rv)) { // includes NS_ERROR_NOT_IMPLEMENTED
|
if (!mDid0RTTSpdy) {
|
||||||
MOZ_ASSERT(list.IsEmpty(), "sub transaction list not empty");
|
rv = MoveTransactionsToSpdy(rv, list);
|
||||||
|
|
||||||
// This is ok - treat mTransaction as a single real request.
|
|
||||||
// Wrap the old http transaction into the new spdy session
|
|
||||||
// as the first stream.
|
|
||||||
LOG(("nsHttpConnection::StartSpdy moves single transaction %p "
|
|
||||||
"into SpdySession %p\n", mTransaction.get(), mSpdySession.get()));
|
|
||||||
rv = AddTransaction(mTransaction, mPriority);
|
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
int32_t count = list.Length();
|
|
||||||
|
|
||||||
LOG(("nsHttpConnection::StartSpdy moving transaction list len=%d "
|
|
||||||
"into SpdySession %p\n", count, mSpdySession.get()));
|
|
||||||
|
|
||||||
if (!count) {
|
|
||||||
mTransaction->Close(NS_ERROR_ABORT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int32_t index = 0; index < count; ++index) {
|
|
||||||
rv = AddTransaction(list[index], mPriority);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable TCP Keepalives - use SPDY ping instead.
|
// Disable TCP Keepalives - use SPDY ping instead.
|
||||||
|
@ -324,8 +384,7 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
|
||||||
// (AlpnEarlySelection), we are using HTTP/1, and the request data can
|
// (AlpnEarlySelection), we are using HTTP/1, and the request data can
|
||||||
// be safely retried.
|
// be safely retried.
|
||||||
m0RTTChecked = true;
|
m0RTTChecked = true;
|
||||||
nsAutoCString earlyNegotiatedNPN;
|
nsresult rvEarlyAlpn = ssl->GetAlpnEarlySelection(mEarlyNegotiatedALPN);
|
||||||
nsresult rvEarlyAlpn = ssl->GetAlpnEarlySelection(earlyNegotiatedNPN);
|
|
||||||
if (NS_FAILED(rvEarlyAlpn)) {
|
if (NS_FAILED(rvEarlyAlpn)) {
|
||||||
// if ssl->DriveHandshake() has never been called the value
|
// if ssl->DriveHandshake() has never been called the value
|
||||||
// for AlpnEarlySelection is still not set. So call it here and
|
// for AlpnEarlySelection is still not set. So call it here and
|
||||||
|
@ -342,7 +401,7 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
|
||||||
// Check NegotiatedNPN first.
|
// Check NegotiatedNPN first.
|
||||||
rv = ssl->GetNegotiatedNPN(negotiatedNPN);
|
rv = ssl->GetNegotiatedNPN(negotiatedNPN);
|
||||||
if (rv == NS_ERROR_NOT_CONNECTED) {
|
if (rv == NS_ERROR_NOT_CONNECTED) {
|
||||||
rvEarlyAlpn = ssl->GetAlpnEarlySelection(earlyNegotiatedNPN);
|
rvEarlyAlpn = ssl->GetAlpnEarlySelection(mEarlyNegotiatedALPN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,17 +410,24 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
|
||||||
"early selected alpn not available", this));
|
"early selected alpn not available", this));
|
||||||
} else {
|
} else {
|
||||||
LOG(("nsHttpConnection::EnsureNPNComplete %p -"
|
LOG(("nsHttpConnection::EnsureNPNComplete %p -"
|
||||||
"early selected alpn: %s", this, earlyNegotiatedNPN.get()));
|
"early selected alpn: %s", this, mEarlyNegotiatedALPN.get()));
|
||||||
uint32_t infoIndex;
|
uint32_t infoIndex;
|
||||||
const SpdyInformation *info = gHttpHandler->SpdyInfo();
|
const SpdyInformation *info = gHttpHandler->SpdyInfo();
|
||||||
// We are doing 0RTT only with Http/1 right now!
|
if (NS_FAILED(info->GetNPNIndex(mEarlyNegotiatedALPN, &infoIndex))) {
|
||||||
if (NS_FAILED(info->GetNPNIndex(earlyNegotiatedNPN, &infoIndex))) {
|
// This is the HTTP/1 case.
|
||||||
// Check if early-data is allowed for this transaction.
|
// Check if early-data is allowed for this transaction.
|
||||||
if (mTransaction->Do0RTT()) {
|
if (mTransaction->Do0RTT()) {
|
||||||
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - We "
|
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - We "
|
||||||
"can do 0RTT!", this));
|
"can do 0RTT (http/1)!", this));
|
||||||
mWaitingFor0RTTResponse = true;
|
mWaitingFor0RTTResponse = true;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// We have h2, we can at least 0-RTT the preamble and opening
|
||||||
|
// SETTINGS, etc, and maybe some of the first request
|
||||||
|
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - Starting "
|
||||||
|
"0RTT for h2!", this));
|
||||||
|
mWaitingFor0RTTResponse = true;
|
||||||
|
Start0RTTSpdy(info->Version[infoIndex]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -392,49 +458,71 @@ nsHttpConnection::EnsureNPNComplete(nsresult &aOut0RTTWriteHandshakeValue,
|
||||||
this, mConnInfo->HashKey().get(), negotiatedNPN.get(),
|
this, mConnInfo->HashKey().get(), negotiatedNPN.get(),
|
||||||
mTLSFilter ? " [Double Tunnel]" : ""));
|
mTLSFilter ? " [Double Tunnel]" : ""));
|
||||||
|
|
||||||
bool ealyDataAccepted = false;
|
bool earlyDataAccepted = false;
|
||||||
if (mWaitingFor0RTTResponse) {
|
if (mWaitingFor0RTTResponse) {
|
||||||
mWaitingFor0RTTResponse = false;
|
mWaitingFor0RTTResponse = false;
|
||||||
// Check if early data has been accepted.
|
// Check if early data has been accepted.
|
||||||
rv = ssl->GetEarlyDataAccepted(&ealyDataAccepted);
|
rv = ssl->GetEarlyDataAccepted(&earlyDataAccepted);
|
||||||
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - early data "
|
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - early data "
|
||||||
"that was sent during 0RTT %s been accepted.",
|
"that was sent during 0RTT %s been accepted [rv=%" PRIx32 "].",
|
||||||
this, ealyDataAccepted ? "has" : "has not"));
|
this, earlyDataAccepted ? "has" : "has not", static_cast<uint32_t>(rv)));
|
||||||
if (NS_FAILED(rv) ||
|
if (NS_FAILED(rv) ||
|
||||||
NS_FAILED(mTransaction->Finish0RTT(!ealyDataAccepted))) {
|
NS_FAILED(mTransaction->Finish0RTT(!earlyDataAccepted, negotiatedNPN != mEarlyNegotiatedALPN))) {
|
||||||
|
LOG(("nsHttpConection::EnsureNPNComplete [this=%p] closing transaction %p", this, mTransaction.get()));
|
||||||
mTransaction->Close(NS_ERROR_NET_RESET);
|
mTransaction->Close(NS_ERROR_NET_RESET);
|
||||||
goto npnComplete;
|
goto npnComplete;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ealyDataAccepted) {
|
if (!earlyDataAccepted) {
|
||||||
uint32_t infoIndex;
|
uint32_t infoIndex;
|
||||||
|
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] early data not accepted", this));
|
||||||
const SpdyInformation *info = gHttpHandler->SpdyInfo();
|
const SpdyInformation *info = gHttpHandler->SpdyInfo();
|
||||||
if (NS_SUCCEEDED(info->GetNPNIndex(negotiatedNPN, &infoIndex))) {
|
if (NS_SUCCEEDED(info->GetNPNIndex(negotiatedNPN, &infoIndex))) {
|
||||||
StartSpdy(info->Version[infoIndex]);
|
StartSpdy(info->Version[infoIndex]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - %d bytes "
|
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - %" PRId64 " bytes "
|
||||||
"has been sent during 0RTT.", this, mContentBytesWritten0RTT));
|
"has been sent during 0RTT.", this, mContentBytesWritten0RTT));
|
||||||
mContentBytesWritten = mContentBytesWritten0RTT;
|
mContentBytesWritten = mContentBytesWritten0RTT;
|
||||||
|
if (mSpdySession) {
|
||||||
|
// We had already started 0RTT-spdy, now we need to fully set up
|
||||||
|
// spdy, since we know we're sticking with it.
|
||||||
|
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] - finishing "
|
||||||
|
"StartSpdy for 0rtt spdy session %p", this, mSpdySession.get()));
|
||||||
|
StartSpdy(mSpdySession->SpdyVersion());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Telemetry::Accumulate(Telemetry::SPDY_NPN_CONNECT, UsingSpdy());
|
//Telemetry::Accumulate(Telemetry::SPDY_NPN_CONNECT, UsingSpdy());
|
||||||
}
|
}
|
||||||
|
|
||||||
npnComplete:
|
npnComplete:
|
||||||
LOG(("nsHttpConnection::EnsureNPNComplete setting complete to true"));
|
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] setting complete to true", this));
|
||||||
mNPNComplete = true;
|
mNPNComplete = true;
|
||||||
|
|
||||||
mTransaction->OnTransportStatus(mSocketTransport,
|
mTransaction->OnTransportStatus(mSocketTransport,
|
||||||
NS_NET_STATUS_TLS_HANDSHAKE_ENDED,
|
NS_NET_STATUS_TLS_HANDSHAKE_ENDED,
|
||||||
0);
|
0);
|
||||||
if (mWaitingFor0RTTResponse) {
|
if (mWaitingFor0RTTResponse) {
|
||||||
|
// Didn't get 0RTT OK, back out of the "attempting 0RTT" state
|
||||||
mWaitingFor0RTTResponse = false;
|
mWaitingFor0RTTResponse = false;
|
||||||
if (NS_FAILED(mTransaction->Finish0RTT(true))) {
|
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] 0rtt failed", this));
|
||||||
|
if (NS_FAILED(mTransaction->Finish0RTT(true, negotiatedNPN != mEarlyNegotiatedALPN))) {
|
||||||
mTransaction->Close(NS_ERROR_NET_RESET);
|
mTransaction->Close(NS_ERROR_NET_RESET);
|
||||||
}
|
}
|
||||||
mContentBytesWritten0RTT = 0;
|
mContentBytesWritten0RTT = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mDid0RTTSpdy && negotiatedNPN != mEarlyNegotiatedALPN) {
|
||||||
|
// Reset the work done by Start0RTTSpdy
|
||||||
|
LOG(("nsHttpConnection::EnsureNPNComplete [this=%p] resetting Start0RTTSpdy", this));
|
||||||
|
mUsingSpdyVersion = 0;
|
||||||
|
mTransaction = nullptr;
|
||||||
|
mSpdySession = nullptr;
|
||||||
|
// We have to reset this here, just in case we end up starting spdy again,
|
||||||
|
// so it can actually do everything it needs to do.
|
||||||
|
mDid0RTTSpdy = false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -247,6 +247,13 @@ private:
|
||||||
|
|
||||||
// Start the Spdy transaction handler when NPN indicates spdy/*
|
// Start the Spdy transaction handler when NPN indicates spdy/*
|
||||||
void StartSpdy(uint8_t versionLevel);
|
void StartSpdy(uint8_t versionLevel);
|
||||||
|
// Like the above, but do the bare minimum to do 0RTT data, so we can back
|
||||||
|
// it out, if necessary
|
||||||
|
void Start0RTTSpdy(uint8_t versionLevel);
|
||||||
|
|
||||||
|
// Helpers for Start*Spdy
|
||||||
|
nsresult TryTakeSubTransactions(nsTArray<RefPtr<nsAHttpTransaction> > &list);
|
||||||
|
nsresult MoveTransactionsToSpdy(nsresult status, nsTArray<RefPtr<nsAHttpTransaction> > &list);
|
||||||
|
|
||||||
// Directly Add a transaction to an active connection for SPDY
|
// Directly Add a transaction to an active connection for SPDY
|
||||||
nsresult AddTransaction(nsAHttpTransaction *, int32_t);
|
nsresult AddTransaction(nsAHttpTransaction *, int32_t);
|
||||||
|
@ -361,6 +368,8 @@ private:
|
||||||
// for the end of
|
// for the end of
|
||||||
// the handsake.
|
// the handsake.
|
||||||
int64_t mContentBytesWritten0RTT;
|
int64_t mContentBytesWritten0RTT;
|
||||||
|
nsCString mEarlyNegotiatedALPN;
|
||||||
|
bool mDid0RTTSpdy;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// For ForceSend()
|
// For ForceSend()
|
||||||
|
|
|
@ -2368,7 +2368,7 @@ nsHttpTransaction::Do0RTT()
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsHttpTransaction::Finish0RTT(bool aRestart)
|
nsHttpTransaction::Finish0RTT(bool aRestart, bool aAlpnChanged /* ignored */)
|
||||||
{
|
{
|
||||||
LOG(("nsHttpTransaction::Finish0RTT %p %d\n", this, aRestart));
|
LOG(("nsHttpTransaction::Finish0RTT %p %d\n", this, aRestart));
|
||||||
MOZ_ASSERT(m0RTTInProgress);
|
MOZ_ASSERT(m0RTTInProgress);
|
||||||
|
|
|
@ -167,7 +167,7 @@ public:
|
||||||
int64_t GetTransferSize() { return mTransferSize; }
|
int64_t GetTransferSize() { return mTransferSize; }
|
||||||
|
|
||||||
bool Do0RTT() override;
|
bool Do0RTT() override;
|
||||||
nsresult Finish0RTT(bool aRestart) override;
|
nsresult Finish0RTT(bool aRestart, bool aAlpnChanged /* ignored */) override;
|
||||||
private:
|
private:
|
||||||
friend class DeleteHttpTransaction;
|
friend class DeleteHttpTransaction;
|
||||||
virtual ~nsHttpTransaction();
|
virtual ~nsHttpTransaction();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user