OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 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 | |
5 #include "net/base/ip_pattern.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/strings/string_number_conversions.h" | |
9 #include "base/strings/string_split.h" | |
10 #include "base/strings/string_tokenizer.h" | |
11 | |
12 namespace net { | |
13 | |
14 class IPPattern::ComponentPattern { | |
15 public: | |
16 explicit ComponentPattern(ComponentPattern* next); | |
17 void AppendRange(uint32 min, uint32 max); | |
18 bool Match(uint32 value) const; | |
19 ComponentPattern* next() const { return next_; } | |
20 ComponentPattern* Reverse(ComponentPattern* previous); | |
wtc
2014/02/11 23:52:30
At least Reverse should be documented. (The other
jar (doing other things)
2014/02/15 21:14:56
Done.
| |
21 private: | |
22 struct Range { | |
23 public: | |
24 Range(uint32 min, uint32 max) : minimum(min), maximum(max) {} | |
25 uint32 minimum; | |
26 uint32 maximum; | |
27 }; | |
28 typedef std::vector<Range> RangeVector; | |
29 RangeVector ranges_; | |
30 ComponentPattern* next_; | |
31 DISALLOW_COPY_AND_ASSIGN(ComponentPattern); | |
wtc
2014/02/11 23:52:30
Nit: you should add more blank lines. For example,
jar (doing other things)
2014/02/15 21:14:56
Done.
| |
32 }; | |
33 | |
34 | |
wtc
2014/02/11 23:52:30
Nit: delete one blank line.
jar (doing other things)
2014/02/15 21:14:56
Done.
| |
35 IPPattern::ComponentPattern::ComponentPattern(ComponentPattern* next) | |
36 : next_(next) { | |
37 } | |
38 | |
39 void IPPattern::ComponentPattern::AppendRange(uint32 min, uint32 max) { | |
40 ranges_.push_back(Range(min, max)); | |
41 } | |
42 | |
43 bool IPPattern::ComponentPattern::Match(uint32 value) const { | |
44 // Simple linear search should be fine, as we usually only have very few | |
45 // distinct ranges to test. | |
46 for (RangeVector::const_iterator range_it = ranges_.begin(); | |
47 range_it != ranges_.end(); ++range_it) { | |
48 if (range_it->maximum >= value && range_it->minimum <= value) { | |
49 return true; | |
50 } | |
wtc
2014/02/11 23:52:30
Nit: we usually omit curly braces for one-line if
jar (doing other things)
2014/02/15 21:14:56
Done.
| |
51 } | |
52 return false; | |
53 } | |
54 | |
55 IPPattern::ComponentPattern* IPPattern::ComponentPattern::Reverse( | |
56 ComponentPattern* previous) { | |
wtc
2014/02/11 23:52:30
Nit: the function parameter should be indented by
jar (doing other things)
2014/02/15 21:14:56
Done.
| |
57 if (!next_) { | |
58 next_ = previous; | |
59 return this; | |
60 } | |
61 ComponentPattern* start = next_->Reverse(this); | |
62 next_ = previous; | |
63 return start; | |
64 } | |
65 | |
66 IPPattern::IPPattern() : is_ipv4_(true), first_component_pattern_(NULL) {} | |
67 | |
68 IPPattern::~IPPattern() { | |
69 while (first_component_pattern_ != NULL) { | |
70 ComponentPattern* component_pattern = first_component_pattern_; | |
71 first_component_pattern_ = first_component_pattern_->next(); | |
72 delete component_pattern; | |
73 } | |
74 } | |
75 | |
76 bool IPPattern::Match(const IPAddressNumber& address) const { | |
77 if (ip_mask_.empty()) { | |
wtc
2014/02/11 23:52:30
It seems that ip_mask_ should not be empty. ip_mas
jar (doing other things)
2014/02/15 21:14:56
Rather than DCHECKing, it seemed nice to insist th
| |
78 return false; | |
79 } | |
80 bool address_is_ipv4 = address.size() == kIPv4AddressSize; | |
81 if (address_is_ipv4 != is_ipv4_) { | |
82 return false; | |
83 } | |
84 | |
85 ComponentPattern* next_pattern = first_component_pattern_; | |
wtc
2014/02/11 23:52:30
Nit: name this variable "pattern".
jar (doing other things)
2014/02/15 21:14:56
Done.
| |
86 int fixed_value_index = 0; | |
87 // IPv6 |address| vectors have 16 pieces, while our |ip_mask_| has only | |
88 // 8, so it is easier to count separately. | |
89 int address_index = 0; | |
90 for (size_t i = 0; i < ip_mask_.size(); ++i) { | |
91 uint32 value_to_test = address[address_index++]; | |
92 if (!is_ipv4_) { | |
93 value_to_test = (value_to_test << 8) + address[address_index++]; | |
94 } | |
95 if (ip_mask_[i]) { | |
96 if (component_values_[fixed_value_index++] != value_to_test) { | |
97 return false; | |
98 } | |
99 continue; | |
100 } | |
101 if (!next_pattern->Match(value_to_test)) { | |
102 return false; | |
103 } | |
104 next_pattern = next_pattern->next(); | |
105 } | |
106 return true; | |
107 } | |
108 | |
109 bool IPPattern::ParsePattern(const std::string& ip_pattern) { | |
110 DCHECK(ip_mask_.empty()); | |
111 if (ip_pattern.find(':') != std::string::npos) { | |
112 is_ipv4_ = false; | |
113 } | |
114 Strings components; | |
115 base::SplitString(ip_pattern, is_ipv4_ ? '.' : ':', &components); | |
116 if (components.size() != (is_ipv4_ ? 4u : 8u)) { | |
117 DVLOG(1) << "Invalid component count: " << ip_pattern; | |
118 return false; | |
119 } | |
120 for (Strings::iterator component_it = components.begin(); | |
121 component_it != components.end(); ++component_it) { | |
122 if (component_it->empty()) { | |
123 DVLOG(1) << "Empty component: " << ip_pattern; | |
124 return false; | |
125 } | |
126 if (*component_it == "*") { | |
127 // Let standard code handle this below. | |
128 *component_it = is_ipv4_ ? "[0-255]" : "[0-FFFF]"; | |
129 } else if ((*component_it)[0] != '[') { | |
130 // This value will just have a specific integer to match. | |
131 uint32 value; | |
132 if (!ValueTextToInt(*component_it, &value)) { | |
133 return false; | |
134 } | |
135 ip_mask_.push_back(true); | |
136 component_values_.push_back(value); | |
137 continue; | |
138 } | |
139 if ((*component_it)[component_it->size() - 1] != ']') { | |
wtc
2014/02/11 23:52:30
This can be component_it->back().
Similarly, on l
jar (doing other things)
2014/02/15 21:14:56
Much nicer! thanks.
Done.
...but then... the try
wtc
2014/02/19 00:24:11
On 2014/02/15 21:14:56, jar wrote:
[...]
| |
140 DVLOG(1) << "Missing close bracket: " << ip_pattern; | |
141 return false; | |
142 } | |
143 // Now we know the size() is at least 2. | |
144 if (component_it->size() == 2) { | |
145 DVLOG(1) << "Empty bracket: " << ip_pattern; | |
146 return false; | |
147 } | |
148 // We'll need a pattern to match this bracketed component. | |
wtc
2014/02/11 23:52:30
Nit: two spaces before "We'll".
jar (doing other things)
2014/02/15 21:14:56
Done.
| |
149 // Anticipate that it will probably link to (be pushed in front of) the | |
150 // existing first_component_pattern_, if we parse the pattern. | |
151 scoped_ptr<ComponentPattern> component_pattern( | |
152 new ComponentPattern(first_component_pattern_)); | |
153 // Trim leading and trailing bracket before calling for parsing. | |
154 if (!ParseComponentPattern(component_it->substr( | |
wtc
2014/02/11 23:52:30
If you change ParseComponentPattern to take a base
jar (doing other things)
2014/02/15 21:14:56
Done.... but we end up converting it std::string i
| |
155 1, component_it->size() - 2), component_pattern.get())) { | |
156 return false; | |
157 } | |
158 ip_mask_.push_back(false); | |
159 // Push onto list. | |
160 DCHECK_EQ(first_component_pattern_, component_pattern->next()); | |
161 first_component_pattern_ = component_pattern.release(); | |
162 } | |
163 // The list starting with first_component_pattern_ is now backwards from what | |
164 // is needed to process a match, so we need to reverse it. | |
wtc
2014/02/11 23:52:30
If you maintain a last_component_pattern pointer a
jar (doing other things)
2014/02/15 21:14:56
Transitioned to std::vector<pointers>
| |
165 if (first_component_pattern_) { | |
166 first_component_pattern_ = first_component_pattern_->Reverse(NULL); | |
167 } | |
168 return true; | |
169 } | |
170 | |
171 bool IPPattern::ParseComponentPattern(const std::string& text, | |
172 ComponentPattern* pattern) const { | |
173 // We're given a comma separated set of ranges, some of which may be simple | |
174 // constants. | |
175 Strings ranges; | |
176 base::SplitString(text, ',', &ranges); | |
177 for (Strings::iterator range_it = ranges.begin(); | |
178 range_it != ranges.end(); ++range_it) { | |
179 base::StringTokenizer range_pair(*range_it, "-"); | |
180 uint32 min = 0; | |
181 range_pair.GetNext(); | |
182 if (!ValueTextToInt(range_pair.token(), &min)) { | |
183 return false; | |
184 } | |
185 uint32 max = min; // Sometimes we have no distinct max. | |
186 if (range_pair.GetNext()) { | |
187 if (!ValueTextToInt(range_pair.token(), &max)) { | |
188 return false; | |
189 } | |
190 } | |
191 if (range_pair.GetNext()) { | |
192 // Too many "-" in this range specifier. | |
193 DVLOG(1) << "Too many hyphens in range: "; | |
194 return false; | |
195 } | |
196 pattern->AppendRange(min, max); | |
wtc
2014/02/11 23:52:30
Is it OK to append some ranges, and then fail and
jar (doing other things)
2014/02/15 21:14:56
The caller discards the partially constructed patt
| |
197 } | |
198 return true; | |
199 } | |
200 | |
201 bool IPPattern::ValueTextToInt(const base::StringPiece& input, | |
202 uint32* output) const { | |
203 bool ok = is_ipv4_ ? base::StringToUint(input, output) | |
204 : base::HexStringToUInt(input, output); | |
wtc
2014/02/11 23:52:30
Nit: we usually put an operator (such as ":") at t
jar (doing other things)
2014/02/15 21:14:56
Done.
| |
205 if (is_ipv4_ && *output > 255u) { | |
206 DVLOG(1) << "IPv4 component greater than 255"; | |
wtc
2014/02/11 23:52:30
For IPv6, you should also verify that *output <= 0
jar (doing other things)
2014/02/15 21:14:56
Done.
| |
207 return false; | |
208 } | |
209 if (!ok) { | |
210 DVLOG(1) << "Could not convert value to number: " << input; | |
211 } | |
wtc
2014/02/11 23:52:30
I think we should first check !ok, then check the
jar (doing other things)
2014/02/15 21:14:56
Good catch!
Done.
| |
212 return ok; | |
213 } | |
214 | |
215 } // namespace net | |
OLD | NEW |