diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-05-15 23:41:41 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-05-16 10:00:40 +0900 |
| commit | d6ee7d49506a87c34aa5b407932d414a552a4523 (patch) | |
| tree | 540da05188fae3ac9f4d0232e1c347bd2b557dad /crates/shirabe/src/util | |
| parent | b6a887e7e5db7747cf05a4c1558a6d765cf7c24e (diff) | |
| download | php-shirabe-d6ee7d49506a87c34aa5b407932d414a552a4523.tar.gz php-shirabe-d6ee7d49506a87c34aa5b407932d414a552a4523.tar.zst php-shirabe-d6ee7d49506a87c34aa5b407932d414a552a4523.zip | |
feat(port): port RequestProxy.php
Diffstat (limited to 'crates/shirabe/src/util')
| -rw-r--r-- | crates/shirabe/src/util/http/request_proxy.rs | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/crates/shirabe/src/util/http/request_proxy.rs b/crates/shirabe/src/util/http/request_proxy.rs index 826598f..1405a32 100644 --- a/crates/shirabe/src/util/http/request_proxy.rs +++ b/crates/shirabe/src/util/http/request_proxy.rs @@ -1 +1,106 @@ //! ref: composer/src/Composer/Util/Http/RequestProxy.php + +use indexmap::IndexMap; +use shirabe_php_shim::{ + curl_version, PhpMixed, CURLAUTH_BASIC, CURL_VERSION_HTTPS_PROXY, CURLOPT_NOPROXY, + CURLOPT_PROXY, CURLOPT_PROXY_CAINFO, CURLOPT_PROXY_CAPATH, CURLOPT_PROXYAUTH, + CURLOPT_PROXYUSERPWD, InvalidArgumentException, +}; + +use crate::downloader::transport_exception::TransportException; + +// contextOptions = array{http: array{proxy: string, header?: string, request_fulluri?: bool}} +type ContextOptions = IndexMap<String, IndexMap<String, PhpMixed>>; + +#[derive(Debug)] +pub struct RequestProxy { + context_options: Option<ContextOptions>, + status: Option<String>, + url: Option<String>, + auth: Option<String>, +} + +impl RequestProxy { + pub fn new(url: Option<String>, auth: Option<String>, context_options: Option<ContextOptions>, status: Option<String>) -> Self { + Self { url, auth, context_options, status } + } + + pub fn none() -> Self { + Self::new(None, None, None, None) + } + + pub fn no_proxy() -> Self { + Self::new(None, None, None, Some("excluded by no_proxy".to_string())) + } + + pub fn get_context_options(&self) -> Option<&ContextOptions> { + self.context_options.as_ref() + } + + pub fn get_curl_options(&self, ssl_options: &IndexMap<String, PhpMixed>) -> Result<IndexMap<i64, PhpMixed>, TransportException> { + if self.is_secure() && !self.supports_secure_proxy() { + return Err(TransportException::new("Cannot use an HTTPS proxy. PHP >= 7.3 and cUrl >= 7.52.0 are required.".to_string())); + } + + let mut options: IndexMap<i64, PhpMixed> = IndexMap::new(); + options.insert(CURLOPT_PROXY, PhpMixed::String(self.url.as_deref().unwrap_or("").to_string())); + + if self.url.is_some() { + options.insert(CURLOPT_NOPROXY, PhpMixed::String(String::new())); + } + + if let Some(auth) = &self.auth { + options.insert(CURLOPT_PROXYAUTH, PhpMixed::Int(CURLAUTH_BASIC)); + options.insert(CURLOPT_PROXYUSERPWD, PhpMixed::String(auth.clone())); + } + + if self.is_secure() { + if let Some(cafile) = ssl_options.get("cafile") { + options.insert(CURLOPT_PROXY_CAINFO, cafile.clone()); + } + if let Some(capath) = ssl_options.get("capath") { + options.insert(CURLOPT_PROXY_CAPATH, capath.clone()); + } + } + + Ok(options) + } + + pub fn get_status(&self, format: Option<&str>) -> Result<String, InvalidArgumentException> { + if self.status.is_none() { + return Ok(String::new()); + } + + let format = format.unwrap_or("%s"); + if format.contains("%s") { + return Ok(format.replace("%s", self.status.as_deref().unwrap())); + } + + Err(InvalidArgumentException { + message: "String format specifier is missing".to_string(), + code: 0, + }) + } + + pub fn is_excluded_by_no_proxy(&self) -> bool { + self.status.is_some() && self.url.is_none() + } + + pub fn is_secure(&self) -> bool { + self.url.as_deref().unwrap_or("").starts_with("https://") + } + + pub fn supports_secure_proxy(&self) -> bool { + let version = match curl_version() { + None => return false, + Some(v) => v, + }; + + if !shirabe_php_shim::defined("CURL_VERSION_HTTPS_PROXY") { + return false; + } + + let features = version.get("features").and_then(|v| v.as_int()).unwrap_or(0); + (features & CURL_VERSION_HTTPS_PROXY) != 0 + } +} |
