uri_parser 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +6 -0
- data/.rvmrc +1 -0
- data/Gemfile +6 -0
- data/Rakefile +13 -0
- data/ext/uri_parser/basictypes.h +89 -0
- data/ext/uri_parser/extconf.h +6 -0
- data/ext/uri_parser/extconf.rb +50 -0
- data/ext/uri_parser/logging.h +5 -0
- data/ext/uri_parser/scoped_ptr.h +322 -0
- data/ext/uri_parser/string16.cc +95 -0
- data/ext/uri_parser/string16.h +194 -0
- data/ext/uri_parser/uri_parser.cc +87 -0
- data/ext/uri_parser/url_canon.h +872 -0
- data/ext/uri_parser/url_canon_etc.cc +392 -0
- data/ext/uri_parser/url_canon_fileurl.cc +215 -0
- data/ext/uri_parser/url_canon_host.cc +401 -0
- data/ext/uri_parser/url_canon_icu.cc +207 -0
- data/ext/uri_parser/url_canon_icu.h +63 -0
- data/ext/uri_parser/url_canon_internal.cc +427 -0
- data/ext/uri_parser/url_canon_internal.h +453 -0
- data/ext/uri_parser/url_canon_internal_file.h +157 -0
- data/ext/uri_parser/url_canon_ip.cc +737 -0
- data/ext/uri_parser/url_canon_ip.h +101 -0
- data/ext/uri_parser/url_canon_mailtourl.cc +137 -0
- data/ext/uri_parser/url_canon_path.cc +380 -0
- data/ext/uri_parser/url_canon_pathurl.cc +128 -0
- data/ext/uri_parser/url_canon_query.cc +189 -0
- data/ext/uri_parser/url_canon_relative.cc +572 -0
- data/ext/uri_parser/url_canon_stdstring.h +134 -0
- data/ext/uri_parser/url_canon_stdurl.cc +211 -0
- data/ext/uri_parser/url_common.h +48 -0
- data/ext/uri_parser/url_file.h +108 -0
- data/ext/uri_parser/url_parse.cc +760 -0
- data/ext/uri_parser/url_parse.h +336 -0
- data/ext/uri_parser/url_parse_file.cc +243 -0
- data/ext/uri_parser/url_parse_internal.h +112 -0
- data/ext/uri_parser/url_util.cc +553 -0
- data/ext/uri_parser/url_util.h +222 -0
- data/lib/uri_parser.rb +28 -0
- data/lib/uri_parser/version.rb +3 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/uri_parser_spec.rb +54 -0
- data/uri_parser.gemspec +26 -0
- metadata +117 -0
@@ -0,0 +1,157 @@
|
|
1
|
+
// Copyright 2007, Google Inc.
|
2
|
+
// All rights reserved.
|
3
|
+
//
|
4
|
+
// Redistribution and use in source and binary forms, with or without
|
5
|
+
// modification, are permitted provided that the following conditions are
|
6
|
+
// met:
|
7
|
+
//
|
8
|
+
// * Redistributions of source code must retain the above copyright
|
9
|
+
// notice, this list of conditions and the following disclaimer.
|
10
|
+
// * Redistributions in binary form must reproduce the above
|
11
|
+
// copyright notice, this list of conditions and the following disclaimer
|
12
|
+
// in the documentation and/or other materials provided with the
|
13
|
+
// distribution.
|
14
|
+
// * Neither the name of Google Inc. nor the names of its
|
15
|
+
// contributors may be used to endorse or promote products derived from
|
16
|
+
// this software without specific prior written permission.
|
17
|
+
//
|
18
|
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
19
|
+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
20
|
+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
21
|
+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
22
|
+
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
23
|
+
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
24
|
+
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
26
|
+
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
27
|
+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
|
30
|
+
// As with url_canon_internal.h, this file is intended to be included in
|
31
|
+
// another C++ file where the template types are defined. This allows the
|
32
|
+
// programmer to use this to use these functions for their own strings
|
33
|
+
// types, without bloating the code by having inline templates used in
|
34
|
+
// every call site.
|
35
|
+
//
|
36
|
+
// *** This file must be included after url_canon_internal as we depend on some
|
37
|
+
// functions in it. ***
|
38
|
+
|
39
|
+
#ifndef GOOGLEURL_SRC_URL_CANON_INTERNAL_FILE_H__
|
40
|
+
#define GOOGLEURL_SRC_URL_CANON_INTERNAL_FILE_H__
|
41
|
+
|
42
|
+
#include "url_file.h"
|
43
|
+
#include "url_parse_internal.h"
|
44
|
+
|
45
|
+
using namespace url_canon;
|
46
|
+
|
47
|
+
// Given a pointer into the spec, this copies and canonicalizes the drive
|
48
|
+
// letter and colon to the output, if one is found. If there is not a drive
|
49
|
+
// spec, it won't do anything. The index of the next character in the input
|
50
|
+
// spec is returned (after the colon when a drive spec is found, the begin
|
51
|
+
// offset if one is not).
|
52
|
+
template<typename CHAR>
|
53
|
+
static int FileDoDriveSpec(const CHAR* spec, int begin, int end,
|
54
|
+
CanonOutput* output) {
|
55
|
+
// The path could be one of several things: /foo/bar, c:/foo/bar, /c:/foo,
|
56
|
+
// (with backslashes instead of slashes as well).
|
57
|
+
int num_slashes = CountConsecutiveSlashes(spec, begin, end);
|
58
|
+
int after_slashes = begin + num_slashes;
|
59
|
+
|
60
|
+
if (!DoesBeginWindowsDriveSpec(spec, after_slashes, end))
|
61
|
+
return begin; // Haven't consumed any characters
|
62
|
+
|
63
|
+
// DoesBeginWindowsDriveSpec will ensure that the drive letter is valid
|
64
|
+
// and that it is followed by a colon/pipe.
|
65
|
+
|
66
|
+
// Normalize Windows drive letters to uppercase
|
67
|
+
if (spec[after_slashes] >= 'a' && spec[after_slashes] <= 'z')
|
68
|
+
output->push_back(spec[after_slashes] - 'a' + 'A');
|
69
|
+
else
|
70
|
+
output->push_back(static_cast<char>(spec[after_slashes]));
|
71
|
+
|
72
|
+
// Normalize the character following it to a colon rather than pipe.
|
73
|
+
output->push_back(':');
|
74
|
+
output->push_back('/');
|
75
|
+
return after_slashes + 2;
|
76
|
+
}
|
77
|
+
|
78
|
+
// FileDoDriveSpec will have already added the first backslash, so we need to
|
79
|
+
// write everything following the slashes using the path canonicalizer.
|
80
|
+
template<typename CHAR, typename UCHAR>
|
81
|
+
static void FileDoPath(const CHAR* spec, int begin, int end,
|
82
|
+
CanonOutput* output) {
|
83
|
+
// Normalize the number of slashes after the drive letter. The path
|
84
|
+
// canonicalizer expects the input to begin in a slash already so
|
85
|
+
// doesn't check. We want to handle no-slashes
|
86
|
+
int num_slashes = CountConsecutiveSlashes(spec, begin, end);
|
87
|
+
int after_slashes = begin + num_slashes;
|
88
|
+
|
89
|
+
// Now use the regular path canonicalizer to canonicalize the rest of the
|
90
|
+
// path. We supply it with the path following the slashes. It won't prepend
|
91
|
+
// a slash because it assumes any nonempty path already starts with one.
|
92
|
+
// We explicitly filter out calls with no path here to prevent that case.
|
93
|
+
ParsedURL::Component sub_path(after_slashes, end - after_slashes);
|
94
|
+
if (sub_path.len > 0) {
|
95
|
+
// Give it a fake output component to write into. DoCanonicalizeFile will
|
96
|
+
// compute the full path component.
|
97
|
+
ParsedURL::Component fake_output_path;
|
98
|
+
URLCanonInternal<CHAR, UCHAR>::DoPath(
|
99
|
+
spec, sub_path, output, &fake_output_path);
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
template<typename CHAR, typename UCHAR>
|
104
|
+
static bool DoCanonicalizeFileURL(const URLComponentSource<CHAR>& source,
|
105
|
+
const ParsedURL& parsed,
|
106
|
+
CanonOutput* output,
|
107
|
+
ParsedURL* new_parsed) {
|
108
|
+
// Things we don't set in file: URLs.
|
109
|
+
new_parsed->username = ParsedURL::Component(0, -1);
|
110
|
+
new_parsed->password = ParsedURL::Component(0, -1);
|
111
|
+
new_parsed->port = ParsedURL::Component(0, -1);
|
112
|
+
|
113
|
+
// Scheme (known, so we don't bother running it through the more
|
114
|
+
// complicated scheme canonicalizer).
|
115
|
+
new_parsed->scheme.begin = output->length();
|
116
|
+
output->push_back('f');
|
117
|
+
output->push_back('i');
|
118
|
+
output->push_back('l');
|
119
|
+
output->push_back('e');
|
120
|
+
new_parsed->scheme.len = output->length() - new_parsed->scheme.begin;
|
121
|
+
output->push_back(':');
|
122
|
+
|
123
|
+
// Write the separator for the host.
|
124
|
+
output->push_back('/');
|
125
|
+
output->push_back('/');
|
126
|
+
|
127
|
+
// Append the host. For many file URLs, this will be empty. For UNC, this
|
128
|
+
// will be present.
|
129
|
+
// TODO(brettw) This doesn't do any checking for host name validity. We
|
130
|
+
// should probably handle validity checking of UNC hosts differently than
|
131
|
+
// for regular IP hosts.
|
132
|
+
bool success = URLCanonInternal<CHAR, UCHAR>::DoHost(
|
133
|
+
source.host, parsed.host, output, &new_parsed->host);
|
134
|
+
|
135
|
+
// Write a separator for the start of the path. We'll ignore any slashes
|
136
|
+
// already at the beginning of the path.
|
137
|
+
new_parsed->path.begin = output->length();
|
138
|
+
output->push_back('/');
|
139
|
+
|
140
|
+
// Copies and normalizes the "c:" at the beginning, if present.
|
141
|
+
int after_drive = FileDoDriveSpec(source.path, parsed.path.begin,
|
142
|
+
parsed.path.end(), output);
|
143
|
+
|
144
|
+
// Copies the rest of the path
|
145
|
+
FileDoPath<CHAR, UCHAR>(source.path, after_drive, parsed.path.end(), output);
|
146
|
+
new_parsed->path.len = output->length() - new_parsed->path.begin;
|
147
|
+
|
148
|
+
// Things following the path we can use the standard canonicalizers for.
|
149
|
+
success &= URLCanonInternal<CHAR, UCHAR>::DoQuery(
|
150
|
+
source.query, parsed.query, output, &new_parsed->query);
|
151
|
+
success &= URLCanonInternal<CHAR, UCHAR>::DoRef(
|
152
|
+
source.ref, parsed.ref, output, &new_parsed->ref);
|
153
|
+
|
154
|
+
return success;
|
155
|
+
}
|
156
|
+
|
157
|
+
#endif // GOOGLEURL_SRC_URL_CANON_INTERNAL_FILE_H__
|
@@ -0,0 +1,737 @@
|
|
1
|
+
// Copyright 2009, Google Inc.
|
2
|
+
// All rights reserved.
|
3
|
+
//
|
4
|
+
// Redistribution and use in source and binary forms, with or without
|
5
|
+
// modification, are permitted provided that the following conditions are
|
6
|
+
// met:
|
7
|
+
//
|
8
|
+
// * Redistributions of source code must retain the above copyright
|
9
|
+
// notice, this list of conditions and the following disclaimer.
|
10
|
+
// * Redistributions in binary form must reproduce the above
|
11
|
+
// copyright notice, this list of conditions and the following disclaimer
|
12
|
+
// in the documentation and/or other materials provided with the
|
13
|
+
// distribution.
|
14
|
+
// * Neither the name of Google Inc. nor the names of its
|
15
|
+
// contributors may be used to endorse or promote products derived from
|
16
|
+
// this software without specific prior written permission.
|
17
|
+
//
|
18
|
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
19
|
+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
20
|
+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
21
|
+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
22
|
+
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
23
|
+
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
24
|
+
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
26
|
+
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
27
|
+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
|
30
|
+
#include "url_canon_ip.h"
|
31
|
+
|
32
|
+
#include <stdlib.h>
|
33
|
+
|
34
|
+
#include "basictypes.h"
|
35
|
+
#include "logging.h"
|
36
|
+
#include "url_canon_internal.h"
|
37
|
+
|
38
|
+
namespace url_canon {
|
39
|
+
|
40
|
+
namespace {
|
41
|
+
|
42
|
+
// Converts one of the character types that represent a numerical base to the
|
43
|
+
// corresponding base.
|
44
|
+
int BaseForType(SharedCharTypes type) {
|
45
|
+
switch (type) {
|
46
|
+
case CHAR_HEX:
|
47
|
+
return 16;
|
48
|
+
case CHAR_DEC:
|
49
|
+
return 10;
|
50
|
+
case CHAR_OCT:
|
51
|
+
return 8;
|
52
|
+
default:
|
53
|
+
return 0;
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
template<typename CHAR, typename UCHAR>
|
58
|
+
bool DoFindIPv4Components(const CHAR* spec,
|
59
|
+
const url_parse::Component& host,
|
60
|
+
url_parse::Component components[4]) {
|
61
|
+
if (!host.is_nonempty())
|
62
|
+
return false;
|
63
|
+
|
64
|
+
int cur_component = 0; // Index of the component we're working on.
|
65
|
+
int cur_component_begin = host.begin; // Start of the current component.
|
66
|
+
int end = host.end();
|
67
|
+
for (int i = host.begin; /* nothing */; i++) {
|
68
|
+
if (i >= end || spec[i] == '.') {
|
69
|
+
// Found the end of the current component.
|
70
|
+
int component_len = i - cur_component_begin;
|
71
|
+
components[cur_component] =
|
72
|
+
url_parse::Component(cur_component_begin, component_len);
|
73
|
+
|
74
|
+
// The next component starts after the dot.
|
75
|
+
cur_component_begin = i + 1;
|
76
|
+
cur_component++;
|
77
|
+
|
78
|
+
// Don't allow empty components (two dots in a row), except we may
|
79
|
+
// allow an empty component at the end (this would indicate that the
|
80
|
+
// input ends in a dot). We also want to error if the component is
|
81
|
+
// empty and it's the only component (cur_component == 1).
|
82
|
+
if (component_len == 0 && (i < end || cur_component == 1))
|
83
|
+
return false;
|
84
|
+
|
85
|
+
if (i >= end)
|
86
|
+
break; // End of the input.
|
87
|
+
|
88
|
+
if (cur_component == 4) {
|
89
|
+
// Anything else after the 4th component is an error unless it is a
|
90
|
+
// dot that would otherwise be treated as the end of input.
|
91
|
+
if (spec[i] == '.' && i + 1 == end)
|
92
|
+
break;
|
93
|
+
return false;
|
94
|
+
}
|
95
|
+
} else if (static_cast<UCHAR>(spec[i]) >= 0x80 ||
|
96
|
+
!IsIPv4Char(static_cast<unsigned char>(spec[i]))) {
|
97
|
+
// Invalid character for an IPv4 address.
|
98
|
+
return false;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
// Fill in any unused components.
|
103
|
+
while (cur_component < 4)
|
104
|
+
components[cur_component++] = url_parse::Component();
|
105
|
+
return true;
|
106
|
+
}
|
107
|
+
|
108
|
+
// Converts an IPv4 component to a 32-bit number, while checking for overflow.
|
109
|
+
//
|
110
|
+
// Possible return values:
|
111
|
+
// - IPV4 - The number was valid, and did not overflow.
|
112
|
+
// - BROKEN - The input was numeric, but too large for a 32-bit field.
|
113
|
+
// - NEUTRAL - Input was not numeric.
|
114
|
+
//
|
115
|
+
// The input is assumed to be ASCII. FindIPv4Components should have stripped
|
116
|
+
// out any input that is greater than 7 bits. The components are assumed
|
117
|
+
// to be non-empty.
|
118
|
+
template<typename CHAR>
|
119
|
+
CanonHostInfo::Family IPv4ComponentToNumber(
|
120
|
+
const CHAR* spec,
|
121
|
+
const url_parse::Component& component,
|
122
|
+
uint32* number) {
|
123
|
+
// Figure out the base
|
124
|
+
SharedCharTypes base;
|
125
|
+
int base_prefix_len = 0; // Size of the prefix for this base.
|
126
|
+
if (spec[component.begin] == '0') {
|
127
|
+
// Either hex or dec, or a standalone zero.
|
128
|
+
if (component.len == 1) {
|
129
|
+
base = CHAR_DEC;
|
130
|
+
} else if (spec[component.begin + 1] == 'X' ||
|
131
|
+
spec[component.begin + 1] == 'x') {
|
132
|
+
base = CHAR_HEX;
|
133
|
+
base_prefix_len = 2;
|
134
|
+
} else {
|
135
|
+
base = CHAR_OCT;
|
136
|
+
base_prefix_len = 1;
|
137
|
+
}
|
138
|
+
} else {
|
139
|
+
base = CHAR_DEC;
|
140
|
+
}
|
141
|
+
|
142
|
+
// Extend the prefix to consume all leading zeros.
|
143
|
+
while (base_prefix_len < component.len &&
|
144
|
+
spec[component.begin + base_prefix_len] == '0')
|
145
|
+
base_prefix_len++;
|
146
|
+
|
147
|
+
// Put the component, minus any base prefix, into a NULL-terminated buffer so
|
148
|
+
// we can call the standard library. Because leading zeros have already been
|
149
|
+
// discarded, filling the entire buffer is guaranteed to trigger the 32-bit
|
150
|
+
// overflow check.
|
151
|
+
const int kMaxComponentLen = 16;
|
152
|
+
char buf[kMaxComponentLen + 1]; // digits + '\0'
|
153
|
+
int dest_i = 0;
|
154
|
+
for (int i = component.begin + base_prefix_len; i < component.end(); i++) {
|
155
|
+
// We know the input is 7-bit, so convert to narrow (if this is the wide
|
156
|
+
// version of the template) by casting.
|
157
|
+
char input = static_cast<char>(spec[i]);
|
158
|
+
|
159
|
+
// Validate that this character is OK for the given base.
|
160
|
+
if (!IsCharOfType(input, base))
|
161
|
+
return CanonHostInfo::NEUTRAL;
|
162
|
+
|
163
|
+
// Fill the buffer, if there's space remaining. This check allows us to
|
164
|
+
// verify that all characters are numeric, even those that don't fit.
|
165
|
+
if (dest_i < kMaxComponentLen)
|
166
|
+
buf[dest_i++] = input;
|
167
|
+
}
|
168
|
+
|
169
|
+
buf[dest_i] = '\0';
|
170
|
+
|
171
|
+
// Use the 64-bit strtoi so we get a big number (no hex, decimal, or octal
|
172
|
+
// number can overflow a 64-bit number in <= 16 characters).
|
173
|
+
uint64 num = _strtoui64(buf, NULL, BaseForType(base));
|
174
|
+
|
175
|
+
// Check for 32-bit overflow.
|
176
|
+
if (num > kuint32max)
|
177
|
+
return CanonHostInfo::BROKEN;
|
178
|
+
|
179
|
+
// No overflow. Success!
|
180
|
+
*number = static_cast<uint32>(num);
|
181
|
+
return CanonHostInfo::IPV4;
|
182
|
+
}
|
183
|
+
|
184
|
+
// Writes the given address (with each character representing one dotted
|
185
|
+
// part of an IPv4 address) to the output, and updating |*out_host| to
|
186
|
+
// identify the added portion.
|
187
|
+
void AppendIPv4Address(const unsigned char address[4],
|
188
|
+
CanonOutput* output,
|
189
|
+
url_parse::Component* out_host) {
|
190
|
+
out_host->begin = output->length();
|
191
|
+
for (int i = 0; i < 4; i++) {
|
192
|
+
char str[16];
|
193
|
+
_itoa_s(address[i], str, 10);
|
194
|
+
|
195
|
+
for (int ch = 0; str[ch] != 0; ch++)
|
196
|
+
output->push_back(str[ch]);
|
197
|
+
|
198
|
+
if (i != 3)
|
199
|
+
output->push_back('.');
|
200
|
+
}
|
201
|
+
out_host->len = output->length() - out_host->begin;
|
202
|
+
}
|
203
|
+
|
204
|
+
// See declaration of IPv4AddressToNumber for documentation.
|
205
|
+
template<typename CHAR>
|
206
|
+
CanonHostInfo::Family DoIPv4AddressToNumber(const CHAR* spec,
|
207
|
+
const url_parse::Component& host,
|
208
|
+
unsigned char address[4],
|
209
|
+
int* num_ipv4_components) {
|
210
|
+
// The identified components. Not all may exist.
|
211
|
+
url_parse::Component components[4];
|
212
|
+
if (!FindIPv4Components(spec, host, components))
|
213
|
+
return CanonHostInfo::NEUTRAL;
|
214
|
+
|
215
|
+
// Convert existing components to digits. Values up to
|
216
|
+
// |existing_components| will be valid.
|
217
|
+
uint32 component_values[4];
|
218
|
+
int existing_components = 0;
|
219
|
+
for (int i = 0; i < 4; i++) {
|
220
|
+
if (components[i].len <= 0)
|
221
|
+
continue;
|
222
|
+
CanonHostInfo::Family family = IPv4ComponentToNumber(
|
223
|
+
spec, components[i], &component_values[existing_components]);
|
224
|
+
|
225
|
+
// Stop if we hit an invalid non-empty component.
|
226
|
+
if (family != CanonHostInfo::IPV4)
|
227
|
+
return family;
|
228
|
+
|
229
|
+
existing_components++;
|
230
|
+
}
|
231
|
+
|
232
|
+
// Use that sequence of numbers to fill out the 4-component IP address.
|
233
|
+
|
234
|
+
// First, process all components but the last, while making sure each fits
|
235
|
+
// within an 8-bit field.
|
236
|
+
for (int i = 0; i < existing_components - 1; i++) {
|
237
|
+
if (component_values[i] > kuint8max)
|
238
|
+
return CanonHostInfo::BROKEN;
|
239
|
+
address[i] = static_cast<unsigned char>(component_values[i]);
|
240
|
+
}
|
241
|
+
|
242
|
+
// Next, consume the last component to fill in the remaining bytes.
|
243
|
+
uint32 last_value = component_values[existing_components - 1];
|
244
|
+
for (int i = 3; i >= existing_components - 1; i--) {
|
245
|
+
address[i] = static_cast<unsigned char>(last_value);
|
246
|
+
last_value >>= 8;
|
247
|
+
}
|
248
|
+
|
249
|
+
// If the last component has residual bits, report overflow.
|
250
|
+
if (last_value != 0)
|
251
|
+
return CanonHostInfo::BROKEN;
|
252
|
+
|
253
|
+
// Tell the caller how many components we saw.
|
254
|
+
*num_ipv4_components = existing_components;
|
255
|
+
|
256
|
+
// Success!
|
257
|
+
return CanonHostInfo::IPV4;
|
258
|
+
}
|
259
|
+
|
260
|
+
// Return true if we've made a final IPV4/BROKEN decision, false if the result
|
261
|
+
// is NEUTRAL, and we could use a second opinion.
|
262
|
+
template<typename CHAR, typename UCHAR>
|
263
|
+
bool DoCanonicalizeIPv4Address(const CHAR* spec,
|
264
|
+
const url_parse::Component& host,
|
265
|
+
CanonOutput* output,
|
266
|
+
CanonHostInfo* host_info) {
|
267
|
+
unsigned char address[4];
|
268
|
+
host_info->family = IPv4AddressToNumber(
|
269
|
+
spec, host, address, &host_info->num_ipv4_components);
|
270
|
+
|
271
|
+
switch (host_info->family) {
|
272
|
+
case CanonHostInfo::IPV4:
|
273
|
+
// Definitely an IPv4 address.
|
274
|
+
AppendIPv4Address(address, output, &host_info->out_host);
|
275
|
+
return true;
|
276
|
+
case CanonHostInfo::BROKEN:
|
277
|
+
// Definitely broken.
|
278
|
+
return true;
|
279
|
+
default:
|
280
|
+
// Could be IPv6 or a hostname.
|
281
|
+
return false;
|
282
|
+
}
|
283
|
+
}
|
284
|
+
|
285
|
+
// Helper class that describes the main components of an IPv6 input string.
|
286
|
+
// See the following examples to understand how it breaks up an input string:
|
287
|
+
//
|
288
|
+
// [Example 1]: input = "[::aa:bb]"
|
289
|
+
// ==> num_hex_components = 2
|
290
|
+
// ==> hex_components[0] = Component(3,2) "aa"
|
291
|
+
// ==> hex_components[1] = Component(6,2) "bb"
|
292
|
+
// ==> index_of_contraction = 0
|
293
|
+
// ==> ipv4_component = Component(0, -1)
|
294
|
+
//
|
295
|
+
// [Example 2]: input = "[1:2::3:4:5]"
|
296
|
+
// ==> num_hex_components = 5
|
297
|
+
// ==> hex_components[0] = Component(1,1) "1"
|
298
|
+
// ==> hex_components[1] = Component(3,1) "2"
|
299
|
+
// ==> hex_components[2] = Component(6,1) "3"
|
300
|
+
// ==> hex_components[3] = Component(8,1) "4"
|
301
|
+
// ==> hex_components[4] = Component(10,1) "5"
|
302
|
+
// ==> index_of_contraction = 2
|
303
|
+
// ==> ipv4_component = Component(0, -1)
|
304
|
+
//
|
305
|
+
// [Example 3]: input = "[::ffff:192.168.0.1]"
|
306
|
+
// ==> num_hex_components = 1
|
307
|
+
// ==> hex_components[0] = Component(3,4) "ffff"
|
308
|
+
// ==> index_of_contraction = 0
|
309
|
+
// ==> ipv4_component = Component(8, 11) "192.168.0.1"
|
310
|
+
//
|
311
|
+
// [Example 4]: input = "[1::]"
|
312
|
+
// ==> num_hex_components = 1
|
313
|
+
// ==> hex_components[0] = Component(1,1) "1"
|
314
|
+
// ==> index_of_contraction = 1
|
315
|
+
// ==> ipv4_component = Component(0, -1)
|
316
|
+
//
|
317
|
+
// [Example 5]: input = "[::192.168.0.1]"
|
318
|
+
// ==> num_hex_components = 0
|
319
|
+
// ==> index_of_contraction = 0
|
320
|
+
// ==> ipv4_component = Component(8, 11) "192.168.0.1"
|
321
|
+
//
|
322
|
+
struct IPv6Parsed {
|
323
|
+
// Zero-out the parse information.
|
324
|
+
void reset() {
|
325
|
+
num_hex_components = 0;
|
326
|
+
index_of_contraction = -1;
|
327
|
+
ipv4_component.reset();
|
328
|
+
}
|
329
|
+
|
330
|
+
// There can be up to 8 hex components (colon separated) in the literal.
|
331
|
+
url_parse::Component hex_components[8];
|
332
|
+
|
333
|
+
// The count of hex components present. Ranges from [0,8].
|
334
|
+
int num_hex_components;
|
335
|
+
|
336
|
+
// The index of the hex component that the "::" contraction precedes, or
|
337
|
+
// -1 if there is no contraction.
|
338
|
+
int index_of_contraction;
|
339
|
+
|
340
|
+
// The range of characters which are an IPv4 literal.
|
341
|
+
url_parse::Component ipv4_component;
|
342
|
+
};
|
343
|
+
|
344
|
+
// Parse the IPv6 input string. If parsing succeeded returns true and fills
|
345
|
+
// |parsed| with the information. If parsing failed (because the input is
|
346
|
+
// invalid) returns false.
|
347
|
+
template<typename CHAR, typename UCHAR>
|
348
|
+
bool DoParseIPv6(const CHAR* spec,
|
349
|
+
const url_parse::Component& host,
|
350
|
+
IPv6Parsed* parsed) {
|
351
|
+
// Zero-out the info.
|
352
|
+
parsed->reset();
|
353
|
+
|
354
|
+
if (!host.is_nonempty())
|
355
|
+
return false;
|
356
|
+
|
357
|
+
// The index for start and end of address range (no brackets).
|
358
|
+
int begin = host.begin;
|
359
|
+
int end = host.end();
|
360
|
+
|
361
|
+
int cur_component_begin = begin; // Start of the current component.
|
362
|
+
|
363
|
+
// Scan through the input, searching for hex components, "::" contractions,
|
364
|
+
// and IPv4 components.
|
365
|
+
for (int i = begin; /* i <= end */; i++) {
|
366
|
+
bool is_colon = spec[i] == ':';
|
367
|
+
bool is_contraction = is_colon && i < end - 1 && spec[i + 1] == ':';
|
368
|
+
|
369
|
+
// We reached the end of the current component if we encounter a colon
|
370
|
+
// (separator between hex components, or start of a contraction), or end of
|
371
|
+
// input.
|
372
|
+
if (is_colon || i == end) {
|
373
|
+
int component_len = i - cur_component_begin;
|
374
|
+
|
375
|
+
// A component should not have more than 4 hex digits.
|
376
|
+
if (component_len > 4)
|
377
|
+
return false;
|
378
|
+
|
379
|
+
// Don't allow empty components.
|
380
|
+
if (component_len == 0) {
|
381
|
+
// The exception is when contractions appear at beginning of the
|
382
|
+
// input or at the end of the input.
|
383
|
+
if (!((is_contraction && i == begin) || (i == end &&
|
384
|
+
parsed->index_of_contraction == parsed->num_hex_components)))
|
385
|
+
return false;
|
386
|
+
}
|
387
|
+
|
388
|
+
// Add the hex component we just found to running list.
|
389
|
+
if (component_len > 0) {
|
390
|
+
// Can't have more than 8 components!
|
391
|
+
if (parsed->num_hex_components >= 8)
|
392
|
+
return false;
|
393
|
+
|
394
|
+
parsed->hex_components[parsed->num_hex_components++] =
|
395
|
+
url_parse::Component(cur_component_begin, component_len);
|
396
|
+
}
|
397
|
+
}
|
398
|
+
|
399
|
+
if (i == end)
|
400
|
+
break; // Reached the end of the input, DONE.
|
401
|
+
|
402
|
+
// We found a "::" contraction.
|
403
|
+
if (is_contraction) {
|
404
|
+
// There can be at most one contraction in the literal.
|
405
|
+
if (parsed->index_of_contraction != -1)
|
406
|
+
return false;
|
407
|
+
parsed->index_of_contraction = parsed->num_hex_components;
|
408
|
+
++i; // Consume the colon we peeked.
|
409
|
+
}
|
410
|
+
|
411
|
+
if (is_colon) {
|
412
|
+
// Colons are separators between components, keep track of where the
|
413
|
+
// current component started (after this colon).
|
414
|
+
cur_component_begin = i + 1;
|
415
|
+
} else {
|
416
|
+
if (static_cast<UCHAR>(spec[i]) >= 0x80)
|
417
|
+
return false; // Not ASCII.
|
418
|
+
|
419
|
+
if (!IsHexChar(static_cast<unsigned char>(spec[i]))) {
|
420
|
+
// Regular components are hex numbers. It is also possible for
|
421
|
+
// a component to be an IPv4 address in dotted form.
|
422
|
+
if (IsIPv4Char(static_cast<unsigned char>(spec[i]))) {
|
423
|
+
// Since IPv4 address can only appear at the end, assume the rest
|
424
|
+
// of the string is an IPv4 address. (We will parse this separately
|
425
|
+
// later).
|
426
|
+
parsed->ipv4_component = url_parse::Component(
|
427
|
+
cur_component_begin, end - cur_component_begin);
|
428
|
+
break;
|
429
|
+
} else {
|
430
|
+
// The character was neither a hex digit, nor an IPv4 character.
|
431
|
+
return false;
|
432
|
+
}
|
433
|
+
}
|
434
|
+
}
|
435
|
+
}
|
436
|
+
|
437
|
+
return true;
|
438
|
+
}
|
439
|
+
|
440
|
+
// Verifies the parsed IPv6 information, checking that the various components
|
441
|
+
// add up to the right number of bits (hex components are 16 bits, while
|
442
|
+
// embedded IPv4 formats are 32 bits, and contractions are placeholdes for
|
443
|
+
// 16 or more bits). Returns true if sizes match up, false otherwise. On
|
444
|
+
// success writes the length of the contraction (if any) to
|
445
|
+
// |out_num_bytes_of_contraction|.
|
446
|
+
bool CheckIPv6ComponentsSize(const IPv6Parsed& parsed,
|
447
|
+
int* out_num_bytes_of_contraction) {
|
448
|
+
// Each group of four hex digits contributes 16 bits.
|
449
|
+
int num_bytes_without_contraction = parsed.num_hex_components * 2;
|
450
|
+
|
451
|
+
// If an IPv4 address was embedded at the end, it contributes 32 bits.
|
452
|
+
if (parsed.ipv4_component.is_valid())
|
453
|
+
num_bytes_without_contraction += 4;
|
454
|
+
|
455
|
+
// If there was a "::" contraction, its size is going to be:
|
456
|
+
// MAX([16bits], [128bits] - num_bytes_without_contraction).
|
457
|
+
int num_bytes_of_contraction = 0;
|
458
|
+
if (parsed.index_of_contraction != -1) {
|
459
|
+
num_bytes_of_contraction = 16 - num_bytes_without_contraction;
|
460
|
+
if (num_bytes_of_contraction < 2)
|
461
|
+
num_bytes_of_contraction = 2;
|
462
|
+
}
|
463
|
+
|
464
|
+
// Check that the numbers add up.
|
465
|
+
if (num_bytes_without_contraction + num_bytes_of_contraction != 16)
|
466
|
+
return false;
|
467
|
+
|
468
|
+
*out_num_bytes_of_contraction = num_bytes_of_contraction;
|
469
|
+
return true;
|
470
|
+
}
|
471
|
+
|
472
|
+
// Converts a hex comonent into a number. This cannot fail since the caller has
|
473
|
+
// already verified that each character in the string was a hex digit, and
|
474
|
+
// that there were no more than 4 characters.
|
475
|
+
template<typename CHAR>
|
476
|
+
uint16 IPv6HexComponentToNumber(const CHAR* spec,
|
477
|
+
const url_parse::Component& component) {
|
478
|
+
DCHECK(component.len <= 4);
|
479
|
+
|
480
|
+
// Copy the hex string into a C-string.
|
481
|
+
char buf[5];
|
482
|
+
for (int i = 0; i < component.len; ++i)
|
483
|
+
buf[i] = static_cast<char>(spec[component.begin + i]);
|
484
|
+
buf[component.len] = '\0';
|
485
|
+
|
486
|
+
// Convert it to a number (overflow is not possible, since with 4 hex
|
487
|
+
// characters we can at most have a 16 bit number).
|
488
|
+
return static_cast<uint16>(_strtoui64(buf, NULL, 16));
|
489
|
+
}
|
490
|
+
|
491
|
+
// Converts an IPv6 address to a 128-bit number (network byte order), returning
|
492
|
+
// true on success. False means that the input was not a valid IPv6 address.
|
493
|
+
template<typename CHAR, typename UCHAR>
|
494
|
+
bool DoIPv6AddressToNumber(const CHAR* spec,
|
495
|
+
const url_parse::Component& host,
|
496
|
+
unsigned char address[16]) {
|
497
|
+
// Make sure the component is bounded by '[' and ']'.
|
498
|
+
int end = host.end();
|
499
|
+
if (!host.is_nonempty() || spec[host.begin] != '[' || spec[end - 1] != ']')
|
500
|
+
return false;
|
501
|
+
|
502
|
+
// Exclude the square brackets.
|
503
|
+
url_parse::Component ipv6_comp(host.begin + 1, host.len - 2);
|
504
|
+
|
505
|
+
// Parse the IPv6 address -- identify where all the colon separated hex
|
506
|
+
// components are, the "::" contraction, and the embedded IPv4 address.
|
507
|
+
IPv6Parsed ipv6_parsed;
|
508
|
+
if (!DoParseIPv6<CHAR, UCHAR>(spec, ipv6_comp, &ipv6_parsed))
|
509
|
+
return false;
|
510
|
+
|
511
|
+
// Do some basic size checks to make sure that the address doesn't
|
512
|
+
// specify more than 128 bits or fewer than 128 bits. This also resolves
|
513
|
+
// how may zero bytes the "::" contraction represents.
|
514
|
+
int num_bytes_of_contraction;
|
515
|
+
if (!CheckIPv6ComponentsSize(ipv6_parsed, &num_bytes_of_contraction))
|
516
|
+
return false;
|
517
|
+
|
518
|
+
int cur_index_in_address = 0;
|
519
|
+
|
520
|
+
// Loop through each hex components, and contraction in order.
|
521
|
+
for (int i = 0; i <= ipv6_parsed.num_hex_components; ++i) {
|
522
|
+
// Append the contraction if it appears before this component.
|
523
|
+
if (i == ipv6_parsed.index_of_contraction) {
|
524
|
+
for (int j = 0; j < num_bytes_of_contraction; ++j)
|
525
|
+
address[cur_index_in_address++] = 0;
|
526
|
+
}
|
527
|
+
// Append the hex component's value.
|
528
|
+
if (i != ipv6_parsed.num_hex_components) {
|
529
|
+
// Get the 16-bit value for this hex component.
|
530
|
+
uint16 number = IPv6HexComponentToNumber<CHAR>(
|
531
|
+
spec, ipv6_parsed.hex_components[i]);
|
532
|
+
// Append to |address|, in network byte order.
|
533
|
+
address[cur_index_in_address++] = (number & 0xFF00) >> 8;
|
534
|
+
address[cur_index_in_address++] = (number & 0x00FF);
|
535
|
+
}
|
536
|
+
}
|
537
|
+
|
538
|
+
// If there was an IPv4 section, convert it into a 32-bit number and append
|
539
|
+
// it to |address|.
|
540
|
+
if (ipv6_parsed.ipv4_component.is_valid()) {
|
541
|
+
// We only allow the embedded IPv4 syntax to be used for "compat" and
|
542
|
+
// "mapped" formats:
|
543
|
+
// "mapped" ==> 0:0:0:0:0:ffff:<IPv4-literal>
|
544
|
+
// "compat" ==> 0:0:0:0:0:0000:<IPv4-literal>
|
545
|
+
for (int j = 0; j < 10; ++j) {
|
546
|
+
if (address[j] != 0)
|
547
|
+
return false;
|
548
|
+
}
|
549
|
+
if (!((address[10] == 0 && address[11] == 0) ||
|
550
|
+
(address[10] == 0xFF && address[11] == 0xFF)))
|
551
|
+
return false;
|
552
|
+
|
553
|
+
// Append the 32-bit number to |address|.
|
554
|
+
int ignored_num_ipv4_components;
|
555
|
+
if (CanonHostInfo::IPV4 !=
|
556
|
+
IPv4AddressToNumber(spec,
|
557
|
+
ipv6_parsed.ipv4_component,
|
558
|
+
&address[cur_index_in_address],
|
559
|
+
&ignored_num_ipv4_components))
|
560
|
+
return false;
|
561
|
+
}
|
562
|
+
|
563
|
+
return true;
|
564
|
+
}
|
565
|
+
|
566
|
+
// Searches for the longest sequence of zeros in |address|, and writes the
|
567
|
+
// range into |contraction_range|. The run of zeros must be at least 16 bits,
|
568
|
+
// and if there is a tie the first is chosen.
|
569
|
+
void ChooseIPv6ContractionRange(const unsigned char address[16],
|
570
|
+
url_parse::Component* contraction_range) {
|
571
|
+
// The longest run of zeros in |address| seen so far.
|
572
|
+
url_parse::Component max_range;
|
573
|
+
|
574
|
+
// The current run of zeros in |address| being iterated over.
|
575
|
+
url_parse::Component cur_range;
|
576
|
+
|
577
|
+
for (int i = 0; i < 16; i += 2) {
|
578
|
+
// Test for 16 bits worth of zero.
|
579
|
+
bool is_zero = (address[i] == 0 && address[i + 1] == 0);
|
580
|
+
|
581
|
+
if (is_zero) {
|
582
|
+
// Add the zero to the current range (or start a new one).
|
583
|
+
if (!cur_range.is_valid())
|
584
|
+
cur_range = url_parse::Component(i, 0);
|
585
|
+
cur_range.len += 2;
|
586
|
+
}
|
587
|
+
|
588
|
+
if (!is_zero || i == 14) {
|
589
|
+
// Just completed a run of zeros. If the run is greater than 16 bits,
|
590
|
+
// it is a candidate for the contraction.
|
591
|
+
if (cur_range.len > 2 && cur_range.len > max_range.len) {
|
592
|
+
max_range = cur_range;
|
593
|
+
}
|
594
|
+
cur_range.reset();
|
595
|
+
}
|
596
|
+
}
|
597
|
+
*contraction_range = max_range;
|
598
|
+
}
|
599
|
+
|
600
|
+
// Return true if we've made a final IPV6/BROKEN decision, false if the result
|
601
|
+
// is NEUTRAL, and we could use a second opinion.
|
602
|
+
template<typename CHAR, typename UCHAR>
|
603
|
+
bool DoCanonicalizeIPv6Address(const CHAR* spec,
|
604
|
+
const url_parse::Component& host,
|
605
|
+
CanonOutput* output,
|
606
|
+
CanonHostInfo* host_info) {
|
607
|
+
// Turn the IP address into a 128 bit number.
|
608
|
+
unsigned char address[16];
|
609
|
+
if (!IPv6AddressToNumber(spec, host, address)) {
|
610
|
+
// If it's not an IPv6 address, scan for characters that should *only*
|
611
|
+
// exist in an IPv6 address.
|
612
|
+
for (int i = host.begin; i < host.end(); i++) {
|
613
|
+
switch (spec[i]) {
|
614
|
+
case '[':
|
615
|
+
case ']':
|
616
|
+
case ':':
|
617
|
+
host_info->family = CanonHostInfo::BROKEN;
|
618
|
+
return true;
|
619
|
+
}
|
620
|
+
}
|
621
|
+
|
622
|
+
// No invalid characters. Could still be IPv4 or a hostname.
|
623
|
+
host_info->family = CanonHostInfo::NEUTRAL;
|
624
|
+
return false;
|
625
|
+
}
|
626
|
+
|
627
|
+
host_info->out_host.begin = output->length();
|
628
|
+
output->push_back('[');
|
629
|
+
|
630
|
+
// We will now output the address according to the rules in:
|
631
|
+
// http://tools.ietf.org/html/draft-kawamura-ipv6-text-representation-01#section-4
|
632
|
+
|
633
|
+
// Start by finding where to place the "::" contraction (if any).
|
634
|
+
url_parse::Component contraction_range;
|
635
|
+
ChooseIPv6ContractionRange(address, &contraction_range);
|
636
|
+
|
637
|
+
for (int i = 0; i <= 14;) {
|
638
|
+
// We check 2 bytes at a time, from bytes (0, 1) to (14, 15), inclusive.
|
639
|
+
DCHECK(i % 2 == 0);
|
640
|
+
if (i == contraction_range.begin && contraction_range.len > 0) {
|
641
|
+
// Jump over the contraction.
|
642
|
+
if (i == 0)
|
643
|
+
output->push_back(':');
|
644
|
+
output->push_back(':');
|
645
|
+
i = contraction_range.end();
|
646
|
+
} else {
|
647
|
+
// Consume the next 16 bits from |address|.
|
648
|
+
int x = address[i] << 8 | address[i + 1];
|
649
|
+
|
650
|
+
i += 2;
|
651
|
+
|
652
|
+
// Stringify the 16 bit number (at most requires 4 hex digits).
|
653
|
+
char str[5];
|
654
|
+
_itoa_s(x, str, 16);
|
655
|
+
for (int ch = 0; str[ch] != 0; ++ch)
|
656
|
+
output->push_back(str[ch]);
|
657
|
+
|
658
|
+
// Put a colon after each number, except the last.
|
659
|
+
if (i < 16)
|
660
|
+
output->push_back(':');
|
661
|
+
}
|
662
|
+
}
|
663
|
+
|
664
|
+
output->push_back(']');
|
665
|
+
host_info->out_host.len = output->length() - host_info->out_host.begin;
|
666
|
+
|
667
|
+
host_info->family = CanonHostInfo::IPV6;
|
668
|
+
return true;
|
669
|
+
}
|
670
|
+
|
671
|
+
} // namespace
|
672
|
+
|
673
|
+
bool FindIPv4Components(const char* spec,
|
674
|
+
const url_parse::Component& host,
|
675
|
+
url_parse::Component components[4]) {
|
676
|
+
return DoFindIPv4Components<char, unsigned char>(spec, host, components);
|
677
|
+
}
|
678
|
+
|
679
|
+
bool FindIPv4Components(const char16* spec,
|
680
|
+
const url_parse::Component& host,
|
681
|
+
url_parse::Component components[4]) {
|
682
|
+
return DoFindIPv4Components<char16, char16>(spec, host, components);
|
683
|
+
}
|
684
|
+
|
685
|
+
void CanonicalizeIPAddress(const char* spec,
|
686
|
+
const url_parse::Component& host,
|
687
|
+
CanonOutput* output,
|
688
|
+
CanonHostInfo* host_info) {
|
689
|
+
if (DoCanonicalizeIPv4Address<char, unsigned char>(
|
690
|
+
spec, host, output, host_info))
|
691
|
+
return;
|
692
|
+
if (DoCanonicalizeIPv6Address<char, unsigned char>(
|
693
|
+
spec, host, output, host_info))
|
694
|
+
return;
|
695
|
+
}
|
696
|
+
|
697
|
+
void CanonicalizeIPAddress(const char16* spec,
|
698
|
+
const url_parse::Component& host,
|
699
|
+
CanonOutput* output,
|
700
|
+
CanonHostInfo* host_info) {
|
701
|
+
if (DoCanonicalizeIPv4Address<char16, char16>(
|
702
|
+
spec, host, output, host_info))
|
703
|
+
return;
|
704
|
+
if (DoCanonicalizeIPv6Address<char16, char16>(
|
705
|
+
spec, host, output, host_info))
|
706
|
+
return;
|
707
|
+
}
|
708
|
+
|
709
|
+
CanonHostInfo::Family IPv4AddressToNumber(const char* spec,
|
710
|
+
const url_parse::Component& host,
|
711
|
+
unsigned char address[4],
|
712
|
+
int* num_ipv4_components) {
|
713
|
+
return DoIPv4AddressToNumber<char>(spec, host, address, num_ipv4_components);
|
714
|
+
}
|
715
|
+
|
716
|
+
CanonHostInfo::Family IPv4AddressToNumber(const char16* spec,
|
717
|
+
const url_parse::Component& host,
|
718
|
+
unsigned char address[4],
|
719
|
+
int* num_ipv4_components) {
|
720
|
+
return DoIPv4AddressToNumber<char16>(
|
721
|
+
spec, host, address, num_ipv4_components);
|
722
|
+
}
|
723
|
+
|
724
|
+
bool IPv6AddressToNumber(const char* spec,
|
725
|
+
const url_parse::Component& host,
|
726
|
+
unsigned char address[16]) {
|
727
|
+
return DoIPv6AddressToNumber<char, unsigned char>(spec, host, address);
|
728
|
+
}
|
729
|
+
|
730
|
+
bool IPv6AddressToNumber(const char16* spec,
|
731
|
+
const url_parse::Component& host,
|
732
|
+
unsigned char address[16]) {
|
733
|
+
return DoIPv6AddressToNumber<char16, char16>(spec, host, address);
|
734
|
+
}
|
735
|
+
|
736
|
+
|
737
|
+
} // namespace url_canon
|