fune/netwerk/protocol/http/Http2Push.cpp
Ryan VanderMeulen db079aae32 Backed out 11 changesets (bug 378637) for Android crashes.
Backed out changeset 2a607cddc4cb (bug 378637)
Backed out changeset e416503aea99 (bug 378637)
Backed out changeset b2257226899f (bug 378637)
Backed out changeset dafd618c3f52 (bug 378637)
Backed out changeset dfde9d47d8c4 (bug 378637)
Backed out changeset cf9de5c367a5 (bug 378637)
Backed out changeset 62aa68e8b499 (bug 378637)
Backed out changeset 38efa8f2e56e (bug 378637)
Backed out changeset 2b5753e09a92 (bug 378637)
Backed out changeset 7a73873e133d (bug 378637)
Backed out changeset f58ce7ac1c7f (bug 378637)
2014-05-09 15:25:55 -04:00

344 lines
8.2 KiB
C++

/* -*- 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"
// Log on level :5, instead of default :4.
#undef LOG
#define LOG(args) LOG5(args)
#undef LOG_ENABLED
#define LOG_ENABLED() LOG5_ENABLED()
#include <algorithm>
#include "Http2Push.h"
#include "nsDependentString.h"
namespace mozilla {
namespace net {
//////////////////////////////////////////
// Http2PushedStream
//////////////////////////////////////////
Http2PushedStream::Http2PushedStream(Http2PushTransactionBuffer *aTransaction,
Http2Session *aSession,
Http2Stream *aAssociatedStream,
uint32_t aID)
:Http2Stream(aTransaction, aSession, 0)
, mConsumerStream(nullptr)
, mBufferedPush(aTransaction)
, mStatus(NS_OK)
, mPushCompleted(false)
, mDeferCleanupOnSuccess(true)
{
LOG3(("Http2PushedStream ctor this=%p 0x%X\n", this, aID));
mStreamID = aID;
MOZ_ASSERT(!(aID & 1)); // must be even to be a pushed stream
mBufferedPush->SetPushStream(this);
mLoadGroupCI = aAssociatedStream->LoadGroupConnectionInfo();
mLastRead = TimeStamp::Now();
SetPriority(aAssociatedStream->Priority() + 1);
}
bool
Http2PushedStream::GetPushComplete()
{
return mPushCompleted;
}
nsresult
Http2PushedStream::WriteSegments(nsAHttpSegmentWriter *writer,
uint32_t count, uint32_t *countWritten)
{
nsresult rv = Http2Stream::WriteSegments(writer, count, countWritten);
if (NS_SUCCEEDED(rv) && *countWritten) {
mLastRead = TimeStamp::Now();
}
if (rv == NS_BASE_STREAM_CLOSED) {
mPushCompleted = true;
rv = NS_OK; // this is what a normal HTTP transaction would do
}
if (rv != NS_BASE_STREAM_WOULD_BLOCK && NS_FAILED(rv))
mStatus = rv;
return rv;
}
nsresult
Http2PushedStream::ReadSegments(nsAHttpSegmentReader *,
uint32_t, uint32_t *count)
{
// 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
CreatePushHashKey(mHeaderScheme, mHeaderHost,
mSession->Serial(), mHeaderPath,
mOrigin, mHashKey);
LOG3(("Http2PushStream 0x%X hash key %s\n", mStreamID, mHashKey.get()));
// the write side of a pushed transaction just involves manipulating a little state
SetSentFin(true);
Http2Stream::mAllHeadersSent = 1;
Http2Stream::ChangeState(UPSTREAM_COMPLETE);
*count = 0;
return NS_OK;
}
bool
Http2PushedStream::GetHashKey(nsCString &key)
{
if (mHashKey.IsEmpty())
return false;
key = mHashKey;
return true;
}
void
Http2PushedStream::ConnectPushedStream(Http2Stream *stream)
{
mSession->ConnectPushedStream(stream);
}
bool
Http2PushedStream::IsOrphaned(TimeStamp now)
{
MOZ_ASSERT(!now.IsNull());
// if session is not transmitting, and is also not connected to a consumer
// stream, and its been like that for too long then it is oprhaned
if (mConsumerStream)
return false;
bool rv = ((now - mLastRead).ToSeconds() > 30.0);
if (rv) {
LOG3(("Http2PushedStream:IsOrphaned 0x%X IsOrphaned %3.2f\n",
mStreamID, (now - mLastRead).ToSeconds()));
}
return rv;
}
nsresult
Http2PushedStream::GetBufferedData(char *buf,
uint32_t count, uint32_t *countWritten)
{
if (NS_FAILED(mStatus))
return mStatus;
nsresult rv = mBufferedPush->GetBufferedData(buf, count, countWritten);
if (NS_FAILED(rv))
return rv;
if (!*countWritten)
rv = GetPushComplete() ? NS_BASE_STREAM_CLOSED : NS_BASE_STREAM_WOULD_BLOCK;
return rv;
}
//////////////////////////////////////////
// Http2PushTransactionBuffer
// This is the nsAHttpTransction owned by the stream when the pushed
// stream has not yet been matched with a pull request
//////////////////////////////////////////
NS_IMPL_ISUPPORTS0(Http2PushTransactionBuffer)
Http2PushTransactionBuffer::Http2PushTransactionBuffer()
: mStatus(NS_OK)
, mRequestHead(nullptr)
, mPushStream(nullptr)
, mIsDone(false)
, mBufferedHTTP1Size(kDefaultBufferSize)
, mBufferedHTTP1Used(0)
, mBufferedHTTP1Consumed(0)
{
mBufferedHTTP1 = new char[mBufferedHTTP1Size];
}
Http2PushTransactionBuffer::~Http2PushTransactionBuffer()
{
delete mRequestHead;
}
void
Http2PushTransactionBuffer::SetConnection(nsAHttpConnection *conn)
{
}
nsAHttpConnection *
Http2PushTransactionBuffer::Connection()
{
return nullptr;
}
void
Http2PushTransactionBuffer::GetSecurityCallbacks(nsIInterfaceRequestor **outCB)
{
*outCB = nullptr;
}
void
Http2PushTransactionBuffer::OnTransportStatus(nsITransport* transport,
nsresult status, uint64_t progress)
{
}
bool
Http2PushTransactionBuffer::IsDone()
{
return mIsDone;
}
nsresult
Http2PushTransactionBuffer::Status()
{
return mStatus;
}
uint32_t
Http2PushTransactionBuffer::Caps()
{
return 0;
}
void
Http2PushTransactionBuffer::SetDNSWasRefreshed()
{
}
uint64_t
Http2PushTransactionBuffer::Available()
{
return mBufferedHTTP1Used - mBufferedHTTP1Consumed;
}
nsresult
Http2PushTransactionBuffer::ReadSegments(nsAHttpSegmentReader *reader,
uint32_t count, uint32_t *countRead)
{
*countRead = 0;
return NS_ERROR_NOT_IMPLEMENTED;
}
nsresult
Http2PushTransactionBuffer::WriteSegments(nsAHttpSegmentWriter *writer,
uint32_t count, uint32_t *countWritten)
{
if ((mBufferedHTTP1Size - mBufferedHTTP1Used) < 20480) {
Http2Session::EnsureBuffer(mBufferedHTTP1,
mBufferedHTTP1Size + kDefaultBufferSize,
mBufferedHTTP1Used,
mBufferedHTTP1Size);
}
count = std::min(count, mBufferedHTTP1Size - mBufferedHTTP1Used);
nsresult rv = writer->OnWriteSegment(mBufferedHTTP1 + mBufferedHTTP1Used,
count, countWritten);
if (NS_SUCCEEDED(rv)) {
mBufferedHTTP1Used += *countWritten;
}
else if (rv == NS_BASE_STREAM_CLOSED) {
mIsDone = true;
}
if (Available()) {
Http2Stream *consumer = mPushStream->GetConsumerStream();
if (consumer) {
LOG3(("Http2PushTransactionBuffer::WriteSegments notifying connection "
"consumer data available 0x%X [%u]\n",
mPushStream->StreamID(), Available()));
mPushStream->ConnectPushedStream(consumer);
}
}
return rv;
}
uint32_t
Http2PushTransactionBuffer::Http1xTransactionCount()
{
return 0;
}
nsHttpRequestHead *
Http2PushTransactionBuffer::RequestHead()
{
if (!mRequestHead)
mRequestHead = new nsHttpRequestHead();
return mRequestHead;
}
nsresult
Http2PushTransactionBuffer::TakeSubTransactions(
nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
void
Http2PushTransactionBuffer::SetProxyConnectFailed()
{
}
void
Http2PushTransactionBuffer::Close(nsresult reason)
{
mStatus = reason;
mIsDone = true;
}
nsresult
Http2PushTransactionBuffer::AddTransaction(nsAHttpTransaction *trans)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
uint32_t
Http2PushTransactionBuffer::PipelineDepth()
{
return 0;
}
nsresult
Http2PushTransactionBuffer::SetPipelinePosition(int32_t position)
{
return NS_OK;
}
int32_t
Http2PushTransactionBuffer::PipelinePosition()
{
return 1;
}
nsresult
Http2PushTransactionBuffer::GetBufferedData(char *buf,
uint32_t count,
uint32_t *countWritten)
{
*countWritten = std::min(count, static_cast<uint32_t>(Available()));
if (*countWritten) {
memcpy(buf, mBufferedHTTP1 + mBufferedHTTP1Consumed, *countWritten);
mBufferedHTTP1Consumed += *countWritten;
}
// If all the data has been consumed then reset the buffer
if (mBufferedHTTP1Consumed == mBufferedHTTP1Used) {
mBufferedHTTP1Consumed = 0;
mBufferedHTTP1Used = 0;
}
return NS_OK;
}
} // namespace mozilla::net
} // namespace mozilla