1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/protocol/http/SpdyPush3.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,368 @@ 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 "SpdyPush3.h" 1.22 +#include "PSpdyPush.h" 1.23 +#include "SpdySession3.h" 1.24 +#include "nsHttpRequestHead.h" 1.25 + 1.26 +namespace mozilla { 1.27 +namespace net { 1.28 + 1.29 +////////////////////////////////////////// 1.30 +// SpdyPushedStream3 1.31 +////////////////////////////////////////// 1.32 + 1.33 +SpdyPushedStream3::SpdyPushedStream3(SpdyPush3TransactionBuffer *aTransaction, 1.34 + SpdySession3 *aSession, 1.35 + SpdyStream3 *aAssociatedStream, 1.36 + uint32_t aID) 1.37 + :SpdyStream3(aTransaction, aSession, 1.38 + 0 /* priority is only for sending, so ignore it on push */) 1.39 + , mConsumerStream(nullptr) 1.40 + , mBufferedPush(aTransaction) 1.41 + , mStatus(NS_OK) 1.42 + , mPushCompleted(false) 1.43 + , mDeferCleanupOnSuccess(true) 1.44 +{ 1.45 + LOG3(("SpdyPushedStream3 ctor this=%p 0x%X\n", this, aID)); 1.46 + mStreamID = aID; 1.47 + mBufferedPush->SetPushStream(this); 1.48 + mLoadGroupCI = aAssociatedStream->LoadGroupConnectionInfo(); 1.49 + mLastRead = TimeStamp::Now(); 1.50 +} 1.51 + 1.52 +bool 1.53 +SpdyPushedStream3::GetPushComplete() 1.54 +{ 1.55 + return mPushCompleted; 1.56 +} 1.57 + 1.58 +nsresult 1.59 +SpdyPushedStream3::WriteSegments(nsAHttpSegmentWriter *writer, 1.60 + uint32_t count, 1.61 + uint32_t *countWritten) 1.62 +{ 1.63 + nsresult rv = SpdyStream3::WriteSegments(writer, count, countWritten); 1.64 + if (NS_SUCCEEDED(rv) && *countWritten) { 1.65 + mLastRead = TimeStamp::Now(); 1.66 + } 1.67 + 1.68 + if (rv == NS_BASE_STREAM_CLOSED) { 1.69 + mPushCompleted = true; 1.70 + rv = NS_OK; // this is what a normal HTTP transaction would do 1.71 + } 1.72 + if (rv != NS_BASE_STREAM_WOULD_BLOCK && NS_FAILED(rv)) 1.73 + mStatus = rv; 1.74 + return rv; 1.75 +} 1.76 + 1.77 +nsresult 1.78 +SpdyPushedStream3::ReadSegments(nsAHttpSegmentReader *, uint32_t, uint32_t *count) 1.79 +{ 1.80 + // The SYN_STREAM for this has been processed, so we need to verify 1.81 + // that :host, :scheme, and :path MUST be present 1.82 + nsDependentCSubstring host, scheme, path; 1.83 + nsresult rv; 1.84 + 1.85 + rv = SpdyStream3::FindHeader(NS_LITERAL_CSTRING(":host"), host); 1.86 + if (NS_FAILED(rv)) { 1.87 + LOG3(("SpdyPushedStream3::ReadSegments session=%p ID 0x%X " 1.88 + "push without required :host\n", mSession, mStreamID)); 1.89 + return rv; 1.90 + } 1.91 + 1.92 + rv = SpdyStream3::FindHeader(NS_LITERAL_CSTRING(":scheme"), scheme); 1.93 + if (NS_FAILED(rv)) { 1.94 + LOG3(("SpdyPushedStream3::ReadSegments session=%p ID 0x%X " 1.95 + "push without required :scheme\n", mSession, mStreamID)); 1.96 + return rv; 1.97 + } 1.98 + 1.99 + rv = SpdyStream3::FindHeader(NS_LITERAL_CSTRING(":path"), path); 1.100 + if (NS_FAILED(rv)) { 1.101 + LOG3(("SpdyPushedStream3::ReadSegments session=%p ID 0x%X " 1.102 + "push without required :host\n", mSession, mStreamID)); 1.103 + return rv; 1.104 + } 1.105 + 1.106 + CreatePushHashKey(nsCString(scheme), nsCString(host), 1.107 + mSession->Serial(), path, 1.108 + mOrigin, mHashKey); 1.109 + 1.110 + LOG3(("SpdyPushStream3 0x%X hash key %s\n", mStreamID, mHashKey.get())); 1.111 + 1.112 + // the write side of a pushed transaction just involves manipulating a little state 1.113 + SpdyStream3::mSentFinOnData = 1; 1.114 + SpdyStream3::mSynFrameComplete = 1; 1.115 + SpdyStream3::ChangeState(UPSTREAM_COMPLETE); 1.116 + *count = 0; 1.117 + return NS_OK; 1.118 +} 1.119 + 1.120 +bool 1.121 +SpdyPushedStream3::GetHashKey(nsCString &key) 1.122 +{ 1.123 + if (mHashKey.IsEmpty()) 1.124 + return false; 1.125 + 1.126 + key = mHashKey; 1.127 + return true; 1.128 +} 1.129 + 1.130 +void 1.131 +SpdyPushedStream3::ConnectPushedStream(SpdyStream3 *stream) 1.132 +{ 1.133 + mSession->ConnectPushedStream(stream); 1.134 +} 1.135 + 1.136 +bool 1.137 +SpdyPushedStream3::IsOrphaned(TimeStamp now) 1.138 +{ 1.139 + MOZ_ASSERT(!now.IsNull()); 1.140 + 1.141 + // if spdy is not transmitting, and is also not connected to a consumer 1.142 + // stream, and its been like that for too long then it is oprhaned 1.143 + 1.144 + if (mConsumerStream) 1.145 + return false; 1.146 + 1.147 + bool rv = ((now - mLastRead).ToSeconds() > 30.0); 1.148 + if (rv) { 1.149 + LOG3(("SpdyPushCache::IsOrphaned 0x%X IsOrphaned %3.2f\n", 1.150 + mStreamID, (now - mLastRead).ToSeconds())); 1.151 + } 1.152 + return rv; 1.153 +} 1.154 + 1.155 +nsresult 1.156 +SpdyPushedStream3::GetBufferedData(char *buf, 1.157 + uint32_t count, 1.158 + uint32_t *countWritten) 1.159 +{ 1.160 + if (NS_FAILED(mStatus)) 1.161 + return mStatus; 1.162 + 1.163 + nsresult rv = mBufferedPush->GetBufferedData(buf, count, countWritten); 1.164 + if (NS_FAILED(rv)) 1.165 + return rv; 1.166 + 1.167 + if (!*countWritten) 1.168 + rv = GetPushComplete() ? NS_BASE_STREAM_CLOSED : NS_BASE_STREAM_WOULD_BLOCK; 1.169 + 1.170 + return rv; 1.171 +} 1.172 + 1.173 +////////////////////////////////////////// 1.174 +// SpdyPush3TransactionBuffer 1.175 +// This is the nsAHttpTransction owned by the stream when the pushed 1.176 +// stream has not yet been matched with a pull request 1.177 +////////////////////////////////////////// 1.178 + 1.179 +NS_IMPL_ISUPPORTS0(SpdyPush3TransactionBuffer) 1.180 + 1.181 +SpdyPush3TransactionBuffer::SpdyPush3TransactionBuffer() 1.182 + : mStatus(NS_OK) 1.183 + , mRequestHead(nullptr) 1.184 + , mPushStream(nullptr) 1.185 + , mIsDone(false) 1.186 + , mBufferedHTTP1Size(kDefaultBufferSize) 1.187 + , mBufferedHTTP1Used(0) 1.188 + , mBufferedHTTP1Consumed(0) 1.189 +{ 1.190 + mBufferedHTTP1 = new char[mBufferedHTTP1Size]; 1.191 +} 1.192 + 1.193 +SpdyPush3TransactionBuffer::~SpdyPush3TransactionBuffer() 1.194 +{ 1.195 + delete mRequestHead; 1.196 +} 1.197 + 1.198 +void 1.199 +SpdyPush3TransactionBuffer::SetConnection(nsAHttpConnection *conn) 1.200 +{ 1.201 +} 1.202 + 1.203 +nsAHttpConnection * 1.204 +SpdyPush3TransactionBuffer::Connection() 1.205 +{ 1.206 + return nullptr; 1.207 +} 1.208 + 1.209 +void 1.210 +SpdyPush3TransactionBuffer::GetSecurityCallbacks(nsIInterfaceRequestor **outCB) 1.211 +{ 1.212 + *outCB = nullptr; 1.213 +} 1.214 + 1.215 +void 1.216 +SpdyPush3TransactionBuffer::OnTransportStatus(nsITransport* transport, 1.217 + nsresult status, uint64_t progress) 1.218 +{ 1.219 +} 1.220 + 1.221 +bool 1.222 +SpdyPush3TransactionBuffer::IsDone() 1.223 +{ 1.224 + return mIsDone; 1.225 +} 1.226 + 1.227 +nsresult 1.228 +SpdyPush3TransactionBuffer::Status() 1.229 +{ 1.230 + return mStatus; 1.231 +} 1.232 + 1.233 +uint32_t 1.234 +SpdyPush3TransactionBuffer::Caps() 1.235 +{ 1.236 + return 0; 1.237 +} 1.238 + 1.239 +void 1.240 +SpdyPush3TransactionBuffer::SetDNSWasRefreshed() 1.241 +{ 1.242 +} 1.243 + 1.244 +uint64_t 1.245 +SpdyPush3TransactionBuffer::Available() 1.246 +{ 1.247 + return mBufferedHTTP1Used - mBufferedHTTP1Consumed; 1.248 +} 1.249 + 1.250 +nsresult 1.251 +SpdyPush3TransactionBuffer::ReadSegments(nsAHttpSegmentReader *reader, 1.252 + uint32_t count, uint32_t *countRead) 1.253 +{ 1.254 + *countRead = 0; 1.255 + return NS_ERROR_NOT_IMPLEMENTED; 1.256 +} 1.257 + 1.258 +nsresult 1.259 +SpdyPush3TransactionBuffer::WriteSegments(nsAHttpSegmentWriter *writer, 1.260 + uint32_t count, uint32_t *countWritten) 1.261 +{ 1.262 + if ((mBufferedHTTP1Size - mBufferedHTTP1Used) < 20480) { 1.263 + SpdySession3::EnsureBuffer(mBufferedHTTP1, 1.264 + mBufferedHTTP1Size + kDefaultBufferSize, 1.265 + mBufferedHTTP1Used, 1.266 + mBufferedHTTP1Size); 1.267 + } 1.268 + 1.269 + count = std::min(count, mBufferedHTTP1Size - mBufferedHTTP1Used); 1.270 + nsresult rv = writer->OnWriteSegment(mBufferedHTTP1 + mBufferedHTTP1Used, 1.271 + count, countWritten); 1.272 + if (NS_SUCCEEDED(rv)) { 1.273 + mBufferedHTTP1Used += *countWritten; 1.274 + } 1.275 + else if (rv == NS_BASE_STREAM_CLOSED) { 1.276 + mIsDone = true; 1.277 + } 1.278 + 1.279 + if (Available()) { 1.280 + SpdyStream3 *consumer = mPushStream->GetConsumerStream(); 1.281 + 1.282 + if (consumer) { 1.283 + LOG3(("SpdyPush3TransactionBuffer::WriteSegments notifying connection " 1.284 + "consumer data available 0x%X [%u]\n", 1.285 + mPushStream->StreamID(), Available())); 1.286 + mPushStream->ConnectPushedStream(consumer); 1.287 + } 1.288 + } 1.289 + 1.290 + return rv; 1.291 +} 1.292 + 1.293 +uint32_t 1.294 +SpdyPush3TransactionBuffer::Http1xTransactionCount() 1.295 +{ 1.296 + return 0; 1.297 +} 1.298 + 1.299 +nsHttpRequestHead * 1.300 +SpdyPush3TransactionBuffer::RequestHead() 1.301 +{ 1.302 + if (!mRequestHead) 1.303 + mRequestHead = new nsHttpRequestHead(); 1.304 + return mRequestHead; 1.305 +} 1.306 + 1.307 +nsresult 1.308 +SpdyPush3TransactionBuffer::TakeSubTransactions( 1.309 + nsTArray<nsRefPtr<nsAHttpTransaction> > &outTransactions) 1.310 +{ 1.311 + return NS_ERROR_NOT_IMPLEMENTED; 1.312 +} 1.313 + 1.314 +void 1.315 +SpdyPush3TransactionBuffer::SetProxyConnectFailed() 1.316 +{ 1.317 +} 1.318 + 1.319 +void 1.320 +SpdyPush3TransactionBuffer::Close(nsresult reason) 1.321 +{ 1.322 + mStatus = reason; 1.323 + mIsDone = true; 1.324 +} 1.325 + 1.326 +nsresult 1.327 +SpdyPush3TransactionBuffer::AddTransaction(nsAHttpTransaction *trans) 1.328 +{ 1.329 + return NS_ERROR_NOT_IMPLEMENTED; 1.330 +} 1.331 + 1.332 +uint32_t 1.333 +SpdyPush3TransactionBuffer::PipelineDepth() 1.334 +{ 1.335 + return 0; 1.336 +} 1.337 + 1.338 +nsresult 1.339 +SpdyPush3TransactionBuffer::SetPipelinePosition(int32_t position) 1.340 +{ 1.341 + return NS_OK; 1.342 +} 1.343 + 1.344 +int32_t 1.345 +SpdyPush3TransactionBuffer::PipelinePosition() 1.346 +{ 1.347 + return 1; 1.348 +} 1.349 + 1.350 +nsresult 1.351 +SpdyPush3TransactionBuffer::GetBufferedData(char *buf, 1.352 + uint32_t count, 1.353 + uint32_t *countWritten) 1.354 +{ 1.355 + *countWritten = std::min(count, static_cast<uint32_t>(Available())); 1.356 + if (*countWritten) { 1.357 + memcpy(buf, mBufferedHTTP1 + mBufferedHTTP1Consumed, *countWritten); 1.358 + mBufferedHTTP1Consumed += *countWritten; 1.359 + } 1.360 + 1.361 + // If all the data has been consumed then reset the buffer 1.362 + if (mBufferedHTTP1Consumed == mBufferedHTTP1Used) { 1.363 + mBufferedHTTP1Consumed = 0; 1.364 + mBufferedHTTP1Used = 0; 1.365 + } 1.366 + 1.367 + return NS_OK; 1.368 +} 1.369 + 1.370 +} // namespace mozilla::net 1.371 +} // namespace mozilla