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