1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/protocol/http/Http2Push.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,344 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set sw=2 ts=8 et tw=80 : */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +// HttpLog.h should generally be included first 1.11 +#include "HttpLog.h" 1.12 + 1.13 +// Log on level :5, instead of default :4. 1.14 +#undef LOG 1.15 +#define LOG(args) LOG5(args) 1.16 +#undef LOG_ENABLED 1.17 +#define LOG_ENABLED() LOG5_ENABLED() 1.18 + 1.19 +#include <algorithm> 1.20 + 1.21 +#include "Http2Push.h" 1.22 + 1.23 +#include "nsDependentString.h" 1.24 + 1.25 +namespace mozilla { 1.26 +namespace net { 1.27 + 1.28 +////////////////////////////////////////// 1.29 +// Http2PushedStream 1.30 +////////////////////////////////////////// 1.31 + 1.32 +Http2PushedStream::Http2PushedStream(Http2PushTransactionBuffer *aTransaction, 1.33 + Http2Session *aSession, 1.34 + Http2Stream *aAssociatedStream, 1.35 + uint32_t aID) 1.36 + :Http2Stream(aTransaction, aSession, 0) 1.37 + , mConsumerStream(nullptr) 1.38 + , mBufferedPush(aTransaction) 1.39 + , mStatus(NS_OK) 1.40 + , mPushCompleted(false) 1.41 + , mDeferCleanupOnSuccess(true) 1.42 +{ 1.43 + LOG3(("Http2PushedStream ctor this=%p 0x%X\n", this, aID)); 1.44 + mStreamID = aID; 1.45 + MOZ_ASSERT(!(aID & 1)); // must be even to be a pushed stream 1.46 + mBufferedPush->SetPushStream(this); 1.47 + mLoadGroupCI = aAssociatedStream->LoadGroupConnectionInfo(); 1.48 + mLastRead = TimeStamp::Now(); 1.49 + SetPriority(aAssociatedStream->Priority() + 1); 1.50 +} 1.51 + 1.52 +bool 1.53 +Http2PushedStream::GetPushComplete() 1.54 +{ 1.55 + return mPushCompleted; 1.56 +} 1.57 + 1.58 +nsresult 1.59 +Http2PushedStream::WriteSegments(nsAHttpSegmentWriter *writer, 1.60 + uint32_t count, uint32_t *countWritten) 1.61 +{ 1.62 + nsresult rv = Http2Stream::WriteSegments(writer, count, countWritten); 1.63 + if (NS_SUCCEEDED(rv) && *countWritten) { 1.64 + mLastRead = TimeStamp::Now(); 1.65 + } 1.66 + 1.67 + if (rv == NS_BASE_STREAM_CLOSED) { 1.68 + mPushCompleted = true; 1.69 + rv = NS_OK; // this is what a normal HTTP transaction would do 1.70 + } 1.71 + if (rv != NS_BASE_STREAM_WOULD_BLOCK && NS_FAILED(rv)) 1.72 + mStatus = rv; 1.73 + return rv; 1.74 +} 1.75 + 1.76 +nsresult 1.77 +Http2PushedStream::ReadSegments(nsAHttpSegmentReader *, 1.78 + uint32_t, uint32_t *count) 1.79 +{ 1.80 + // The request headers for this has been processed, so we need to verify 1.81 + // that :authority, :scheme, and :path MUST be present. :method MUST NOT be 1.82 + // present 1.83 + CreatePushHashKey(mHeaderScheme, mHeaderHost, 1.84 + mSession->Serial(), mHeaderPath, 1.85 + mOrigin, mHashKey); 1.86 + 1.87 + LOG3(("Http2PushStream 0x%X hash key %s\n", mStreamID, mHashKey.get())); 1.88 + 1.89 + // the write side of a pushed transaction just involves manipulating a little state 1.90 + SetSentFin(true); 1.91 + Http2Stream::mAllHeadersSent = 1; 1.92 + Http2Stream::ChangeState(UPSTREAM_COMPLETE); 1.93 + *count = 0; 1.94 + return NS_OK; 1.95 +} 1.96 + 1.97 +bool 1.98 +Http2PushedStream::GetHashKey(nsCString &key) 1.99 +{ 1.100 + if (mHashKey.IsEmpty()) 1.101 + return false; 1.102 + 1.103 + key = mHashKey; 1.104 + return true; 1.105 +} 1.106 + 1.107 +void 1.108 +Http2PushedStream::ConnectPushedStream(Http2Stream *stream) 1.109 +{ 1.110 + mSession->ConnectPushedStream(stream); 1.111 +} 1.112 + 1.113 +bool 1.114 +Http2PushedStream::IsOrphaned(TimeStamp now) 1.115 +{ 1.116 + MOZ_ASSERT(!now.IsNull()); 1.117 + 1.118 + // if session is not transmitting, and is also not connected to a consumer 1.119 + // stream, and its been like that for too long then it is oprhaned 1.120 + 1.121 + if (mConsumerStream) 1.122 + return false; 1.123 + 1.124 + bool rv = ((now - mLastRead).ToSeconds() > 30.0); 1.125 + if (rv) { 1.126 + LOG3(("Http2PushedStream:IsOrphaned 0x%X IsOrphaned %3.2f\n", 1.127 + mStreamID, (now - mLastRead).ToSeconds())); 1.128 + } 1.129 + return rv; 1.130 +} 1.131 + 1.132 +nsresult 1.133 +Http2PushedStream::GetBufferedData(char *buf, 1.134 + uint32_t count, uint32_t *countWritten) 1.135 +{ 1.136 + if (NS_FAILED(mStatus)) 1.137 + return mStatus; 1.138 + 1.139 + nsresult rv = mBufferedPush->GetBufferedData(buf, count, countWritten); 1.140 + if (NS_FAILED(rv)) 1.141 + return rv; 1.142 + 1.143 + if (!*countWritten) 1.144 + rv = GetPushComplete() ? NS_BASE_STREAM_CLOSED : NS_BASE_STREAM_WOULD_BLOCK; 1.145 + 1.146 + return rv; 1.147 +} 1.148 + 1.149 +////////////////////////////////////////// 1.150 +// Http2PushTransactionBuffer 1.151 +// This is the nsAHttpTransction owned by the stream when the pushed 1.152 +// stream has not yet been matched with a pull request 1.153 +////////////////////////////////////////// 1.154 + 1.155 +NS_IMPL_ISUPPORTS0(Http2PushTransactionBuffer) 1.156 + 1.157 +Http2PushTransactionBuffer::Http2PushTransactionBuffer() 1.158 + : mStatus(NS_OK) 1.159 + , mRequestHead(nullptr) 1.160 + , mPushStream(nullptr) 1.161 + , mIsDone(false) 1.162 + , mBufferedHTTP1Size(kDefaultBufferSize) 1.163 + , mBufferedHTTP1Used(0) 1.164 + , mBufferedHTTP1Consumed(0) 1.165 +{ 1.166 + mBufferedHTTP1 = new char[mBufferedHTTP1Size]; 1.167 +} 1.168 + 1.169 +Http2PushTransactionBuffer::~Http2PushTransactionBuffer() 1.170 +{ 1.171 + delete mRequestHead; 1.172 +} 1.173 + 1.174 +void 1.175 +Http2PushTransactionBuffer::SetConnection(nsAHttpConnection *conn) 1.176 +{ 1.177 +} 1.178 + 1.179 +nsAHttpConnection * 1.180 +Http2PushTransactionBuffer::Connection() 1.181 +{ 1.182 + return nullptr; 1.183 +} 1.184 + 1.185 +void 1.186 +Http2PushTransactionBuffer::GetSecurityCallbacks(nsIInterfaceRequestor **outCB) 1.187 +{ 1.188 + *outCB = nullptr; 1.189 +} 1.190 + 1.191 +void 1.192 +Http2PushTransactionBuffer::OnTransportStatus(nsITransport* transport, 1.193 + nsresult status, uint64_t progress) 1.194 +{ 1.195 +} 1.196 + 1.197 +bool 1.198 +Http2PushTransactionBuffer::IsDone() 1.199 +{ 1.200 + return mIsDone; 1.201 +} 1.202 + 1.203 +nsresult 1.204 +Http2PushTransactionBuffer::Status() 1.205 +{ 1.206 + return mStatus; 1.207 +} 1.208 + 1.209 +uint32_t 1.210 +Http2PushTransactionBuffer::Caps() 1.211 +{ 1.212 + return 0; 1.213 +} 1.214 + 1.215 +void 1.216 +Http2PushTransactionBuffer::SetDNSWasRefreshed() 1.217 +{ 1.218 +} 1.219 + 1.220 +uint64_t 1.221 +Http2PushTransactionBuffer::Available() 1.222 +{ 1.223 + return mBufferedHTTP1Used - mBufferedHTTP1Consumed; 1.224 +} 1.225 + 1.226 +nsresult 1.227 +Http2PushTransactionBuffer::ReadSegments(nsAHttpSegmentReader *reader, 1.228 + uint32_t count, uint32_t *countRead) 1.229 +{ 1.230 + *countRead = 0; 1.231 + return NS_ERROR_NOT_IMPLEMENTED; 1.232 +} 1.233 + 1.234 +nsresult 1.235 +Http2PushTransactionBuffer::WriteSegments(nsAHttpSegmentWriter *writer, 1.236 + uint32_t count, uint32_t *countWritten) 1.237 +{ 1.238 + if ((mBufferedHTTP1Size - mBufferedHTTP1Used) < 20480) { 1.239 + Http2Session::EnsureBuffer(mBufferedHTTP1, 1.240 + mBufferedHTTP1Size + kDefaultBufferSize, 1.241 + mBufferedHTTP1Used, 1.242 + mBufferedHTTP1Size); 1.243 + } 1.244 + 1.245 + count = std::min(count, mBufferedHTTP1Size - mBufferedHTTP1Used); 1.246 + nsresult rv = writer->OnWriteSegment(mBufferedHTTP1 + mBufferedHTTP1Used, 1.247 + count, countWritten); 1.248 + if (NS_SUCCEEDED(rv)) { 1.249 + mBufferedHTTP1Used += *countWritten; 1.250 + } 1.251 + else if (rv == NS_BASE_STREAM_CLOSED) { 1.252 + mIsDone = true; 1.253 + } 1.254 + 1.255 + if (Available()) { 1.256 + Http2Stream *consumer = mPushStream->GetConsumerStream(); 1.257 + 1.258 + if (consumer) { 1.259 + LOG3(("Http2PushTransactionBuffer::WriteSegments notifying connection " 1.260 + "consumer data available 0x%X [%u]\n", 1.261 + mPushStream->StreamID(), Available())); 1.262 + mPushStream->ConnectPushedStream(consumer); 1.263 + } 1.264 + } 1.265 + 1.266 + return rv; 1.267 +} 1.268 + 1.269 +uint32_t 1.270 +Http2PushTransactionBuffer::Http1xTransactionCount() 1.271 +{ 1.272 + return 0; 1.273 +} 1.274 + 1.275 +nsHttpRequestHead * 1.276 +Http2PushTransactionBuffer::RequestHead() 1.277 +{ 1.278 + if (!mRequestHead) 1.279 + mRequestHead = new nsHttpRequestHead(); 1.280 + return mRequestHead; 1.281 +} 1.282 + 1.283 +nsresult 1.284 +Http2PushTransactionBuffer::TakeSubTransactions( 1.285 + nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions) 1.286 +{ 1.287 + return NS_ERROR_NOT_IMPLEMENTED; 1.288 +} 1.289 + 1.290 +void 1.291 +Http2PushTransactionBuffer::SetProxyConnectFailed() 1.292 +{ 1.293 +} 1.294 + 1.295 +void 1.296 +Http2PushTransactionBuffer::Close(nsresult reason) 1.297 +{ 1.298 + mStatus = reason; 1.299 + mIsDone = true; 1.300 +} 1.301 + 1.302 +nsresult 1.303 +Http2PushTransactionBuffer::AddTransaction(nsAHttpTransaction *trans) 1.304 +{ 1.305 + return NS_ERROR_NOT_IMPLEMENTED; 1.306 +} 1.307 + 1.308 +uint32_t 1.309 +Http2PushTransactionBuffer::PipelineDepth() 1.310 +{ 1.311 + return 0; 1.312 +} 1.313 + 1.314 +nsresult 1.315 +Http2PushTransactionBuffer::SetPipelinePosition(int32_t position) 1.316 +{ 1.317 + return NS_OK; 1.318 +} 1.319 + 1.320 +int32_t 1.321 +Http2PushTransactionBuffer::PipelinePosition() 1.322 +{ 1.323 + return 1; 1.324 +} 1.325 + 1.326 +nsresult 1.327 +Http2PushTransactionBuffer::GetBufferedData(char *buf, 1.328 + uint32_t count, 1.329 + uint32_t *countWritten) 1.330 +{ 1.331 + *countWritten = std::min(count, static_cast<uint32_t>(Available())); 1.332 + if (*countWritten) { 1.333 + memcpy(buf, mBufferedHTTP1 + mBufferedHTTP1Consumed, *countWritten); 1.334 + mBufferedHTTP1Consumed += *countWritten; 1.335 + } 1.336 + 1.337 + // If all the data has been consumed then reset the buffer 1.338 + if (mBufferedHTTP1Consumed == mBufferedHTTP1Used) { 1.339 + mBufferedHTTP1Consumed = 0; 1.340 + mBufferedHTTP1Used = 0; 1.341 + } 1.342 + 1.343 + return NS_OK; 1.344 +} 1.345 + 1.346 +} // namespace mozilla::net 1.347 +} // namespace mozilla