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 |