1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
|
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/proxy/proxy_server.h"
#include <algorithm>
#include "base/string_tokenizer.h"
#include "base/string_util.h"
#include "net/base/net_util.h"
#include "net/http/http_util.h"
namespace net {
namespace {
// Parse the proxy type from a PAC string, to a ProxyServer::Scheme.
// This mapping is case-insensitive. If no type could be matched
// returns SCHEME_INVALID.
ProxyServer::Scheme GetSchemeFromPacType(std::string::const_iterator begin,
std::string::const_iterator end) {
if (LowerCaseEqualsASCII(begin, end, "proxy"))
return ProxyServer::SCHEME_HTTP;
if (LowerCaseEqualsASCII(begin, end, "socks")) {
// Default to v4 for compatibility. This is because the SOCKS4 vs SOCKS5
// notation didn't originally exist, so if a client returns SOCKS they
// really meant SOCKS4.
return ProxyServer::SCHEME_SOCKS4;
}
if (LowerCaseEqualsASCII(begin, end, "socks4"))
return ProxyServer::SCHEME_SOCKS4;
if (LowerCaseEqualsASCII(begin, end, "socks5"))
return ProxyServer::SCHEME_SOCKS5;
if (LowerCaseEqualsASCII(begin, end, "direct"))
return ProxyServer::SCHEME_DIRECT;
return ProxyServer::SCHEME_INVALID;
}
// Parse the proxy scheme from a URL-like representation, to a
// ProxyServer::Scheme. This corresponds with the values used in
// ProxyServer::ToURI(). If no type could be matched, returns SCHEME_INVALID.
ProxyServer::Scheme GetSchemeFromURI(std::string::const_iterator begin,
std::string::const_iterator end) {
if (LowerCaseEqualsASCII(begin, end, "http"))
return ProxyServer::SCHEME_HTTP;
if (LowerCaseEqualsASCII(begin, end, "socks4"))
return ProxyServer::SCHEME_SOCKS4;
if (LowerCaseEqualsASCII(begin, end, "socks"))
return ProxyServer::SCHEME_SOCKS4;
if (LowerCaseEqualsASCII(begin, end, "socks5"))
return ProxyServer::SCHEME_SOCKS5;
if (LowerCaseEqualsASCII(begin, end, "direct"))
return ProxyServer::SCHEME_DIRECT;
return ProxyServer::SCHEME_INVALID;
}
} // namespace
std::string ProxyServer::HostNoBrackets() const {
// Doesn't make sense to call this if the URI scheme doesn't
// have concept of a host.
DCHECK(is_valid() && !is_direct());
// Remove brackets from an RFC 2732-style IPv6 literal address.
const std::string::size_type len = host_.size();
if (len != 0 && host_[0] == '[' && host_[len - 1] == ']')
return host_.substr(1, len - 2);
return host_;
}
int ProxyServer::port() const {
// Doesn't make sense to call this if the URI scheme doesn't
// have concept of a port.
DCHECK(is_valid() && !is_direct());
return port_;
}
std::string ProxyServer::host_and_port() const {
// Doesn't make sense to call this if the URI scheme doesn't
// have concept of a host.
DCHECK(is_valid() && !is_direct());
return host_ + ":" + IntToString(port_);
}
// static
ProxyServer ProxyServer::FromURI(const std::string& uri,
Scheme default_scheme) {
return FromURI(uri.begin(), uri.end(), default_scheme);
}
// static
ProxyServer ProxyServer::FromURI(std::string::const_iterator begin,
std::string::const_iterator end,
Scheme default_scheme) {
// We will default to |default_scheme| if no scheme specifier was given.
Scheme scheme = default_scheme;
// Trim the leading/trailing whitespace.
HttpUtil::TrimLWS(&begin, &end);
// Check for [<scheme> "://"]
std::string::const_iterator colon = std::find(begin, end, ':');
if (colon != end &&
(end - colon) >= 3 &&
*(colon + 1) == '/' &&
*(colon + 2) == '/') {
scheme = GetSchemeFromURI(begin, colon);
begin = colon + 3; // Skip past the "://"
}
// Now parse the <host>[":"<port>].
return FromSchemeHostAndPort(scheme, begin, end);
}
std::string ProxyServer::ToURI() const {
switch (scheme_) {
case SCHEME_DIRECT:
return "direct://";
case SCHEME_HTTP:
// Leave off "http://" since it is our default scheme.
return host_and_port();
case SCHEME_SOCKS4:
return std::string("socks4://") + host_and_port();
case SCHEME_SOCKS5:
return std::string("socks5://") + host_and_port();
default:
// Got called with an invalid scheme.
NOTREACHED();
return std::string();
}
}
// static
ProxyServer ProxyServer::FromPacString(const std::string& pac_string) {
return FromPacString(pac_string.begin(), pac_string.end());
}
ProxyServer ProxyServer::FromPacString(std::string::const_iterator begin,
std::string::const_iterator end) {
// Trim the leading/trailing whitespace.
HttpUtil::TrimLWS(&begin, &end);
// Input should match:
// "DIRECT" | ( <type> 1*(LWS) <host-and-port> )
// Start by finding the first space (if any).
std::string::const_iterator space;
for (space = begin; space != end; ++space) {
if (HttpUtil::IsLWS(*space)) {
break;
}
}
// Everything to the left of the space is the scheme.
Scheme scheme = GetSchemeFromPacType(begin, space);
// And everything to the right of the space is the
// <host>[":" <port>].
return FromSchemeHostAndPort(scheme, space, end);
}
std::string ProxyServer::ToPacString() const {
switch (scheme_) {
case SCHEME_DIRECT:
return "DIRECT";
case SCHEME_HTTP:
return std::string("PROXY ") + host_and_port();
case SCHEME_SOCKS4:
// For compatibility send SOCKS instead of SOCKS4.
return std::string("SOCKS ") + host_and_port();
case SCHEME_SOCKS5:
return std::string("SOCKS5 ") + host_and_port();
default:
// Got called with an invalid scheme.
NOTREACHED();
return std::string();
}
}
// static
int ProxyServer::GetDefaultPortForScheme(Scheme scheme) {
switch (scheme) {
case SCHEME_HTTP:
return 80;
case SCHEME_SOCKS4:
case SCHEME_SOCKS5:
return 1080;
default:
return -1;
}
}
// static
ProxyServer ProxyServer::FromSchemeHostAndPort(
Scheme scheme,
std::string::const_iterator begin,
std::string::const_iterator end) {
// Trim leading/trailing space.
HttpUtil::TrimLWS(&begin, &end);
if (scheme == SCHEME_DIRECT && begin != end)
return ProxyServer(); // Invalid -- DIRECT cannot have a host/port.
std::string host;
int port = -1;
if (scheme != SCHEME_INVALID && scheme != SCHEME_DIRECT) {
// If the scheme has a host/port, parse it.
bool ok = net::ParseHostAndPort(begin, end, &host, &port);
if (!ok)
return ProxyServer(); // Invalid -- failed parsing <host>[":"<port>]
}
// Choose a default port number if none was given.
if (port == -1)
port = GetDefaultPortForScheme(scheme);
return ProxyServer(scheme, host, port);
}
} // namespace net
|