gix_credentials/protocol/context/
mod.rs1use bstr::BString;
2
3#[derive(Debug, thiserror::Error)]
5#[allow(missing_docs)]
6pub enum Error {
7 #[error("{key:?}={value:?} must not contain null bytes or newlines neither in key nor in value.")]
8 Encoding { key: String, value: BString },
9}
10
11mod access {
12 use bstr::BString;
13
14 use crate::protocol::Context;
15
16 impl Context {
17 pub fn to_url(&self) -> Option<BString> {
19 use bstr::{ByteSlice, ByteVec};
20 let mut buf: BString = self.protocol.clone()?.into();
21 buf.push_str(b"://");
22 if let Some(user) = &self.username {
23 buf.push_str(user);
24 buf.push(b'@');
25 }
26 if let Some(host) = &self.host {
27 buf.push_str(host);
28 }
29 if let Some(path) = &self.path {
30 if !path.starts_with_str("/") {
31 buf.push(b'/');
32 }
33 buf.push_str(path);
34 }
35 buf.into()
36 }
37 pub fn to_prompt(&self, field: &str) -> String {
39 match self.to_url() {
40 Some(url) => format!("{field} for {url}: "),
41 None => format!("{field}: "),
42 }
43 }
44 }
45}
46
47mod mutate {
48 use bstr::ByteSlice;
49
50 use crate::{protocol, protocol::Context};
51
52 impl Context {
54 #[allow(clippy::result_large_err)]
58 pub fn destructure_url_in_place(&mut self, use_http_path: bool) -> Result<&mut Self, protocol::Error> {
59 let url = gix_url::parse(self.url.as_ref().ok_or(protocol::Error::UrlMissing)?.as_ref())?;
60 self.protocol = Some(url.scheme.as_str().into());
61 self.username = url.user().map(ToOwned::to_owned);
62 self.password = url.password().map(ToOwned::to_owned);
63 self.host = url.host().map(ToOwned::to_owned).map(|mut host| {
64 if let Some(port) = url.port {
65 use std::fmt::Write;
66 write!(host, ":{port}").expect("infallible");
67 }
68 host
69 });
70 if !matches!(url.scheme, gix_url::Scheme::Http | gix_url::Scheme::Https) || use_http_path {
71 let path = url.path.trim_with(|b| b == '/');
72 self.path = (!path.is_empty()).then(|| path.into());
73 }
74 Ok(self)
75 }
76 }
77}
78
79mod serde;
80pub use self::serde::decode;