зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1581637
- Part 8 - Add Http3Session/Http3Stream. r=mayhemer
Differential Revision: https://phabricator.services.mozilla.com/D46652 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
e6722f5da2
Коммит
e7b8f84a64
|
@ -63,7 +63,7 @@ class ASpdySession : public nsAHttpTransaction {
|
||||||
// soft errors are errors that terminate a stream without terminating the
|
// soft errors are errors that terminate a stream without terminating the
|
||||||
// connection. In general non-network errors are stream errors as well
|
// connection. In general non-network errors are stream errors as well
|
||||||
// as network specific items like cancels.
|
// as network specific items like cancels.
|
||||||
bool SoftStreamError(nsresult code) {
|
static bool SoftStreamError(nsresult code) {
|
||||||
if (NS_SUCCEEDED(code) || code == NS_BASE_STREAM_WOULD_BLOCK) {
|
if (NS_SUCCEEDED(code) || code == NS_BASE_STREAM_WOULD_BLOCK) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,175 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim:set ts=4 sw=2 et cindent: */
|
||||||
|
/* 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 Http3Session_H__
|
||||||
|
#define Http3Session_H__
|
||||||
|
|
||||||
|
#include "nsISupportsImpl.h"
|
||||||
|
#include "mozilla/net/NeqoHttp3Conn.h"
|
||||||
|
#include "nsAHttpConnection.h"
|
||||||
|
#include "nsRefPtrHashtable.h"
|
||||||
|
#include "nsWeakReference.h"
|
||||||
|
#include "HttpTrafficAnalyzer.h"
|
||||||
|
#include "mozilla/UniquePtr.h"
|
||||||
|
#include "nsDeque.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace net {
|
||||||
|
|
||||||
|
class Http3Stream;
|
||||||
|
class QuicSocketControl;
|
||||||
|
|
||||||
|
// IID for the Http3Session interface
|
||||||
|
#define NS_HTTP3SESSION_IID \
|
||||||
|
{ \
|
||||||
|
0x8fc82aaf, 0xc4ef, 0x46ed, { \
|
||||||
|
0x89, 0x41, 0x93, 0x95, 0x8f, 0xac, 0x4f, 0x21 \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
class Http3Session final : public nsAHttpTransaction,
|
||||||
|
public nsAHttpConnection,
|
||||||
|
public nsAHttpSegmentReader,
|
||||||
|
public nsAHttpSegmentWriter,
|
||||||
|
public nsITimerCallback {
|
||||||
|
public:
|
||||||
|
NS_DECLARE_STATIC_IID_ACCESSOR(NS_HTTP3SESSION_IID)
|
||||||
|
|
||||||
|
NS_DECL_ISUPPORTS
|
||||||
|
NS_DECL_NSAHTTPTRANSACTION
|
||||||
|
NS_DECL_NSAHTTPCONNECTION(mConnection)
|
||||||
|
NS_DECL_NSAHTTPSEGMENTREADER
|
||||||
|
NS_DECL_NSAHTTPSEGMENTWRITER
|
||||||
|
NS_DECL_NSITIMERCALLBACK
|
||||||
|
|
||||||
|
Http3Session();
|
||||||
|
nsresult Init(const nsACString& aOrigin, nsISocketTransport* aSocketTransport,
|
||||||
|
nsHttpConnection* readerWriter);
|
||||||
|
|
||||||
|
bool IsConnected() const { return mState == CONNECTED; }
|
||||||
|
bool IsClosing() const { return (mState == CLOSING || mState == CLOSED); }
|
||||||
|
nsresult GetError() const { return mError; }
|
||||||
|
|
||||||
|
nsresult Process();
|
||||||
|
|
||||||
|
bool AddStream(nsAHttpTransaction* aHttpTransaction, int32_t aPriority,
|
||||||
|
nsIInterfaceRequestor* aCallbacks);
|
||||||
|
|
||||||
|
bool CanReuse();
|
||||||
|
|
||||||
|
// TODO: use this.
|
||||||
|
bool RoomForMoreStreams() { return mQueuedStreams.GetSize() == 0; }
|
||||||
|
|
||||||
|
// We will let neqo-transport handle connection timeouts.
|
||||||
|
uint32_t ReadTimeoutTick(PRIntervalTime now) { return UINT32_MAX; }
|
||||||
|
|
||||||
|
// overload of nsAHttpTransaction
|
||||||
|
MOZ_MUST_USE nsresult ReadSegmentsAgain(nsAHttpSegmentReader*, uint32_t,
|
||||||
|
uint32_t*, bool*) final;
|
||||||
|
MOZ_MUST_USE nsresult WriteSegmentsAgain(nsAHttpSegmentWriter*, uint32_t,
|
||||||
|
uint32_t*, bool*) final;
|
||||||
|
|
||||||
|
bool ResponseTimeoutEnabled() const final { return true; }
|
||||||
|
PRIntervalTime ResponseTimeout() final;
|
||||||
|
|
||||||
|
// The folowing functions are used by Http3Stream:
|
||||||
|
nsresult TryActivating(const nsACString& aMethod, const nsACString& aScheme,
|
||||||
|
const nsACString& aHost, const nsACString& aPath,
|
||||||
|
const nsACString& aHeaders, uint64_t* aStreamId,
|
||||||
|
Http3Stream* aStream);
|
||||||
|
void CloseSendingSide(uint64_t aStreamId);
|
||||||
|
nsresult SendRequestBody(uint64_t aStreamId, const char* buf, uint32_t count,
|
||||||
|
uint32_t* countRead);
|
||||||
|
nsresult ReadResponseHeaders(uint64_t aStreamId,
|
||||||
|
nsTArray<uint8_t>& aResponseHeaders, bool* aFin);
|
||||||
|
nsresult ReadResponseData(uint64_t aStreamId, char* aBuf, uint32_t aCount,
|
||||||
|
uint32_t* aCountWritten, bool* aFin);
|
||||||
|
|
||||||
|
const static uint32_t kDefaultReadAmount = 2048;
|
||||||
|
|
||||||
|
void CloseStream(Http3Stream* aStream, nsresult aResult);
|
||||||
|
|
||||||
|
void SetCleanShutdown(bool aCleanShutdown) {
|
||||||
|
mCleanShutdown = aCleanShutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRIntervalTime IdleTime();
|
||||||
|
|
||||||
|
bool TestJoinConnection(const nsACString& hostname, int32_t port);
|
||||||
|
bool JoinConnection(const nsACString& hostname, int32_t port);
|
||||||
|
|
||||||
|
void TransactionHasDataToWrite(nsAHttpTransaction* caller) override;
|
||||||
|
|
||||||
|
nsISocketTransport* SocketTransport() { return mSocketTransport; }
|
||||||
|
|
||||||
|
// This function will be called by QuicSocketControl when the certificate
|
||||||
|
// verification is done.
|
||||||
|
void Authenticated(int32_t aError);
|
||||||
|
|
||||||
|
private:
|
||||||
|
~Http3Session();
|
||||||
|
|
||||||
|
void CloseInternal(bool aCallNeqoClose);
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
bool RealJoinConnection(const nsACString& hostname, int32_t port,
|
||||||
|
bool justKidding);
|
||||||
|
|
||||||
|
nsresult ProcessOutput();
|
||||||
|
nsresult ProcessInput();
|
||||||
|
nsresult ProcessEvents(uint32_t count, uint32_t* countWritten, bool* again);
|
||||||
|
nsresult ProcessOutputAndEvents();
|
||||||
|
|
||||||
|
void SetupTimer(uint64_t aTimeout);
|
||||||
|
|
||||||
|
void ResetRecvd(uint64_t aStreamId, Http3AppError aError);
|
||||||
|
|
||||||
|
void QueueStream(Http3Stream* stream);
|
||||||
|
void RemoveStreamFromQueues(Http3Stream*);
|
||||||
|
void ProcessPending();
|
||||||
|
|
||||||
|
void CallCertVerification();
|
||||||
|
void SetSecInfo();
|
||||||
|
|
||||||
|
RefPtr<NeqoHttp3Conn> mHttp3Connection;
|
||||||
|
RefPtr<nsAHttpConnection> mConnection;
|
||||||
|
nsRefPtrHashtable<nsUint64HashKey, Http3Stream> mStreamIdHash;
|
||||||
|
nsRefPtrHashtable<nsPtrHashKey<nsAHttpTransaction>, Http3Stream>
|
||||||
|
mStreamTransactionHash;
|
||||||
|
|
||||||
|
nsDeque mReadyForWrite;
|
||||||
|
nsDeque mQueuedStreams;
|
||||||
|
|
||||||
|
enum State { INITIALIZING, CONNECTED, CLOSING, CLOSED } mState;
|
||||||
|
|
||||||
|
bool mAuthenticationStarted;
|
||||||
|
bool mCleanShutdown;
|
||||||
|
bool mGoawayReceived;
|
||||||
|
bool mShouldClose;
|
||||||
|
nsresult mError;
|
||||||
|
bool mBeforeConnectedError;
|
||||||
|
uint64_t mCurrentForegroundTabOuterContentWindowId;
|
||||||
|
|
||||||
|
nsTArray<uint8_t> mPacketToSend;
|
||||||
|
|
||||||
|
RefPtr<nsHttpConnection> mSegmentReaderWriter;
|
||||||
|
|
||||||
|
// The underlying socket transport object is needed to propogate some events
|
||||||
|
RefPtr<nsISocketTransport> mSocketTransport;
|
||||||
|
|
||||||
|
nsCOMPtr<nsITimer> mTimer;
|
||||||
|
|
||||||
|
nsDataHashtable<nsCStringHashKey, bool> mJoinConnectionCache;
|
||||||
|
|
||||||
|
RefPtr<QuicSocketControl> mSocketControl;
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_DEFINE_STATIC_IID_ACCESSOR(Http3Session, NS_HTTP3SESSION_IID);
|
||||||
|
|
||||||
|
} // namespace net
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // Http3Session_H__
|
|
@ -0,0 +1,332 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
// HttpLog.h should generally be included first
|
||||||
|
#include "HttpLog.h"
|
||||||
|
#include "Http3Session.h"
|
||||||
|
#include "Http3Stream.h"
|
||||||
|
#include "nsHttpRequestHead.h"
|
||||||
|
#include "nsISocketTransport.h"
|
||||||
|
#include "nsSocketTransportService2.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace net {
|
||||||
|
|
||||||
|
Http3Stream::Http3Stream(nsAHttpTransaction* httpTransaction,
|
||||||
|
Http3Session* session)
|
||||||
|
: mState(PREPARING_HEADERS),
|
||||||
|
mStreamId(UINT64_MAX),
|
||||||
|
mSession(session),
|
||||||
|
mTransaction(httpTransaction),
|
||||||
|
mRequestHeadersDone(false),
|
||||||
|
mRequestStarted(false),
|
||||||
|
mQueued(false),
|
||||||
|
mRequestBlockedOnRead(false),
|
||||||
|
mDataReceived(false),
|
||||||
|
mRequestBodyLenRemaining(0),
|
||||||
|
mSocketTransport(session->SocketTransport()),
|
||||||
|
mTotalSent(0),
|
||||||
|
mTotalRead(0),
|
||||||
|
mFin(false) {
|
||||||
|
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||||
|
LOG3(("Http3Stream::Http3Stream [this=%p]", this));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Http3Stream::Close(nsresult aResult) { mTransaction->Close(aResult); }
|
||||||
|
|
||||||
|
void Http3Stream::GetHeadersString(const char* buf, uint32_t avail,
|
||||||
|
uint32_t* countUsed) {
|
||||||
|
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||||
|
LOG3(("Http3Stream::GetHeadersString %p avail=%u.", this, avail));
|
||||||
|
|
||||||
|
mFlatHttpRequestHeaders.Append(buf, avail);
|
||||||
|
// We can use the simple double crlf because firefox is the
|
||||||
|
// only client we are parsing
|
||||||
|
int32_t endHeader = mFlatHttpRequestHeaders.Find("\r\n\r\n");
|
||||||
|
|
||||||
|
if (endHeader == kNotFound) {
|
||||||
|
// We don't have all the headers yet
|
||||||
|
LOG3(
|
||||||
|
("Http3Stream::GetHeadersString %p "
|
||||||
|
"Need more header bytes. Len = %u",
|
||||||
|
this, mFlatHttpRequestHeaders.Length()));
|
||||||
|
*countUsed = avail;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t oldLen = mFlatHttpRequestHeaders.Length();
|
||||||
|
mFlatHttpRequestHeaders.SetLength(endHeader + 2);
|
||||||
|
*countUsed = avail - (oldLen - endHeader) + 4;
|
||||||
|
|
||||||
|
FindRequestContentLength();
|
||||||
|
mRequestHeadersDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Http3Stream::FindRequestContentLength() {
|
||||||
|
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||||
|
// Look for Content-Length header to find out if we have request body and
|
||||||
|
// how long it is.
|
||||||
|
int32_t contentLengthStart = mFlatHttpRequestHeaders.Find("Content-Length:");
|
||||||
|
if (contentLengthStart == -1) {
|
||||||
|
// There is no content-Length.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have Content-Length header, find the end of it.
|
||||||
|
int32_t crlfIndex = mFlatHttpRequestHeaders.Find("\r\n", false, contentLengthStart);
|
||||||
|
if (crlfIndex == -1) {
|
||||||
|
MOZ_ASSERT(false, "We must have \\r\\n at the end of the headers string.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the beginning.
|
||||||
|
int32_t valueIndex =
|
||||||
|
mFlatHttpRequestHeaders.Find(":", false, contentLengthStart) + 1;
|
||||||
|
if (valueIndex > crlfIndex) {
|
||||||
|
// Content-Length headers is empty.
|
||||||
|
MOZ_ASSERT(false, "Content-Length must have a value.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* beginBuffer = mFlatHttpRequestHeaders.BeginReading();
|
||||||
|
while (valueIndex < crlfIndex && beginBuffer[valueIndex] == ' ') {
|
||||||
|
++valueIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsDependentCSubstring value =
|
||||||
|
Substring(beginBuffer + valueIndex, beginBuffer + crlfIndex);
|
||||||
|
|
||||||
|
int64_t len;
|
||||||
|
nsCString tmp(value);
|
||||||
|
if (nsHttp::ParseInt64(tmp.get(), nullptr, &len)) {
|
||||||
|
mRequestBodyLenRemaining = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult Http3Stream::TryActivating() {
|
||||||
|
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||||
|
LOG(("Http3Stream::TryActivating [this=%p]", this));
|
||||||
|
nsHttpRequestHead* head = mTransaction->RequestHead();
|
||||||
|
|
||||||
|
nsAutoCString authorityHeader;
|
||||||
|
nsresult rv = head->GetHeader(nsHttp::Host, authorityHeader);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
MOZ_ASSERT(false);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsDependentCString scheme(head->IsHTTPS() ? "https" : "http");
|
||||||
|
|
||||||
|
nsAutoCString method;
|
||||||
|
nsAutoCString path;
|
||||||
|
head->Method(method);
|
||||||
|
head->Path(path);
|
||||||
|
|
||||||
|
rv = mSession->TryActivating(method, scheme, authorityHeader, path,
|
||||||
|
mFlatHttpRequestHeaders, &mStreamId, this);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
mRequestStarted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult Http3Stream::OnReadSegment(const char* buf, uint32_t count,
|
||||||
|
uint32_t* countRead) {
|
||||||
|
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||||
|
|
||||||
|
LOG(("Http3Stream::OnReadSegment count=%u state=%d [this=%p]", count, mState,
|
||||||
|
this));
|
||||||
|
|
||||||
|
switch (mState) {
|
||||||
|
case PREPARING_HEADERS:
|
||||||
|
GetHeadersString(buf, count, countRead);
|
||||||
|
|
||||||
|
if (*countRead) {
|
||||||
|
mTotalSent += *countRead;
|
||||||
|
mTransaction->OnTransportStatus(mSocketTransport,
|
||||||
|
NS_NET_STATUS_SENDING_TO, mTotalSent);
|
||||||
|
}
|
||||||
|
MOZ_ASSERT(!mRequestStarted, "We should be in one of the next states.");
|
||||||
|
if (mRequestHeadersDone && !mRequestStarted) {
|
||||||
|
nsresult rv = TryActivating();
|
||||||
|
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
|
||||||
|
LOG3(("Http3Stream::OnReadSegment %p cannot activate now. queued.\n",
|
||||||
|
this));
|
||||||
|
return *countRead ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK;
|
||||||
|
}
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
LOG3(("Http3Stream::OnReadSegment %p cannot activate error=0x%" PRIx32
|
||||||
|
".",
|
||||||
|
this, static_cast<uint32_t>(rv)));
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mRequestStarted) {
|
||||||
|
if (mRequestBodyLenRemaining) {
|
||||||
|
mState = SENDING_BODY;
|
||||||
|
} else {
|
||||||
|
mTransaction->OnTransportStatus(mSocketTransport,
|
||||||
|
NS_NET_STATUS_WAITING_FOR, 0);
|
||||||
|
mSession->CloseSendingSide(mStreamId);
|
||||||
|
mState = READING_HEADERS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SENDING_BODY: {
|
||||||
|
nsresult rv = mSession->SendRequestBody(mStreamId, buf, count, countRead);
|
||||||
|
MOZ_ASSERT(mRequestBodyLenRemaining >= *countRead,
|
||||||
|
"We cannot send more that than we promised.");
|
||||||
|
if (mRequestBodyLenRemaining < *countRead) {
|
||||||
|
rv = NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
LOG3(("Http3Stream::OnReadSegment %p sending body returns "
|
||||||
|
"error=0x%" PRIx32 ".", this, static_cast<uint32_t>(rv)));
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
mRequestBodyLenRemaining -= *countRead;
|
||||||
|
if (!mRequestBodyLenRemaining) {
|
||||||
|
mTransaction->OnTransportStatus(mSocketTransport,
|
||||||
|
NS_NET_STATUS_WAITING_FOR, 0);
|
||||||
|
mSession->CloseSendingSide(mStreamId);
|
||||||
|
mState = READING_HEADERS;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case EARLY_RESPONSE:
|
||||||
|
// We do not need to send the rest of the request, so just ignore it.
|
||||||
|
*countRead = count;
|
||||||
|
mRequestBodyLenRemaining -= count;
|
||||||
|
if (!mRequestBodyLenRemaining) {
|
||||||
|
mTransaction->OnTransportStatus(mSocketTransport,
|
||||||
|
NS_NET_STATUS_WAITING_FOR, 0);
|
||||||
|
mState = READING_HEADERS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MOZ_ASSERT(false, "We are done sending this request!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult Http3Stream::OnWriteSegment(char* buf, uint32_t count,
|
||||||
|
uint32_t* countWritten) {
|
||||||
|
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||||
|
|
||||||
|
LOG(("Http3Stream::OnWriteSegment [this=%p, state=%d", this, mState));
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
switch (mState) {
|
||||||
|
case PREPARING_HEADERS:
|
||||||
|
case SENDING_BODY:
|
||||||
|
case EARLY_RESPONSE:
|
||||||
|
break;
|
||||||
|
case READING_HEADERS: {
|
||||||
|
if (mFlatResponseHeaders.IsEmpty()) {
|
||||||
|
nsresult rv = mSession->ReadResponseHeaders(
|
||||||
|
mStreamId, mFlatResponseHeaders, &mFin);
|
||||||
|
if (NS_FAILED(rv) && (rv != NS_BASE_STREAM_WOULD_BLOCK)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
LOG(("Http3Stream::OnWriteSegment [this=%p, read %u bytes of headers",
|
||||||
|
this, (uint32_t)mFlatResponseHeaders.Length()));
|
||||||
|
}
|
||||||
|
*countWritten = (mFlatResponseHeaders.Length() > count)
|
||||||
|
? count
|
||||||
|
: mFlatResponseHeaders.Length();
|
||||||
|
memcpy(buf, mFlatResponseHeaders.Elements(), *countWritten);
|
||||||
|
|
||||||
|
mFlatResponseHeaders.RemoveElementsAt(0, *countWritten);
|
||||||
|
if (mFlatResponseHeaders.Length() == 0) {
|
||||||
|
mState = mFin ? RECEIVED_FIN : READING_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*countWritten == 0 ) {
|
||||||
|
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||||
|
} else {
|
||||||
|
mTotalRead += *countWritten;
|
||||||
|
mTransaction->OnTransportStatus(mSocketTransport,
|
||||||
|
NS_NET_STATUS_RECEIVING_FROM, mTotalRead);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case READING_DATA: {
|
||||||
|
rv = mSession->ReadResponseData(mStreamId, buf, count, countWritten,
|
||||||
|
&mFin);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
if (*countWritten == 0) {
|
||||||
|
if (mFin) {
|
||||||
|
mState = DONE;
|
||||||
|
rv = NS_BASE_STREAM_CLOSED;
|
||||||
|
} else {
|
||||||
|
rv = NS_BASE_STREAM_WOULD_BLOCK;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mTotalRead += *countWritten;
|
||||||
|
mTransaction->OnTransportStatus(
|
||||||
|
mSocketTransport, NS_NET_STATUS_RECEIVING_FROM, mTotalRead);
|
||||||
|
|
||||||
|
if (mFin) {
|
||||||
|
mState = RECEIVED_FIN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case RECEIVED_FIN:
|
||||||
|
case RECEIVED_RESET:
|
||||||
|
rv = NS_BASE_STREAM_CLOSED;
|
||||||
|
break;
|
||||||
|
case DONE:
|
||||||
|
rv = NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult Http3Stream::ReadSegments(nsAHttpSegmentReader* reader, uint32_t count,
|
||||||
|
uint32_t* countRead) {
|
||||||
|
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||||
|
|
||||||
|
mRequestBlockedOnRead = false;
|
||||||
|
|
||||||
|
nsresult rv = NS_OK;
|
||||||
|
switch (mState) {
|
||||||
|
case PREPARING_HEADERS:
|
||||||
|
case SENDING_BODY: {
|
||||||
|
rv = mTransaction->ReadSegments(this, count, countRead);
|
||||||
|
LOG(("Http3Stream::ReadSegments rv=0x%" PRIx32 " [this=%p]",
|
||||||
|
static_cast<uint32_t>(rv), this));
|
||||||
|
|
||||||
|
if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
|
||||||
|
mRequestBlockedOnRead = true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
*countRead = 0;
|
||||||
|
rv = NS_OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
LOG(("Http3Stream::ReadSegments rv=0x%" PRIx32 " [this=%p]",
|
||||||
|
static_cast<uint32_t>(rv), this));
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult Http3Stream::WriteSegments(nsAHttpSegmentWriter* writer,
|
||||||
|
uint32_t count, uint32_t* countWritten) {
|
||||||
|
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||||
|
LOG(("Http3Stream::WriteSegments [this=%p]", this));
|
||||||
|
nsresult rv = mTransaction->WriteSegments(this, count, countWritten);
|
||||||
|
LOG(("Http3Stream::WriteSegments rv=0x%" PRIx32 " [this=%p]",
|
||||||
|
static_cast<uint32_t>(rv), this));
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace net
|
||||||
|
} // namespace mozilla
|
|
@ -0,0 +1,153 @@
|
||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||||
|
/* 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 mozilla_net_Http3Stream_h
|
||||||
|
#define mozilla_net_Http3Stream_h
|
||||||
|
|
||||||
|
#include "nsAHttpTransaction.h"
|
||||||
|
#include "ARefBase.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace net {
|
||||||
|
|
||||||
|
class Http3Session;
|
||||||
|
|
||||||
|
class Http3Stream final : public nsAHttpSegmentReader,
|
||||||
|
public nsAHttpSegmentWriter,
|
||||||
|
public ARefBase {
|
||||||
|
public:
|
||||||
|
NS_DECL_NSAHTTPSEGMENTREADER
|
||||||
|
NS_DECL_NSAHTTPSEGMENTWRITER
|
||||||
|
// for RefPtr
|
||||||
|
NS_INLINE_DECL_REFCOUNTING(Http3Stream, override)
|
||||||
|
|
||||||
|
Http3Stream(nsAHttpTransaction* httpTransaction, Http3Session* session);
|
||||||
|
|
||||||
|
bool HasStreamId() const { return mStreamId != UINT64_MAX; }
|
||||||
|
uint64_t StreamId() const { return mStreamId; }
|
||||||
|
|
||||||
|
nsresult TryActivating();
|
||||||
|
|
||||||
|
// TODO priorities
|
||||||
|
void TopLevelOuterContentWindowIdChanged(uint64_t windowId){};
|
||||||
|
|
||||||
|
MOZ_MUST_USE nsresult ReadSegments(nsAHttpSegmentReader*, uint32_t,
|
||||||
|
uint32_t*);
|
||||||
|
MOZ_MUST_USE nsresult WriteSegments(nsAHttpSegmentWriter*, uint32_t,
|
||||||
|
uint32_t*);
|
||||||
|
|
||||||
|
bool RequestBlockedOnRead() const { return mRequestBlockedOnRead; }
|
||||||
|
|
||||||
|
void SetQueued(bool aStatus) { mQueued = aStatus; }
|
||||||
|
bool Queued() const { return mQueued; }
|
||||||
|
|
||||||
|
bool Done() const { return mState == DONE; }
|
||||||
|
|
||||||
|
void Close(nsresult aResult);
|
||||||
|
bool RecvdData() const { return mDataReceived; }
|
||||||
|
|
||||||
|
nsAHttpTransaction* Transaction() { return mTransaction; }
|
||||||
|
bool RecvdFin() const { return mState == RECEIVED_FIN; }
|
||||||
|
bool RecvdReset() const { return mState == RECEIVED_RESET; }
|
||||||
|
void SetRecvdReset() { mState = RECEIVED_RESET; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
~Http3Stream() = default;
|
||||||
|
|
||||||
|
void GetHeadersString(const char* buf, uint32_t avail, uint32_t* countUsed);
|
||||||
|
nsresult StartRequest();
|
||||||
|
void FindRequestContentLength();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StreamState:
|
||||||
|
* While sending request:
|
||||||
|
* - PREPARING_HEADERS:
|
||||||
|
* In this state we are collecting the headers and in some cases also
|
||||||
|
* waiting to be able to create a new stream.
|
||||||
|
* We need to read all headers into a buffer before calling
|
||||||
|
* Http3Session::TryActivating. Neqo may not have place for a new
|
||||||
|
* stream if it hits MAX_STREAMS limit. In that case the steam will be
|
||||||
|
* queued and dequeue when neqo can again create new stream
|
||||||
|
* (RequestsCreatable will be called).
|
||||||
|
* If transaction has data to send state changes to SENDING_BODY,
|
||||||
|
* otherwise the state transfers to READING_HEADERS.
|
||||||
|
* - SENDING_BODY:
|
||||||
|
* The stream will be in this state while the transaction is sending
|
||||||
|
* request body. Http3Session::SendRequestBody will be call to give
|
||||||
|
* the data to neqo.
|
||||||
|
* After SENDING_BODY, the state transfers to READING_HEADERS.
|
||||||
|
* - EARLY_RESPONSE:
|
||||||
|
* The server may send STOP_SENDING frame with error HTTP_EARLY_RESPONSE.
|
||||||
|
* That error means that the server is not interested in the request body.
|
||||||
|
* In this state the server will just ignore the request body.
|
||||||
|
* After sending a request, the transaction reads data:
|
||||||
|
* - READING_HEADERS:
|
||||||
|
* In this state Http3Session::ReadResponseHeaders will be called to read
|
||||||
|
* the response headers. All headers will be read at once into
|
||||||
|
* mFlatResponseHeaders. The stream will be in this state until all
|
||||||
|
* headers are given to the transaction.
|
||||||
|
* If the stream has been closed by the server after sending headers the
|
||||||
|
* stream will transit into RECEIVED_FIN state, otherwise it transits to
|
||||||
|
* READING_DATA state.
|
||||||
|
* - READING_DATA:
|
||||||
|
* In this state Http3Session::ReadResponseData will be called and the
|
||||||
|
* response body will be given to the transaction.
|
||||||
|
* This state may transfer to RECEIVED_FIN or DONE state.
|
||||||
|
* - RECEIVED_FIN:
|
||||||
|
* The stream is in this state when the receiving side is closed by the
|
||||||
|
* server and this information is not given to the transaction yet.
|
||||||
|
* (example 1: ReadResponseData(Http3Stream is in READING_DATA state)
|
||||||
|
* returns 10 bytes and fin set to true (the server has closed the
|
||||||
|
* stream). The transaction will get this 10 bytes, but it cannot get
|
||||||
|
* the information about the fin at the same time. The Http3Stream
|
||||||
|
* transit into RECEIVED_FIN state. The transaction will need to call
|
||||||
|
* OnWriteSegment again and the Http3Stream::OnWriteSegment will return
|
||||||
|
* NS_BASE_STREAM_CLOSED which means that the stream has been closed.
|
||||||
|
* example 2: if ReadResponseData(Http3Stream is in READING_DATA state)
|
||||||
|
* returns 0 bytes and a fin set to true. Http3Stream::OnWriteSegment
|
||||||
|
* will return NS_BASE_STREAM_CLOSED to the transaction and transfer to
|
||||||
|
* state DONE.)
|
||||||
|
* - RECEIVED_RESET:
|
||||||
|
* The stream has been reset by the server.
|
||||||
|
* - DONE:
|
||||||
|
* The transaction is done.
|
||||||
|
**/
|
||||||
|
enum StreamState {
|
||||||
|
PREPARING_HEADERS,
|
||||||
|
SENDING_BODY,
|
||||||
|
EARLY_RESPONSE,
|
||||||
|
READING_HEADERS,
|
||||||
|
READING_DATA,
|
||||||
|
RECEIVED_FIN,
|
||||||
|
RECEIVED_RESET,
|
||||||
|
DONE
|
||||||
|
} mState;
|
||||||
|
|
||||||
|
uint64_t mStreamId;
|
||||||
|
Http3Session* mSession;
|
||||||
|
RefPtr<nsAHttpTransaction> mTransaction;
|
||||||
|
nsCString mFlatHttpRequestHeaders;
|
||||||
|
bool mRequestHeadersDone;
|
||||||
|
bool mRequestStarted;
|
||||||
|
bool mQueued;
|
||||||
|
bool mRequestBlockedOnRead;
|
||||||
|
bool mDataReceived;
|
||||||
|
nsTArray<uint8_t> mFlatResponseHeaders;
|
||||||
|
uint32_t mRequestBodyLenRemaining;
|
||||||
|
|
||||||
|
// The underlying socket transport object is needed to propogate some events
|
||||||
|
RefPtr<nsISocketTransport> mSocketTransport;
|
||||||
|
|
||||||
|
// For Progress Events
|
||||||
|
uint64_t mTotalSent;
|
||||||
|
uint64_t mTotalRead;
|
||||||
|
|
||||||
|
bool mFin;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace net
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // mozilla_net_Http3Stream_h
|
|
@ -43,20 +43,17 @@ QuicSocketControl::GetSSLVersionOffered(int16_t* aSSLVersionOffered) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuicSocketControl::CallAuthenticated() {
|
void QuicSocketControl::CallAuthenticated() {
|
||||||
// // Will be added when Http3 lands
|
if (mHttp3Session) {
|
||||||
/* if (mHttp3Session) {
|
|
||||||
RefPtr<Http3Session> http3Session = do_QueryReferent(mHttp3Session);
|
RefPtr<Http3Session> http3Session = do_QueryReferent(mHttp3Session);
|
||||||
http3Session->Authenticated(GetErrorCode());
|
http3Session->Authenticated(GetErrorCode());
|
||||||
}
|
}
|
||||||
mHttp3Session = nullptr;*/
|
mHttp3Session = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will be added when Http3 lands
|
void QuicSocketControl::SetAuthenticationCallback(Http3Session* aHttp3Session) {
|
||||||
// void QuicSocketControl::SetAuthenticationCallback(Http3Session
|
mHttp3Session = do_GetWeakReference(
|
||||||
// *aHttp3Session) {
|
static_cast<nsISupportsWeakReference*>(aHttp3Session));
|
||||||
// mHttp3Session = do_GetWeakReference(
|
}
|
||||||
// static_cast<nsISupportsWeakReference*>(aHttp3Session));
|
|
||||||
//}
|
|
||||||
|
|
||||||
void QuicSocketControl::HandshakeCompleted() {
|
void QuicSocketControl::HandshakeCompleted() {
|
||||||
psm::RememberCertErrorsTable::GetInstance().LookupCertErrorBits(this);
|
psm::RememberCertErrorsTable::GetInstance().LookupCertErrorBits(this);
|
||||||
|
|
|
@ -12,8 +12,7 @@
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
namespace net {
|
namespace net {
|
||||||
|
|
||||||
// Will be added when Http3 lands.
|
class Http3Session;
|
||||||
// class Http3Session;
|
|
||||||
|
|
||||||
// IID for the QuicSocketControl interface
|
// IID for the QuicSocketControl interface
|
||||||
#define NS_QUICSOCKETCONTROL_IID \
|
#define NS_QUICSOCKETCONTROL_IID \
|
||||||
|
@ -37,8 +36,7 @@ class QuicSocketControl final : public CommonSocketControl {
|
||||||
void SetInfo(uint16_t aCipherSuite, uint16_t aProtocolVersion,
|
void SetInfo(uint16_t aCipherSuite, uint16_t aProtocolVersion,
|
||||||
uint16_t aKeaGroup, uint16_t aSignatureScheme);
|
uint16_t aKeaGroup, uint16_t aSignatureScheme);
|
||||||
|
|
||||||
// Will be added when Http3 lands.
|
void SetAuthenticationCallback(Http3Session* aHttp3Session);
|
||||||
// void SetAuthenticationCallback(Http3Session *aHttp3Session);
|
|
||||||
void CallAuthenticated();
|
void CallAuthenticated();
|
||||||
|
|
||||||
void HandshakeCompleted();
|
void HandshakeCompleted();
|
||||||
|
|
|
@ -77,6 +77,8 @@ UNIFIED_SOURCES += [
|
||||||
'Http2Push.cpp',
|
'Http2Push.cpp',
|
||||||
'Http2Session.cpp',
|
'Http2Session.cpp',
|
||||||
'Http2Stream.cpp',
|
'Http2Stream.cpp',
|
||||||
|
'Http3Session.cpp',
|
||||||
|
'Http3Stream.cpp',
|
||||||
'HttpAuthUtils.cpp',
|
'HttpAuthUtils.cpp',
|
||||||
'HttpBackgroundChannelChild.cpp',
|
'HttpBackgroundChannelChild.cpp',
|
||||||
'HttpBackgroundChannelParent.cpp',
|
'HttpBackgroundChannelParent.cpp',
|
||||||
|
@ -134,6 +136,7 @@ LOCAL_INCLUDES += [
|
||||||
'/netwerk/base',
|
'/netwerk/base',
|
||||||
'/netwerk/cookie',
|
'/netwerk/cookie',
|
||||||
'/netwerk/ipc',
|
'/netwerk/ipc',
|
||||||
|
'/netwerk/socket/neqo_glue',
|
||||||
'/netwerk/url-classifier',
|
'/netwerk/url-classifier',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -81,6 +81,7 @@ EXPORTS += [
|
||||||
'RootCertificateTelemetryUtils.h',
|
'RootCertificateTelemetryUtils.h',
|
||||||
'ScopedNSSTypes.h',
|
'ScopedNSSTypes.h',
|
||||||
'SharedCertVerifier.h',
|
'SharedCertVerifier.h',
|
||||||
|
'SSLServerCertVerification.h',
|
||||||
'TransportSecurityInfo.h',
|
'TransportSecurityInfo.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче