Commit db952581 authored by Kershaw Chang's avatar Kershaw Chang
Browse files

Bug 1740274 - Avoid accessing Http2Session through raw pointer, r=necko-reviewers,dragana, a=dsmith

parent 975bcd67
Loading
Loading
Loading
Loading
+11 −9
Original line number Diff line number Diff line
@@ -220,13 +220,14 @@ nsresult Http2PushedStream::ReadSegments(nsAHttpSegmentReader* reader, uint32_t,

  mozilla::OriginAttributes originAttributes;
  switch (mUpstreamState) {
    case GENERATING_HEADERS:
    case GENERATING_HEADERS: {
      // The request headers for this has been processed, so we need to verify
      // that :authority, :scheme, and :path MUST be present. :method MUST NOT
      // be present
      mSocketTransport->GetOriginAttributes(&originAttributes);
      RefPtr<Http2Session> session = Session();
      CreatePushHashKey(mHeaderScheme, mHeaderHost, originAttributes,
                        Session()->Serial(), mHeaderPath, mOrigin, mHashKey);
                        session->Serial(), mHeaderPath, mOrigin, mHashKey);

      LOG3(("Http2PushStream 0x%X hash key %s\n", mStreamID, mHashKey.get()));

@@ -236,7 +237,7 @@ nsresult Http2PushedStream::ReadSegments(nsAHttpSegmentReader* reader, uint32_t,
      Http2Stream::mRequestHeadersDone = 1;
      Http2Stream::mOpenGenerated = 1;
      Http2Stream::ChangeState(UPSTREAM_COMPLETE);
      break;
    } break;

    case UPSTREAM_COMPLETE:
      // Let's just clear the stream's transmit buffer by pushing it into
@@ -267,7 +268,8 @@ void Http2PushedStream::AdjustInitialWindow() {
    Http2Stream::AdjustInitialWindow();
    // Http2PushedStream::ReadSegments is needed to call TransmitFrame()
    // and actually get this information into the session bytestream
    Session()->TransactionHasDataToWrite(this);
    RefPtr<Http2Session> session = Session();
    session->TransactionHasDataToWrite(this);
  }
  // Otherwise, when we get hooked up, the initial window will get bumped
  // anyway, so we're good to go.
@@ -289,7 +291,8 @@ bool Http2PushedStream::GetHashKey(nsCString& key) {
}

void Http2PushedStream::ConnectPushedStream(Http2Stream* stream) {
  Session()->ConnectPushedStream(stream);
  RefPtr<Http2Session> session = Session();
  session->ConnectPushedStream(stream);
}

bool Http2PushedStream::IsOrphaned(TimeStamp now) {
@@ -338,8 +341,8 @@ void Http2PushedStream::TopBrowsingContextIdChanged(uint64_t id) {
  MOZ_ASSERT(gHttpHandler->ActiveTabPriority());

  mCurrentTopBrowsingContextId = id;

  if (!Session()->UseH2Deps()) {
  RefPtr<Http2Session> session = Session();
  if (!session->UseH2Deps()) {
    return;
  }

@@ -352,8 +355,7 @@ void Http2PushedStream::TopBrowsingContextIdChanged(uint64_t id) {
  }

  if (mPriorityDependency != oldDependency) {
    Session()->SendPriorityFrame(mStreamID, mPriorityDependency,
                                 mPriorityWeight);
    session->SendPriorityFrame(mStreamID, mPriorityDependency, mPriorityWeight);
  }
}

+69 −56
Original line number Diff line number Diff line
@@ -118,10 +118,10 @@ Http2Stream::~Http2Stream() {
  LOG3(("Http2Stream::~Http2Stream %p", this));
}

Http2Session* Http2Stream::Session() {
already_AddRefed<Http2Session> Http2Stream::Session() {
  RefPtr<Http2Session> session = do_QueryReferent(mSession);
  MOZ_RELEASE_ASSERT(session);
  return session.get();
  return session.forget();
}

void Http2Stream::ClearPushSource() {
@@ -140,8 +140,9 @@ nsresult Http2Stream::ReadSegments(nsAHttpSegmentReader* reader, uint32_t count,
                                   uint32_t* countRead) {
  LOG3(("Http2Stream %p ReadSegments reader=%p count=%d state=%x", this, reader,
        count, mUpstreamState));
  RefPtr<Http2Session> session = Session();
  // Reader is nullptr when this is a push stream.
  MOZ_DIAGNOSTIC_ASSERT(!reader || (reader == Session()));
  MOZ_DIAGNOSTIC_ASSERT(!reader || (reader == session));

  MOZ_ASSERT(OnSocketThread(), "not on socket thread");

@@ -182,7 +183,7 @@ nsresult Http2Stream::ReadSegments(nsAHttpSegmentReader* reader, uint32_t count,
      // If not, mark the stream for callback when writing can proceed.
      if (NS_SUCCEEDED(rv) && mUpstreamState == GENERATING_HEADERS &&
          !mRequestHeadersDone) {
        Session()->TransactionHasDataToWrite(this);
        session->TransactionHasDataToWrite(this);
      }

      // mTxinlineFrameUsed represents any queued un-sent frame. It might
@@ -239,7 +240,7 @@ nsresult Http2Stream::ReadSegments(nsAHttpSegmentReader* reader, uint32_t count,
        } else {
          GenerateDataFrameHeader(0, true);
          ChangeState(SENDING_FIN_STREAM);
          Session()->TransactionHasDataToWrite(this);
          session->TransactionHasDataToWrite(this);
          rv = NS_BASE_STREAM_WOULD_BLOCK;
        }
      }
@@ -422,6 +423,7 @@ nsresult Http2Stream::ParseHttpRequestHeaders(const char* buf, uint32_t avail,

  mFlatHttpRequestHeaders.Append(buf, avail);
  nsHttpRequestHead* head = mTransaction->RequestHead();
  RefPtr<Http2Session> session = Session();

  // We can use the simple double crlf because firefox is the
  // only client we are parsing
@@ -460,7 +462,7 @@ nsresult Http2Stream::ParseHttpRequestHeaders(const char* buf, uint32_t avail,
  mSocketTransport->GetOriginAttributes(&originAttributes);

  CreatePushHashKey(nsDependentCString(head->IsHTTPS() ? "https" : "http"),
                    authorityHeader, originAttributes, Session()->Serial(),
                    authorityHeader, originAttributes, session->Serial(),
                    requestURI, mOrigin, hashkey);

  // check the push cache for GET
@@ -481,14 +483,14 @@ nsresult Http2Stream::ParseHttpRequestHeaders(const char* buf, uint32_t avail,
    nsHttpTransaction* trans = mTransaction->QueryHttpTransaction();
    if (trans && (pushedStreamWrapper = trans->TakePushedStream()) &&
        (pushedStream = pushedStreamWrapper->GetStream())) {
      if (pushedStream->Session() == Session()) {
      RefPtr<Http2Session> pushSession = pushedStream->Session();
      if (pushSession == session) {
        LOG3(("Pushed Stream match based on OnPush correlation %p",
              pushedStream));
      } else {
        LOG3(("Pushed Stream match failed due to stream mismatch %p %" PRId64
              " %" PRId64 "\n",
              pushedStream, pushedStream->Session()->Serial(),
              Session()->Serial()));
              pushedStream, pushSession->Serial(), session->Serial()));
        pushedStream->OnPushFailed();
        pushedStream = nullptr;
      }
@@ -504,7 +506,7 @@ nsresult Http2Stream::ParseHttpRequestHeaders(const char* buf, uint32_t avail,
    LOG3(
        ("Pushed Stream Lookup "
         "session=%p key=%s requestcontext=%p cache=%p hit=%p\n",
         Session(), hashkey.get(), requestContext, cache, pushedStream));
         session.get(), hashkey.get(), requestContext, cache, pushedStream));

    if (pushedStream) {
      LOG3(("Pushed Stream Match located %p id=0x%X key=%s\n", pushedStream,
@@ -516,13 +518,13 @@ nsresult Http2Stream::ParseHttpRequestHeaders(const char* buf, uint32_t avail,

      // There is probably pushed data buffered so trigger a read manually
      // as we can't rely on future network events to do it
      Session()->ConnectPushedStream(this);
      session->ConnectPushedStream(this);
      mOpenGenerated = 1;

      // if the "mother stream" had TRR, this one is a TRR stream too!
      RefPtr<nsHttpConnectionInfo> ci(Transaction()->ConnectionInfo());
      if (ci && ci->GetIsTrrServiceChannel()) {
        Session()->IncrementTrrCounter();
        session->IncrementTrrCounter();
      }

      return NS_OK;
@@ -536,7 +538,8 @@ nsresult Http2Stream::GenerateOpen() {
  // It is now OK to assign a streamID that we are assured will
  // be monotonically increasing amongst new streams on this
  // session
  mStreamID = Session()->RegisterStreamID(this);
  RefPtr<Http2Session> session = Session();
  mStreamID = session->RegisterStreamID(this);
  MOZ_ASSERT(mStreamID & 1, "Http2 Stream Channel ID must be odd");
  MOZ_ASSERT(!mOpenGenerated);

@@ -546,7 +549,7 @@ nsresult Http2Stream::GenerateOpen() {
  nsAutoCString requestURI;
  head->RequestURI(requestURI);
  LOG3(("Http2Stream %p Stream ID 0x%X [session=%p] for URI %s\n", this,
        mStreamID, Session(), requestURI.get()));
        mStreamID, session.get(), requestURI.get()));

  if (mStreamID >= 0x80000000) {
    // streamID must fit in 31 bits. Evading This is theoretically possible
@@ -608,12 +611,12 @@ nsresult Http2Stream::GenerateOpen() {
    useSimpleConnect = false;
    protocol.AppendLiteral("websocket");
  }
  rv = Session()->Compressor()->EncodeHeaderBlock(
  rv = session->Compressor()->EncodeHeaderBlock(
      mFlatHttpRequestHeaders, method, path, authorityHeader, scheme, protocol,
      useSimpleConnect, compressedData);
  NS_ENSURE_SUCCESS(rv, rv);

  int64_t clVal = Session()->Compressor()->GetParsedContentLength();
  int64_t clVal = session->Compressor()->GetParsedContentLength();
  if (clVal != -1) {
    mRequestBodyLenRemaining = clVal;
  }
@@ -698,7 +701,7 @@ nsresult Http2Stream::GenerateOpen() {
    }
    dataLength -= frameLen;

    Session()->CreateFrameHeader(mTxInlineFrame.get() + outputOffset,
    session->CreateFrameHeader(mTxInlineFrame.get() + outputOffset,
                               frameLen + (idx ? 0 : 5),
                               (idx) ? Http2Session::FRAME_TYPE_CONTINUATION
                                     : Http2Session::FRAME_TYPE_HEADERS,
@@ -761,14 +764,15 @@ void Http2Stream::AdjustInitialWindow() {
  // bump it up to the pull limit set by the channel or session
  // don't allow windows less than push
  uint32_t bump = 0;
  RefPtr<Http2Session> session = Session();
  nsHttpTransaction* trans = mTransaction->QueryHttpTransaction();
  if (trans && trans->InitialRwin()) {
    bump = (trans->InitialRwin() > mClientReceiveWindow)
               ? (trans->InitialRwin() - mClientReceiveWindow)
               : 0;
  } else {
    MOZ_ASSERT(Session()->InitialRwin() >= mClientReceiveWindow);
    bump = Session()->InitialRwin() - mClientReceiveWindow;
    MOZ_ASSERT(session->InitialRwin() >= mClientReceiveWindow);
    bump = session->InitialRwin() - mClientReceiveWindow;
  }

  LOG3(("AdjustInitialwindow increased flow control window %p 0x%X %u\n", this,
@@ -783,8 +787,8 @@ void Http2Stream::AdjustInitialWindow() {
  uint8_t* packet = mTxInlineFrame.get() + mTxInlineFrameUsed;
  mTxInlineFrameUsed += Http2Session::kFrameHeaderBytes + 4;

  Session()->CreateFrameHeader(
      packet, 4, Http2Session::FRAME_TYPE_WINDOW_UPDATE, 0, stream->mStreamID);
  session->CreateFrameHeader(packet, 4, Http2Session::FRAME_TYPE_WINDOW_UPDATE,
                             0, stream->mStreamID);

  mClientReceiveWindow += bump;
  bump = PR_htonl(bump);
@@ -812,7 +816,8 @@ void Http2Stream::AdjustPushedPriority() {
  uint8_t* packet = mTxInlineFrame.get() + mTxInlineFrameUsed;
  mTxInlineFrameUsed += Http2Session::kFrameHeaderBytes + 5;

  Session()->CreateFrameHeader(packet, 5, Http2Session::FRAME_TYPE_PRIORITY, 0,
  RefPtr<Http2Session> session = Session();
  session->CreateFrameHeader(packet, 5, Http2Session::FRAME_TYPE_PRIORITY, 0,
                             mPushSource->mStreamID);

  mPushSource->SetPriorityDependency(mPriority, mPriorityDependency);
@@ -892,6 +897,7 @@ nsresult Http2Stream::TransmitFrame(const char* buf, uint32_t* countUsed,

  uint32_t transmittedCount;
  nsresult rv;
  RefPtr<Http2Session> session = Session();

  // In the (relatively common) event that we have a small amount of data
  // split between the inlineframe and the streamframe, then move the stream
@@ -912,7 +918,7 @@ nsresult Http2Stream::TransmitFrame(const char* buf, uint32_t* countUsed,

  if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
    MOZ_ASSERT(!forceCommitment, "forceCommitment with WOULD_BLOCK");
    Session()->TransactionHasDataToWrite(this);
    session->TransactionHasDataToWrite(this);
  }
  if (NS_FAILED(rv)) {  // this will include WOULD_BLOCK
    return rv;
@@ -923,12 +929,12 @@ nsresult Http2Stream::TransmitFrame(const char* buf, uint32_t* countUsed,
  // which calls the socket write function. It will accept all of the inline and
  // stream data because of the above 'commitment' even if it has to buffer

  rv = Session()->BufferOutput(reinterpret_cast<char*>(mTxInlineFrame.get()),
  rv = session->BufferOutput(reinterpret_cast<char*>(mTxInlineFrame.get()),
                             mTxInlineFrameUsed, &transmittedCount);
  LOG3(
      ("Http2Stream::TransmitFrame for inline BufferOutput session=%p "
       "stream=%p result %" PRIx32 " len=%d",
       Session(), this, static_cast<uint32_t>(rv), transmittedCount));
       session.get(), this, static_cast<uint32_t>(rv), transmittedCount));

  MOZ_ASSERT(rv != NS_BASE_STREAM_WOULD_BLOCK,
             "inconsistent inline commitment result");
@@ -938,7 +944,7 @@ nsresult Http2Stream::TransmitFrame(const char* buf, uint32_t* countUsed,
  MOZ_ASSERT(transmittedCount == mTxInlineFrameUsed,
             "inconsistent inline commitment count");

  Http2Session::LogIO(Session(), this, "Writing from Inline Buffer",
  Http2Session::LogIO(session, this, "Writing from Inline Buffer",
                      reinterpret_cast<char*>(mTxInlineFrame.get()),
                      transmittedCount);

@@ -954,16 +960,16 @@ nsresult Http2Stream::TransmitFrame(const char* buf, uint32_t* countUsed,

    // If there is already data buffered, just add to that to form
    // a single TLS Application Data Record - otherwise skip the memcpy
    if (Session()->AmountOfOutputBuffered()) {
      rv = Session()->BufferOutput(buf, mTxStreamFrameSize, &transmittedCount);
    if (session->AmountOfOutputBuffered()) {
      rv = session->BufferOutput(buf, mTxStreamFrameSize, &transmittedCount);
    } else {
      rv = Session()->OnReadSegment(buf, mTxStreamFrameSize, &transmittedCount);
      rv = session->OnReadSegment(buf, mTxStreamFrameSize, &transmittedCount);
    }

    LOG3(
        ("Http2Stream::TransmitFrame for regular session=%p "
         "stream=%p result %" PRIx32 " len=%d",
         Session(), this, static_cast<uint32_t>(rv), transmittedCount));
         session.get(), this, static_cast<uint32_t>(rv), transmittedCount));

    MOZ_ASSERT(rv != NS_BASE_STREAM_WOULD_BLOCK,
               "inconsistent stream commitment result");
@@ -973,14 +979,14 @@ nsresult Http2Stream::TransmitFrame(const char* buf, uint32_t* countUsed,
    MOZ_ASSERT(transmittedCount == mTxStreamFrameSize,
               "inconsistent stream commitment count");

    Http2Session::LogIO(Session(), this, "Writing from Transaction Buffer", buf,
    Http2Session::LogIO(session, this, "Writing from Transaction Buffer", buf,
                        transmittedCount);

    *countUsed += mTxStreamFrameSize;
  }

  if (!mAttempting0RTT) {
    Session()->FlushOutputQueue();
    session->FlushOutputQueue();
  }

  // calling this will trigger waiting_for if mRequestBodyLenRemaining is 0
@@ -1012,7 +1018,8 @@ void Http2Stream::GenerateDataFrameHeader(uint32_t dataLength, bool lastFrame) {
    if (dataLength) SetSentFin(true);
  }

  Session()->CreateFrameHeader(mTxInlineFrame.get(), dataLength,
  RefPtr<Http2Session> session = Session();
  session->CreateFrameHeader(mTxInlineFrame.get(), dataLength,
                             Http2Session::FRAME_TYPE_DATA, frameFlags,
                             mStreamID);

@@ -1079,7 +1086,8 @@ nsresult Http2Stream::ConvertResponseHeaders(Http2Decompressor* decompressor,

  if (httpResponseCode == 421) {
    // Origin Frame requires 421 to remove this origin from the origin set
    Session()->Received421(mTransaction->ConnectionInfo());
    RefPtr<Http2Session> session = Session();
    session->Received421(mTransaction->ConnectionInfo());
  }

  if (aHeadersIn.Length() && aHeadersOut.Length()) {
@@ -1202,7 +1210,8 @@ void Http2Stream::SetAllHeadersReceived() {
}

bool Http2Stream::AllowFlowControlledWrite() {
  return (Session()->ServerSessionWindow() > 0) && (mServerReceiveWindow > 0);
  RefPtr<Http2Session> session = Session();
  return (session->ServerSessionWindow() > 0) && (mServerReceiveWindow > 0);
}

void Http2Stream::UpdateServerReceiveWindow(int32_t delta) {
@@ -1213,7 +1222,8 @@ void Http2Stream::UpdateServerReceiveWindow(int32_t delta) {
        ("Http2Stream::UpdateServerReceived UnPause %p 0x%X "
         "Open stream window\n",
         this, mStreamID));
    Session()->TransactionHasDataToWrite(this);
    RefPtr<Http2Session> session = Session();
    session->TransactionHasDataToWrite(this);
  }
}

@@ -1270,7 +1280,8 @@ static uint32_t GetPriorityDependencyFromTransaction(nsHttpTransaction* trans) {
}

void Http2Stream::UpdatePriorityDependency() {
  if (!Session()->UseH2Deps()) {
  RefPtr<Http2Session> session = Session();
  if (!session->UseH2Deps()) {
    return;
  }

@@ -1328,7 +1339,7 @@ void Http2Stream::TopBrowsingContextIdChanged(uint64_t id) {

void Http2Stream::TopBrowsingContextIdChangedInternal(uint64_t id) {
  MOZ_ASSERT(gHttpHandler->ActiveTabPriority());

  RefPtr<Http2Session> session = Session();
  LOG3(
      ("Http2Stream::TopBrowsingContextIdChangedInternal "
       "%p bcId=%" PRIx64 "\n",
@@ -1336,7 +1347,7 @@ void Http2Stream::TopBrowsingContextIdChangedInternal(uint64_t id) {

  mCurrentTopBrowsingContextId = id;

  if (!Session()->UseH2Deps()) {
  if (!session->UseH2Deps()) {
    return;
  }

@@ -1372,7 +1383,7 @@ void Http2Stream::TopBrowsingContextIdChangedInternal(uint64_t id) {
    modifyStreamID = mPushSource->StreamID();
  }
  if (modifyStreamID) {
    Session()->SendPriorityFrame(modifyStreamID, mPriorityDependency,
    session->SendPriorityFrame(modifyStreamID, mPriorityDependency,
                               mPriorityWeight);
  }
}
@@ -1425,6 +1436,7 @@ nsresult Http2Stream::OnReadSegment(const char* buf, uint32_t count,

  nsresult rv = NS_ERROR_UNEXPECTED;
  uint32_t dataLength;
  RefPtr<Http2Session> session = Session();

  switch (mUpstreamState) {
    case GENERATING_HEADERS:
@@ -1442,7 +1454,7 @@ nsresult Http2Stream::OnReadSegment(const char* buf, uint32_t count,
      }

      if (mRequestHeadersDone && !mOpenGenerated) {
        if (!Session()->TryToActivate(this)) {
        if (!session->TryToActivate(this)) {
          LOG3(("Http2Stream::OnReadSegment %p cannot activate now. queued.\n",
                this));
          return *countRead ? NS_OK : NS_BASE_STREAM_WOULD_BLOCK;
@@ -1477,7 +1489,7 @@ nsresult Http2Stream::OnReadSegment(const char* buf, uint32_t count,
            ("Http2Stream this=%p, id 0x%X request body suspended because "
             "remote window is stream=%" PRId64 " session=%" PRId64 ".\n",
             this, mStreamID, mServerReceiveWindow,
             Session()->ServerSessionWindow()));
             session->ServerSessionWindow()));
        mBlockedOnRwin = true;
        return NS_BASE_STREAM_WOULD_BLOCK;
      }
@@ -1492,8 +1504,8 @@ nsresult Http2Stream::OnReadSegment(const char* buf, uint32_t count,
        dataLength = Http2Session::kMaxFrameData;
      }

      if (dataLength > Session()->ServerSessionWindow()) {
        dataLength = static_cast<uint32_t>(Session()->ServerSessionWindow());
      if (dataLength > session->ServerSessionWindow()) {
        dataLength = static_cast<uint32_t>(session->ServerSessionWindow());
      }

      if (dataLength > mServerReceiveWindow) {
@@ -1506,10 +1518,10 @@ nsresult Http2Stream::OnReadSegment(const char* buf, uint32_t count,
           " session window=%" PRId64 " "
           "max frame=%d USING=%u\n",
           this, mStreamID, count, mChunkSize, mServerReceiveWindow,
           Session()->ServerSessionWindow(), Http2Session::kMaxFrameData,
           session->ServerSessionWindow(), Http2Session::kMaxFrameData,
           dataLength));

      Session()->DecrementServerSessionWindow(dataLength);
      session->DecrementServerSessionWindow(dataLength);
      mServerReceiveWindow -= dataLength;

      LOG3(("Http2Stream %p id 0x%x request len remaining %" PRId64 ", "
@@ -1580,7 +1592,8 @@ nsresult Http2Stream::OnWriteSegment(char* buf, uint32_t count,
    rv = mPushSource->GetBufferedData(buf, count, countWritten);
    if (NS_FAILED(rv)) return rv;

    Session()->ConnectPushedStream(this);
    RefPtr<Http2Session> session = Session();
    session->ConnectPushedStream(this);
    return NS_OK;
  }

+1 −1
Original line number Diff line number Diff line
@@ -162,7 +162,7 @@ class Http2Stream : public nsAHttpSegmentReader,
  // This is a no-op on pull streams. Pushed streams override this.
  virtual void SetPushComplete(){};

  Http2Session* Session();
  already_AddRefed<Http2Session> Session();

  [[nodiscard]] static nsresult MakeOriginURL(const nsACString& origin,
                                              nsCOMPtr<nsIURI>& url);
+3 −3
Original line number Diff line number Diff line
@@ -1647,10 +1647,10 @@ nsresult nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction* trans) {
  if (pushedStreamWrapper) {
    Http2PushedStream* pushedStream = pushedStreamWrapper->GetStream();
    if (pushedStream) {
      RefPtr<Http2Session> session = pushedStream->Session();
      LOG(("  ProcessNewTransaction %p tied to h2 session push %p\n", trans,
           pushedStream->Session()));
      return pushedStream->Session()->AddStream(trans, trans->Priority(), false,
                                                false, nullptr)
           session.get()));
      return session->AddStream(trans, trans->Priority(), false, false, nullptr)
                 ? NS_OK
                 : NS_ERROR_UNEXPECTED;
    }