OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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 #include "net/spdy/hpack_huffman_aggregator.h" | |
5 | |
6 #include "base/metrics/bucket_ranges.h" | |
7 #include "base/metrics/field_trial.h" | |
8 #include "base/metrics/histogram.h" | |
9 #include "base/metrics/sample_vector.h" | |
10 #include "base/strings/string_number_conversions.h" | |
11 #include "base/strings/string_util.h" | |
12 #include "net/base/load_flags.h" | |
13 #include "net/http/http_request_headers.h" | |
14 #include "net/http/http_request_info.h" | |
15 #include "net/http/http_response_headers.h" | |
16 #include "net/spdy/hpack_encoder.h" | |
17 #include "net/spdy/spdy_http_utils.h" | |
18 | |
19 namespace net { | |
20 | |
21 namespace { | |
22 | |
23 const char kHistogramName[] = "Net.SpdyHpackEncodedCharacterFrequency"; | |
24 | |
25 const size_t kTotalCountsPublishThreshold = 10000; | |
26 | |
27 // Each encoder uses the default dynamic table size of 4096 total bytes. | |
28 const size_t kMaxEncoders = 20; | |
29 | |
30 } // namespace | |
31 | |
32 HpackHuffmanAggregator::HpackHuffmanAggregator() | |
33 : counts_(256, 0), | |
34 total_counts_(0), | |
35 max_encoders_(kMaxEncoders) { | |
36 } | |
37 | |
38 HpackHuffmanAggregator::~HpackHuffmanAggregator() { | |
39 } | |
40 | |
41 void HpackHuffmanAggregator::AggregateTransactionCharacterCounts( | |
42 const HttpRequestInfo& request, | |
43 const HttpRequestHeaders& request_headers, | |
44 const ProxyServer& proxy, | |
45 const HttpResponseHeaders& response_headers) { | |
46 if (IsCrossOrigin(request)) { | |
47 return; | |
48 } | |
49 HostPortPair endpoint = HostPortPair(request.url.HostNoBrackets(), | |
50 request.url.EffectiveIntPort()); | |
51 HpackEncoder* encoder = ObtainEncoder( | |
52 SpdySessionKey(endpoint, proxy, request.privacy_mode)); | |
53 | |
54 // Convert and encode the request and response header sets. | |
55 { | |
56 SpdyHeaderBlock headers; | |
57 CreateSpdyHeadersFromHttpRequest( | |
58 request, request_headers, &headers, SPDY4, false); | |
59 | |
60 std::string tmp_out; | |
61 encoder->EncodeHeaderSet(headers, &tmp_out); | |
62 } | |
63 { | |
64 SpdyHeaderBlock headers; | |
65 CreateSpdyHeadersFromHttpResponse(response_headers, &headers); | |
66 | |
67 std::string tmp_out; | |
68 encoder->EncodeHeaderSet(headers, &tmp_out); | |
69 } | |
70 if (total_counts_ >= kTotalCountsPublishThreshold) { | |
71 PublishCounts(); | |
72 } | |
73 } | |
74 | |
75 // static | |
76 bool HpackHuffmanAggregator::UseAggregator() { | |
77 const std::string group_name = | |
78 base::FieldTrialList::FindFullName("HpackHuffmanAggregator"); | |
79 if (group_name == "Enabled") { | |
80 return true; | |
81 } | |
82 // HACK(jgraettinger): To be removed before submission. | |
jar (doing other things)
2014/04/18 21:14:53
hmmmm.... this seems like a bad plan.... and subje
| |
83 // This is here to enable by-default on try-bots. | |
84 if (group_name.empty()) { | |
85 return true; | |
86 } | |
87 return false; | |
88 } | |
89 | |
90 // static | |
91 void HpackHuffmanAggregator::CreateSpdyHeadersFromHttpResponse( | |
92 const HttpResponseHeaders& headers, | |
93 SpdyHeaderBlock* headers_out) { | |
94 // Lower-case header names, and coalesce multiple values delimited by \0. | |
95 // Also add the fixed status header. | |
96 std::string name, value; | |
97 void* it = NULL; | |
98 while (headers.EnumerateHeaderLines(&it, &name, &value)) { | |
99 StringToLowerASCII(&name); | |
100 if (headers_out->find(name) == headers_out->end()) { | |
101 (*headers_out)[name] = value; | |
102 } else { | |
103 (*headers_out)[name] += std::string(1, '\0') + value; | |
104 } | |
105 } | |
106 (*headers_out)[":status"] = base::IntToString(headers.response_code()); | |
107 } | |
108 | |
109 // static | |
110 bool HpackHuffmanAggregator::IsCrossOrigin(const HttpRequestInfo& request) { | |
111 // Require that the request is top-level, or that it shares | |
112 // an origin with its referer. | |
113 HostPortPair endpoint = HostPortPair(request.url.HostNoBrackets(), | |
114 request.url.EffectiveIntPort()); | |
115 if ((request.load_flags & LOAD_MAIN_FRAME) == 0) { | |
116 std::string referer_str; | |
117 if (!request.extra_headers.GetHeader(HttpRequestHeaders::kReferer, | |
118 &referer_str)) { | |
119 // Require a referer. | |
120 return true; | |
121 } | |
122 GURL referer(referer_str); | |
123 HostPortPair referer_endpoint = HostPortPair(referer.HostNoBrackets(), | |
124 referer.EffectiveIntPort()); | |
125 if (!endpoint.Equals(referer_endpoint)) { | |
126 // Cross-origin request. | |
127 return true; | |
128 } | |
129 } | |
130 return false; | |
131 } | |
132 | |
133 HpackEncoder* HpackHuffmanAggregator::ObtainEncoder(const SpdySessionKey& key) { | |
134 for (OriginEncoders::iterator it = encoders_.begin(); | |
135 it != encoders_.end(); ++it) { | |
136 if (key.Equals(it->first)) { | |
137 // Move to head of list and return. | |
138 OriginEncoder origin_encoder = *it; | |
139 encoders_.erase(it); | |
140 encoders_.push_front(origin_encoder); | |
141 return origin_encoder.second; | |
142 } | |
143 } | |
144 // Not found. Create a new encoder, evicting one if needed. | |
145 encoders_.push_front(std::make_pair(key, new HpackEncoder())); | |
146 if (encoders_.size() > max_encoders_) { | |
147 delete encoders_.back().second; | |
148 encoders_.pop_back(); | |
149 } | |
150 encoders_.front().second->SetCharCountsStorage(&counts_, &total_counts_); | |
151 return encoders_.front().second; | |
152 } | |
153 | |
154 void HpackHuffmanAggregator::PublishCounts() { | |
155 // base::Histogram requires that values be 1-indexed. | |
156 const size_t kRangeMin = 1; | |
157 const size_t kRangeMax = counts_.size() + 1; | |
158 const size_t kBucketCount = kRangeMax + 1; | |
159 | |
160 base::BucketRanges ranges(kBucketCount + 1); | |
161 for (size_t i = 0; i != ranges.size(); ++i) { | |
162 ranges.set_range(i, i); | |
163 } | |
164 ranges.ResetChecksum(); | |
165 | |
166 // Copy |counts_| into a SampleVector. | |
167 base::SampleVector samples(&ranges); | |
168 for (size_t i = 0; i != counts_.size(); ++i) { | |
169 samples.Accumulate(i + 1, counts_[i]); | |
jar (doing other things)
2014/04/18 21:14:53
Why are you putting samples into your personal his
| |
170 } | |
171 | |
172 STATIC_HISTOGRAM_POINTER_BLOCK( | |
173 kHistogramName, | |
174 AddSamples(samples), | |
175 base::LinearHistogram::FactoryGet( | |
176 kHistogramName, kRangeMin, kRangeMax, kBucketCount, | |
177 base::HistogramBase::kUmaTargetedHistogramFlag)); | |
178 | |
179 // Clear counts. | |
180 counts_.assign(counts_.size(), 0); | |
181 total_counts_ = 0; | |
182 } | |
183 | |
184 } // namespace net | |
OLD | NEW |