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
|
//! ref: composer/src/Composer/Util/Http/ProxyItem.php
use crate::util::http::request_proxy::RequestProxy;
use indexmap::IndexMap;
use shirabe_php_shim::{
PhpMixed, RuntimeException, base64_encode, parse_url_all, rawurldecode, strpbrk,
};
#[derive(Debug)]
pub struct ProxyItem {
url: String,
safe_url: String,
curl_auth: Option<String>,
options_proxy: String,
options_auth: Option<String>,
}
impl ProxyItem {
pub fn new(proxy_url: String, env_name: String) -> Result<Self, RuntimeException> {
let syntax_error = format!("unsupported `{}` syntax", env_name);
if strpbrk(&proxy_url, "\r\n\t").is_some() {
return Err(RuntimeException {
message: syntax_error,
code: 0,
});
}
let proxy_parsed = parse_url_all(&proxy_url);
let proxy = match proxy_parsed.as_array() {
None => {
return Err(RuntimeException {
message: syntax_error,
code: 0,
});
}
Some(a) => a.clone(),
};
if !proxy.contains_key("host") {
return Err(RuntimeException {
message: format!("unable to find proxy host in {}", env_name),
code: 0,
});
}
let scheme = if proxy.contains_key("scheme") {
format!(
"{}://",
proxy["scheme"].as_string().unwrap_or("").to_lowercase()
)
} else {
"http://".to_string()
};
let mut safe = String::new();
let mut curl_auth: Option<String> = None;
let mut options_auth: Option<String> = None;
if proxy.contains_key("user") {
safe = "***".to_string();
let user_raw = proxy["user"].as_string().unwrap_or("");
let auth_raw = rawurldecode(user_raw);
let mut user = user_raw.to_string();
let mut auth = auth_raw;
if proxy.contains_key("pass") {
let pass_raw = proxy["pass"].as_string().unwrap_or("");
safe += ":***";
user += &format!(":{}", pass_raw);
auth += &format!(":{}", rawurldecode(pass_raw));
}
safe += "@";
if !user.is_empty() {
curl_auth = Some(user);
options_auth = Some(format!(
"Proxy-Authorization: Basic {}",
base64_encode(&auth)
));
}
}
let host = proxy["host"].as_string().unwrap_or("").to_string();
let port: Option<i64>;
if proxy.contains_key("port") {
port = proxy["port"].as_int();
} else if scheme == "http://" {
port = Some(80);
} else if scheme == "https://" {
port = Some(443);
} else {
port = None;
}
// We need a port because curl uses 1080 for http. Port 0 is reserved,
// but is considered valid depending on the PHP or Curl version.
let port = match port {
None => {
return Err(RuntimeException {
message: format!("unable to find proxy port in {}", env_name),
code: 0,
});
}
Some(0) => {
return Err(RuntimeException {
message: format!("port 0 is reserved in {}", env_name),
code: 0,
});
}
Some(p) => p,
};
let url = format!("{}{}:{}", scheme, host, port);
let safe_url = format!("{}{}{}:{}", scheme, safe, host, port);
let options_proxy_scheme = scheme
.replace("http://", "tcp://")
.replace("https://", "ssl://");
let options_proxy = format!("{}{}:{}", options_proxy_scheme, host, port);
Ok(Self {
url,
safe_url,
curl_auth,
options_proxy,
options_auth,
})
}
pub fn to_request_proxy(&self, scheme: String) -> RequestProxy {
let mut http_options: IndexMap<String, PhpMixed> = IndexMap::new();
http_options.insert(
"proxy".to_string(),
PhpMixed::String(self.options_proxy.clone()),
);
if let Some(ref auth) = self.options_auth {
http_options.insert("header".to_string(), PhpMixed::String(auth.clone()));
}
if scheme == "http" {
http_options.insert("request_fulluri".to_string(), PhpMixed::Bool(true));
}
let mut options: IndexMap<String, IndexMap<String, PhpMixed>> = IndexMap::new();
options.insert("http".to_string(), http_options);
RequestProxy::new(
Some(self.url.clone()),
self.curl_auth.clone(),
Some(options),
Some(self.safe_url.clone()),
)
}
}
|