blob: ac97f2614bc192b6a1ea7aabf6c13013f2be2f51 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use std::{
borrow::Cow,
collections::HashMap,
fmt::{Debug, Display, Formatter},
str::FromStr,
};
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Url {
inner: url::Url,
}
impl Url {
pub fn empty() -> Self {
"empty://localhost".parse().unwrap()
}
pub fn protocol(&self) -> &str {
self.inner.scheme()
}
pub fn host(&self) -> Option<&str> {
self.inner.host_str()
}
pub fn authority(&self) -> &str {
self.inner.authority()
}
pub fn username(&self) -> &str {
self.inner.username()
}
pub fn password(&self) -> Option<&str> {
self.inner.password()
}
pub fn port(&self) -> Option<u16> {
self.inner.port_or_known_default()
}
pub fn path(&self) -> &str {
self.inner.path()
}
pub fn query<T: UrlParam>(&self) -> Option<T> {
self.inner
.query_pairs()
.find(|(k, _)| k == T::name())
.map(|(_, v)| T::from_str(&v).ok())
.flatten()
}
pub fn query_param_by_key(&self, key: &str) -> Option<String> {
self.inner
.query_pairs()
.find(|(k, _)| k == key)
.map(|(_, v)| v.into_owned())
}
pub fn all_query_params(&self) -> HashMap<String, String> {
self.inner
.query_pairs()
.map(|(k, v)| (k.into_owned(), v.into_owned()))
.collect()
}
pub fn set_protocol(&mut self, protocol: &str) {
let _ = self.inner.set_scheme(protocol);
}
pub fn set_host(&mut self, host: &str) {
let _ = self.inner.set_host(Some(host));
}
pub fn set_port(&mut self, port: u16) {
let _ = self.inner.set_port(Some(port));
}
pub fn set_username(&mut self, username: &str) {
let _ = self.inner.set_username(username);
}
pub fn set_password(&mut self, password: &str) {
let _ = self.inner.set_password(Some(password));
}
pub fn set_path(&mut self, path: &str) {
let _ = self.inner.set_path(path);
}
pub fn extend_pairs(&mut self, pairs: impl Iterator<Item = (String, String)>) {
let mut query_pairs = self.inner.query_pairs_mut();
query_pairs.extend_pairs(pairs);
}
pub fn add_query_param<T: UrlParam>(&mut self, param: T) {
let mut pairs = self.inner.query_pairs_mut();
pairs.append_pair(T::name(), &param.as_str());
}
pub fn remove_query_param<T: UrlParam>(&mut self) {
let query = self.inner.query_pairs().filter(|(k, v)| k.ne(T::name()));
let mut inner_url = self.inner.clone();
inner_url.query_pairs_mut().clear().extend_pairs(query);
self.inner = inner_url;
}
pub fn remove_all_param(&mut self) {
self.inner.query_pairs_mut().clear();
}
pub fn as_str(&self) -> &str {
self.inner.as_str()
}
pub fn short_url_without_query(&self) -> String {
let mut url = self.inner.clone();
url.set_query(Some(""));
url.into()
}
}
impl FromStr for Url {
type Err = url::ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Url {
inner: url::Url::parse(s)?,
})
}
}
impl Display for Url {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.inner, f)
}
}
impl Debug for Url {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(&self.inner, f)
}
}
impl From<Url> for String {
fn from(url: Url) -> Self {
url.inner.into()
}
}
pub trait UrlParam: FromStr {
type TargetType;
fn name() -> &'static str;
fn value(&self) -> Self::TargetType;
fn as_str(&self) -> Cow<str>;
}