| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/quic/quic_client_promised_info.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "net/quic/spdy_utils.h" | |
| 9 | |
| 10 using net::SpdyHeaderBlock; | |
| 11 using net::kPushPromiseTimeoutSecs; | |
| 12 using std::string; | |
| 13 | |
| 14 namespace net { | |
| 15 | |
| 16 QuicClientPromisedInfo::QuicClientPromisedInfo(QuicClientSessionBase* session, | |
| 17 QuicStreamId id, | |
| 18 string url) | |
| 19 : session_(session), | |
| 20 id_(id), | |
| 21 url_(url), | |
| 22 client_request_delegate_(nullptr) {} | |
| 23 | |
| 24 QuicClientPromisedInfo::~QuicClientPromisedInfo() {} | |
| 25 | |
| 26 void QuicClientPromisedInfo::CleanupAlarm::OnAlarm() { | |
| 27 DVLOG(1) << "self GC alarm for stream " << promised_->id_; | |
| 28 promised_->Reset(QUIC_STREAM_CANCELLED); | |
| 29 } | |
| 30 | |
| 31 void QuicClientPromisedInfo::Init() { | |
| 32 cleanup_alarm_.reset(session_->connection()->alarm_factory()->CreateAlarm( | |
| 33 new QuicClientPromisedInfo::CleanupAlarm(this))); | |
| 34 cleanup_alarm_->Set( | |
| 35 session_->connection()->helper()->GetClock()->ApproximateNow() + | |
| 36 QuicTime::Delta::FromSeconds(kPushPromiseTimeoutSecs)); | |
| 37 } | |
| 38 | |
| 39 void QuicClientPromisedInfo::OnPromiseHeaders(const SpdyHeaderBlock& headers) { | |
| 40 // RFC7540, Section 8.2, requests MUST be safe [RFC7231], Section | |
| 41 // 4.2.1. GET and HEAD are the methods that are safe and required. | |
| 42 SpdyHeaderBlock::const_iterator it = headers.find(":method"); | |
| 43 DCHECK(it != headers.end()); | |
| 44 if (!(it->second == "GET" || it->second == "HEAD")) { | |
| 45 DVLOG(1) << "Promise for stream " << id_ << " has invalid method " | |
| 46 << it->second; | |
| 47 Reset(QUIC_INVALID_PROMISE_METHOD); | |
| 48 return; | |
| 49 } | |
| 50 if (!SpdyUtils::UrlIsValid(headers)) { | |
| 51 DVLOG(1) << "Promise for stream " << id_ << " has invalid URL " << url_; | |
| 52 Reset(QUIC_INVALID_PROMISE_URL); | |
| 53 return; | |
| 54 } | |
| 55 if (!session_->IsAuthorized(SpdyUtils::GetHostNameFromHeaderBlock(headers))) { | |
| 56 Reset(QUIC_UNAUTHORIZED_PROMISE_URL); | |
| 57 return; | |
| 58 } | |
| 59 request_headers_.reset(new SpdyHeaderBlock(headers.Clone())); | |
| 60 } | |
| 61 | |
| 62 void QuicClientPromisedInfo::OnResponseHeaders(const SpdyHeaderBlock& headers) { | |
| 63 response_headers_.reset(new SpdyHeaderBlock(headers.Clone())); | |
| 64 if (client_request_delegate_) { | |
| 65 // We already have a client request waiting. | |
| 66 FinalValidation(); | |
| 67 } | |
| 68 } | |
| 69 | |
| 70 void QuicClientPromisedInfo::Reset(QuicRstStreamErrorCode error_code) { | |
| 71 QuicClientPushPromiseIndex::Delegate* delegate = client_request_delegate_; | |
| 72 session_->ResetPromised(id_, error_code); | |
| 73 session_->DeletePromised(this); | |
| 74 if (delegate) { | |
| 75 delegate->OnRendezvousResult(nullptr); | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 QuicAsyncStatus QuicClientPromisedInfo::FinalValidation() { | |
| 80 if (!client_request_delegate_->CheckVary( | |
| 81 *client_request_headers_, *request_headers_, *response_headers_)) { | |
| 82 Reset(QUIC_PROMISE_VARY_MISMATCH); | |
| 83 return QUIC_FAILURE; | |
| 84 } | |
| 85 QuicSpdyStream* stream = session_->GetPromisedStream(id_); | |
| 86 if (!stream) { | |
| 87 // This shouldn't be possible, as |ClientRequest| guards against | |
| 88 // closed stream for the synchronous case. And in the | |
| 89 // asynchronous case, a RST can only be caught by |OnAlarm()|. | |
| 90 QUIC_BUG << "missing promised stream" << id_; | |
| 91 } | |
| 92 QuicClientPushPromiseIndex::Delegate* delegate = client_request_delegate_; | |
| 93 session_->DeletePromised(this); | |
| 94 // Stream can start draining now | |
| 95 if (delegate) { | |
| 96 delegate->OnRendezvousResult(stream); | |
| 97 } | |
| 98 return QUIC_SUCCESS; | |
| 99 } | |
| 100 | |
| 101 QuicAsyncStatus QuicClientPromisedInfo::HandleClientRequest( | |
| 102 const SpdyHeaderBlock& request_headers, | |
| 103 QuicClientPushPromiseIndex::Delegate* delegate) { | |
| 104 if (session_->IsClosedStream(id_)) { | |
| 105 // There was a RST on the response stream. | |
| 106 session_->DeletePromised(this); | |
| 107 return QUIC_FAILURE; | |
| 108 } | |
| 109 client_request_delegate_ = delegate; | |
| 110 client_request_headers_.reset(new SpdyHeaderBlock(request_headers.Clone())); | |
| 111 if (!response_headers_) { | |
| 112 return QUIC_PENDING; | |
| 113 } | |
| 114 return FinalValidation(); | |
| 115 } | |
| 116 | |
| 117 void QuicClientPromisedInfo::Cancel() { | |
| 118 // Don't fire OnRendezvousResult() for client initiated cancel. | |
| 119 client_request_delegate_ = nullptr; | |
| 120 Reset(QUIC_STREAM_CANCELLED); | |
| 121 } | |
| 122 | |
| 123 } // namespace net | |
| OLD | NEW |