OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/libjingle/xmpp/jid.h" | |
12 | |
13 #include <ctype.h> | |
14 | |
15 #include <algorithm> | |
16 #include <string> | |
17 | |
18 #include "webrtc/libjingle/xmpp/constants.h" | |
19 #include "webrtc/base/common.h" | |
20 #include "webrtc/base/logging.h" | |
21 | |
22 namespace buzz { | |
23 | |
24 Jid::Jid() { | |
25 } | |
26 | |
27 Jid::Jid(const std::string& jid_string) { | |
28 if (jid_string.empty()) | |
29 return; | |
30 | |
31 // First find the slash and slice off that part | |
32 size_t slash = jid_string.find('/'); | |
33 resource_name_ = (slash == std::string::npos ? STR_EMPTY : | |
34 jid_string.substr(slash + 1)); | |
35 | |
36 // Now look for the node | |
37 size_t at = jid_string.find('@'); | |
38 size_t domain_begin; | |
39 if (at < slash && at != std::string::npos) { | |
40 node_name_ = jid_string.substr(0, at); | |
41 domain_begin = at + 1; | |
42 } else { | |
43 domain_begin = 0; | |
44 } | |
45 | |
46 // Now take what is left as the domain | |
47 size_t domain_length = (slash == std::string::npos) ? | |
48 (jid_string.length() - domain_begin) : (slash - domain_begin); | |
49 domain_name_ = jid_string.substr(domain_begin, domain_length); | |
50 | |
51 ValidateOrReset(); | |
52 } | |
53 | |
54 Jid::Jid(const std::string& node_name, | |
55 const std::string& domain_name, | |
56 const std::string& resource_name) | |
57 : node_name_(node_name), | |
58 domain_name_(domain_name), | |
59 resource_name_(resource_name) { | |
60 ValidateOrReset(); | |
61 } | |
62 | |
63 void Jid::ValidateOrReset() { | |
64 bool valid_node; | |
65 bool valid_domain; | |
66 bool valid_resource; | |
67 | |
68 node_name_ = PrepNode(node_name_, &valid_node); | |
69 domain_name_ = PrepDomain(domain_name_, &valid_domain); | |
70 resource_name_ = PrepResource(resource_name_, &valid_resource); | |
71 | |
72 if (!valid_node || !valid_domain || !valid_resource) { | |
73 node_name_.clear(); | |
74 domain_name_.clear(); | |
75 resource_name_.clear(); | |
76 } | |
77 } | |
78 | |
79 std::string Jid::Str() const { | |
80 if (!IsValid()) | |
81 return STR_EMPTY; | |
82 | |
83 std::string ret; | |
84 | |
85 if (!node_name_.empty()) | |
86 ret = node_name_ + "@"; | |
87 | |
88 ASSERT(domain_name_ != STR_EMPTY); | |
89 ret += domain_name_; | |
90 | |
91 if (!resource_name_.empty()) | |
92 ret += "/" + resource_name_; | |
93 | |
94 return ret; | |
95 } | |
96 | |
97 Jid::~Jid() { | |
98 } | |
99 | |
100 bool Jid::IsEmpty() const { | |
101 return (node_name_.empty() && domain_name_.empty() && | |
102 resource_name_.empty()); | |
103 } | |
104 | |
105 bool Jid::IsValid() const { | |
106 return !domain_name_.empty(); | |
107 } | |
108 | |
109 bool Jid::IsBare() const { | |
110 if (IsEmpty()) { | |
111 LOG(LS_VERBOSE) << "Warning: Calling IsBare() on the empty jid."; | |
112 return true; | |
113 } | |
114 return IsValid() && resource_name_.empty(); | |
115 } | |
116 | |
117 bool Jid::IsFull() const { | |
118 return IsValid() && !resource_name_.empty(); | |
119 } | |
120 | |
121 Jid Jid::BareJid() const { | |
122 if (!IsValid()) | |
123 return Jid(); | |
124 if (!IsFull()) | |
125 return *this; | |
126 return Jid(node_name_, domain_name_, STR_EMPTY); | |
127 } | |
128 | |
129 bool Jid::BareEquals(const Jid& other) const { | |
130 return other.node_name_ == node_name_ && | |
131 other.domain_name_ == domain_name_; | |
132 } | |
133 | |
134 void Jid::CopyFrom(const Jid& jid) { | |
135 this->node_name_ = jid.node_name_; | |
136 this->domain_name_ = jid.domain_name_; | |
137 this->resource_name_ = jid.resource_name_; | |
138 } | |
139 | |
140 bool Jid::operator==(const Jid& other) const { | |
141 return other.node_name_ == node_name_ && | |
142 other.domain_name_ == domain_name_ && | |
143 other.resource_name_ == resource_name_; | |
144 } | |
145 | |
146 int Jid::Compare(const Jid& other) const { | |
147 int compare_result; | |
148 compare_result = node_name_.compare(other.node_name_); | |
149 if (0 != compare_result) | |
150 return compare_result; | |
151 compare_result = domain_name_.compare(other.domain_name_); | |
152 if (0 != compare_result) | |
153 return compare_result; | |
154 compare_result = resource_name_.compare(other.resource_name_); | |
155 return compare_result; | |
156 } | |
157 | |
158 // --- JID parsing code: --- | |
159 | |
160 // Checks and normalizes the node part of a JID. | |
161 std::string Jid::PrepNode(const std::string& node, bool* valid) { | |
162 *valid = false; | |
163 std::string result; | |
164 | |
165 for (std::string::const_iterator i = node.begin(); i < node.end(); ++i) { | |
166 bool char_valid = true; | |
167 unsigned char ch = *i; | |
168 if (ch <= 0x7F) { | |
169 result += PrepNodeAscii(ch, &char_valid); | |
170 } | |
171 else { | |
172 // TODO: implement the correct stringprep protocol for these | |
173 result += tolower(ch); | |
174 } | |
175 if (!char_valid) { | |
176 return STR_EMPTY; | |
177 } | |
178 } | |
179 | |
180 if (result.length() > 1023) { | |
181 return STR_EMPTY; | |
182 } | |
183 *valid = true; | |
184 return result; | |
185 } | |
186 | |
187 | |
188 // Returns the appropriate mapping for an ASCII character in a node. | |
189 char Jid::PrepNodeAscii(char ch, bool* valid) { | |
190 *valid = true; | |
191 switch (ch) { | |
192 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': | |
193 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': | |
194 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': | |
195 case 'V': case 'W': case 'X': case 'Y': case 'Z': | |
196 return (char)(ch + ('a' - 'A')); | |
197 | |
198 case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: | |
199 case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: | |
200 case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11: | |
201 case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: | |
202 case ' ': case '&': case '/': case ':': case '<': case '>': case '@': | |
203 case '\"': case '\'': | |
204 case 0x7F: | |
205 *valid = false; | |
206 return 0; | |
207 | |
208 default: | |
209 return ch; | |
210 } | |
211 } | |
212 | |
213 | |
214 // Checks and normalizes the resource part of a JID. | |
215 std::string Jid::PrepResource(const std::string& resource, bool* valid) { | |
216 *valid = false; | |
217 std::string result; | |
218 | |
219 for (std::string::const_iterator i = resource.begin(); | |
220 i < resource.end(); ++i) { | |
221 bool char_valid = true; | |
222 unsigned char ch = *i; | |
223 if (ch <= 0x7F) { | |
224 result += PrepResourceAscii(ch, &char_valid); | |
225 } | |
226 else { | |
227 // TODO: implement the correct stringprep protocol for these | |
228 result += ch; | |
229 } | |
230 } | |
231 | |
232 if (result.length() > 1023) { | |
233 return STR_EMPTY; | |
234 } | |
235 *valid = true; | |
236 return result; | |
237 } | |
238 | |
239 // Returns the appropriate mapping for an ASCII character in a resource. | |
240 char Jid::PrepResourceAscii(char ch, bool* valid) { | |
241 *valid = true; | |
242 switch (ch) { | |
243 case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: | |
244 case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: | |
245 case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11: | |
246 case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: | |
247 case 0x7F: | |
248 *valid = false; | |
249 return 0; | |
250 | |
251 default: | |
252 return ch; | |
253 } | |
254 } | |
255 | |
256 // Checks and normalizes the domain part of a JID. | |
257 std::string Jid::PrepDomain(const std::string& domain, bool* valid) { | |
258 *valid = false; | |
259 std::string result; | |
260 | |
261 // TODO: if the domain contains a ':', then we should parse it | |
262 // as an IPv6 address rather than giving an error about illegal domain. | |
263 PrepDomain(domain, &result, valid); | |
264 if (!*valid) { | |
265 return STR_EMPTY; | |
266 } | |
267 | |
268 if (result.length() > 1023) { | |
269 return STR_EMPTY; | |
270 } | |
271 *valid = true; | |
272 return result; | |
273 } | |
274 | |
275 | |
276 // Checks and normalizes an IDNA domain. | |
277 void Jid::PrepDomain(const std::string& domain, std::string* buf, bool* valid) { | |
278 *valid = false; | |
279 std::string::const_iterator last = domain.begin(); | |
280 for (std::string::const_iterator i = domain.begin(); i < domain.end(); ++i) { | |
281 bool label_valid = true; | |
282 char ch = *i; | |
283 switch (ch) { | |
284 case 0x002E: | |
285 #if 0 // FIX: This isn't UTF-8-aware. | |
286 case 0x3002: | |
287 case 0xFF0E: | |
288 case 0xFF61: | |
289 #endif | |
290 PrepDomainLabel(last, i, buf, &label_valid); | |
291 *buf += '.'; | |
292 last = i + 1; | |
293 break; | |
294 } | |
295 if (!label_valid) { | |
296 return; | |
297 } | |
298 } | |
299 PrepDomainLabel(last, domain.end(), buf, valid); | |
300 } | |
301 | |
302 // Checks and normalizes a domain label. | |
303 void Jid::PrepDomainLabel( | |
304 std::string::const_iterator start, std::string::const_iterator end, | |
305 std::string* buf, bool* valid) { | |
306 *valid = false; | |
307 | |
308 int start_len = static_cast<int>(buf->length()); | |
309 for (std::string::const_iterator i = start; i < end; ++i) { | |
310 bool char_valid = true; | |
311 unsigned char ch = *i; | |
312 if (ch <= 0x7F) { | |
313 *buf += PrepDomainLabelAscii(ch, &char_valid); | |
314 } | |
315 else { | |
316 // TODO: implement ToASCII for these | |
317 *buf += ch; | |
318 } | |
319 if (!char_valid) { | |
320 return; | |
321 } | |
322 } | |
323 | |
324 int count = static_cast<int>(buf->length() - start_len); | |
325 if (count == 0) { | |
326 return; | |
327 } | |
328 else if (count > 63) { | |
329 return; | |
330 } | |
331 | |
332 // Is this check needed? See comment in PrepDomainLabelAscii. | |
333 if ((*buf)[start_len] == '-') { | |
334 return; | |
335 } | |
336 if ((*buf)[buf->length() - 1] == '-') { | |
337 return; | |
338 } | |
339 *valid = true; | |
340 } | |
341 | |
342 | |
343 // Returns the appropriate mapping for an ASCII character in a domain label. | |
344 char Jid::PrepDomainLabelAscii(char ch, bool* valid) { | |
345 *valid = true; | |
346 // TODO: A literal reading of the spec seems to say that we do | |
347 // not need to check for these illegal characters (an "internationalized | |
348 // domain label" runs ToASCII with UseSTD3... set to false). But that | |
349 // can't be right. We should at least be checking that there are no '/' | |
350 // or '@' characters in the domain. Perhaps we should see what others | |
351 // do in this case. | |
352 | |
353 switch (ch) { | |
354 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': | |
355 case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': | |
356 case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': | |
357 case 'V': case 'W': case 'X': case 'Y': case 'Z': | |
358 return (char)(ch + ('a' - 'A')); | |
359 | |
360 case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: | |
361 case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: | |
362 case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11: | |
363 case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: | |
364 case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: | |
365 case 0x1E: case 0x1F: case 0x20: case 0x21: case 0x22: case 0x23: | |
366 case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: | |
367 case 0x2A: case 0x2B: case 0x2C: case 0x2E: case 0x2F: case 0x3A: | |
368 case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: case 0x40: | |
369 case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: case 0x60: | |
370 case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: | |
371 *valid = false; | |
372 return 0; | |
373 | |
374 default: | |
375 return ch; | |
376 } | |
377 } | |
378 | |
379 } // namespace buzz | |
OLD | NEW |