#[non_exhaustive]pub struct BypassRules {
pub patterns: Vec<HostPattern>,
pub exclude_simple_hostnames: bool,
pub reversed_exceptions: bool,
pub rejected: Vec<RejectedValue>,
pub require_explicit_port: bool,
}Expand description
Destinations that must not go through a proxy
(parse::no_proxy / parse::proxy_override).
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.patterns: Vec<HostPattern>Parsed list entries.
exclude_simple_hostnames: boolDot-less host bypass, as a switch (macOS ExcludeSimpleHostnames). The list
spelling HostPattern::Local says the same thing until
reversed_exceptions is set, where a switch and a
list entry mean opposite things — see
excludes_simple_hostnames.
reversed_exceptions: boolKDE/config-kde inclusion list — the implicit set still applies; see matches.
rejected: Vec<RejectedValue>Redacted unparseable originals; affects verdict under
reversed_exceptions. Not a complete ledger of the
entries that match nothing — see HostPattern::Wildcard.
require_explicit_port: boolWhether a destination’s port counts only when the destination wrote one, so that a
ported entry such as example.com:80 does not meet a portless http://example.com/.
Set for GNOME ignore-hosts and nowhere else. GLib resolves the destination with
G_URI_FLAGS_NONE (gsimpleproxyresolver.c:341) and fills a scheme’s default port
only under G_URI_FLAGS_SCHEME_NORMALIZE (guri.c:1006), so the port it compares
against is 0 unless the URL carried one. Windows fills it — a ProxyOverride entry
of host:80 was measured bypassing a portless http://host/.
matches does not read this: it is told a port and answers about
that port. matches_url is where it is read, and is the reason
to prefer that method whenever the destination is a Url — it passes
Url::port rather than
port_or_known_default when this is set. Reading the field by hand is supported, not
recommended.
One case is approximate, and in the safe direction. Url drops a port equal to the
scheme’s default while parsing, so http://host:80/ and http://host/ are the same
value and port answers None for both. A rule on that port — host:80 for
http, host:443 for https — therefore stops firing entirely here, where GLib
still fires it on the spelling that wrote the port out. The destination goes to the
proxy instead of direct; the distinction was gone before this crate saw the URL.
Implementations§
Source§impl BypassRules
impl BypassRules
Sourcepub const fn new() -> Self
pub const fn new() -> Self
An empty rule set with the default loopback behaviour (loopback is bypassed).
Sourcepub fn bypass_loopback(&self) -> bool
pub fn bypass_loopback(&self) -> bool
Whether the implicit bypass set — loopback and link-local — is still in force,
which it is unless the list carries HostPattern::SubtractImplicit
(<-loopback>).
A rough answer, and the reason it is not a field: <-loopback> subtracts the
implicit set only from the entries written before it, so a list that carries the
token can still bypass a loopback destination named after it. Ask
matches about a destination; ask this about the list.
assert!(parse::no_proxy("localhost").bypass_loopback());
assert!(!parse::proxy_override("<-loopback>").bypass_loopback());
// The token is in the list, so this is `false` — but `localhost` is written
// after it and wins on the destination it names.
let readded = parse::proxy_override("<-loopback>;localhost");
assert!(!readded.bypass_loopback());
assert!(readded.matches_authority("localhost"));
assert!(!readded.matches_authority("127.0.0.1"));Sourcepub fn excludes_simple_hostnames(&self) -> bool
pub fn excludes_simple_hostnames(&self) -> bool
Whether either representation of the dot-less host rule is present — the
exclude_simple_hostnames switch or a
HostPattern::Local entry.
Present, not equivalent. Under
reversed_exceptions the two part company, because
one is a switch and the other is a list entry: the switch bypasses dot-less hosts
before the list is consulted at all, the way the implicit set does, while a
Local entry is inside the inclusion list and so means the opposite — dot-less
hosts are exactly the ones that keep using the proxy. So this answering true
does not by itself tell you matches will bypass a dot-less
host; ask matches. Folding one representation into the other silently flips
that verdict.
Sourcepub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
Empty patterns and default flags (BypassRules::new). <-loopback> is an entry
in patterns, so a list holding only that is not empty — it
carries an instruction, and reporting it empty would invite a caller to drop it and
put the implicit bypass back. Omits rejected (only matters under
reversed_exceptions, which already answers false).
assert!(BypassRules::new().is_empty());
assert!(parse::no_proxy("").is_empty());
// `<-loopback>` is an instruction, not an absence of one.
assert!(!parse::proxy_override("<-loopback>").is_empty());Sourcepub fn matches(&self, host: &Host, port: Option<u16>) -> bool
pub fn matches(&self, host: &Host, port: Option<u16>) -> bool
Whether host bypasses the proxy.
A host with no text answers false before any of the below, in both modes. Nothing
in this crate asks — a URL with no host is Direct long before the bypass list is
reached — so that answer is for a caller who assembled the Host itself. Such a
caller owns the other end of this too: a Host::Domain is taken as text and never
re-read as an address, so Domain("0177.0.0.1") misses the loopback switch that
matches_authority hits for the same characters. Neither
Url::host nor url::Host::parse can hand over that value — both fold every numeric
spelling to Host::Ipv4 — and re-parsing here would cost every call for a shape only
a literal Host::Domain(_) can make.
No name is resolved here, ever. A host that /etc/hosts or DNS points at
127.0.0.1 is still read as the characters it was written with, so it misses the
implicit set and goes through the proxy unless an entry names it. Chromium reads the
same way — ProxyHostMatchingRules::Matches takes a GURL and every rule under it
asks url.host() — and a lookup inside a predicate that runs per request would put
its latency and its failures there too.
Ported :port rules never match port = None (Go). Under
reversed_exceptions, patterns are inclusion-only
while rejected is empty.
Entries are read back to front, and the first one that has something to say
answers: “Later rules override earlier rules … when mixing positive and negative
rules, evaluation order makes a difference”
(Chromium, net/base/scheme_host_port_matcher.cc; the expectation “comes from
WinInet (which is where <-loopback> comes from)”,
proxy_host_matching_rules_unittest.cc). Order only ever matters because of
HostPattern::SubtractImplicit, the one entry that takes a bypass away — so
127.0.0.1;<-loopback> proxies 127.0.0.1 and <-loopback>;127.0.0.1 sends it
direct. With no entry deciding, the implicit set does: loopback and link-local
alike, and not inverted by reversed_exceptions, because an inclusion list that
never named loopback has not asked for loopback to be proxied.
exclude_simple_hostnames is a switch and not an
entry, so it is not inverted either — unlike a HostPattern::Local entry, which
is; see excludes_simple_hostnames for why that
changes the answer here. An IPv4-mapped IPv6 destination
(::ffff:a.b.c.d) is compared as the IPv4 address it maps, against CIDR and exact
patterns alike, and against the loopback/link-local switches.
let rules = parse::no_proxy("localhost, .example.com, 10.0.0.0/8");
assert!(rules.matches_authority("www.example.com"));
assert!(rules.matches_authority("10.1.2.3:443"));
assert!(!rules.matches_authority("example.org"));
// Link-local destinations bypass even though the list above never mentions them.
assert!(rules.matches_authority("169.254.1.1"));
assert!(rules.matches_authority("[fe80::1]"));Sourcepub fn matches_url(&self, url: &Url) -> bool
pub fn matches_url(&self, url: &Url) -> bool
Whether a destination URL bypasses the proxy.
Prefer this over matches whenever the destination is a Url: it is
the only entry point that reads require_explicit_port,
and getting that wrong by hand is silent — a GNOME ignore-hosts of example.com:80
asked about with port_or_known_default reports a bypass GNOME does not have. This
crate’s own resolve goes through here.
A URL with no host to compare — data:, mailto:, or one whose host was emptied —
is reported as “does not bypass”, the same reading as an unparseable authority in
matches_authority. It is not a statement that such a URL
needs a proxy; a caller that routes hostless URLs direct should say so before asking.
let rules = parse::no_proxy(".example.com");
assert!(rules.matches_url(&Url::parse("https://www.example.com/x").unwrap()));
assert!(!rules.matches_url(&Url::parse("https://example.org/").unwrap()));
assert!(!rules.matches_url(&Url::parse("data:,hello").unwrap()));Convenience wrapper around BypassRules::matches taking a host[:port]
string such as example.com:8080 or [::1]:443.
Unparseable input is reported as “does not bypass”: an authority this cannot split is one it cannot prove is exempt, so it goes through the proxy, which can still refuse it. (Other stacks disagree on this edge; this crate does not claim their spelling.)
Supplies no default port: an authority written without one is asked with none, so
a rule spelled example.com:80 does not match example.com.
matches_url is the entry point that fills one in.
Trait Implementations§
Source§impl Clone for BypassRules
impl Clone for BypassRules
Source§fn clone(&self) -> BypassRules
fn clone(&self) -> BypassRules
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for BypassRules
impl Debug for BypassRules
Source§impl Default for BypassRules
impl Default for BypassRules
impl Eq for BypassRules
Source§impl PartialEq for BypassRules
impl PartialEq for BypassRules
impl StructuralPartialEq for BypassRules
Auto Trait Implementations§
impl Freeze for BypassRules
impl RefUnwindSafe for BypassRules
impl Send for BypassRules
impl Sync for BypassRules
impl Unpin for BypassRules
impl UnsafeUnpin for BypassRules
impl UnwindSafe for BypassRules
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.