rvoip_sip_core/types/
uri.rs

1//! # SIP URI Implementation
2//!
3//! This module provides a comprehensive implementation of SIP Uniform Resource Identifiers (URIs) 
4//! as defined in [RFC 3261](https://tools.ietf.org/html/rfc3261).
5//!
6//! SIP URIs are used to identify users, servers, and services in a SIP network.
7//! They have a similar structure to email addresses, with additional parameters 
8//! and headers for SIP-specific functionality.
9//!
10//! ## URI Structure
11//!
12//! A SIP URI has the following general form:
13//!
14//! ```text
15//! sip:user:password@host:port;uri-parameters?headers
16//! ```
17//!
18//! Where:
19//! - `sip:` is the scheme (can also be `sips:` for secure SIP)
20//! - `user:password` is the optional userinfo component (password is deprecated)
21//! - `host` is the required domain name or IP address
22//! - `port` is the optional port number
23//! - `uri-parameters` are optional parameters (`;key=value` or `;key`)
24//! - `headers` are optional headers (`?key=value&key=value`)
25//!
26//! ## Usage Examples
27//!
28//! ```rust
29//! use rvoip_sip_core::prelude::*;
30//! use std::str::FromStr;
31//!
32//! // Parse a URI from a string
33//! let uri = Uri::from_str("sip:alice@example.com:5060;transport=udp?subject=meeting").unwrap();
34//!
35//! // Access URI components
36//! assert_eq!(uri.scheme, Scheme::Sip);
37//! assert_eq!(uri.username(), Some("alice"));
38//! assert_eq!(uri.host.to_string(), "example.com");
39//! assert_eq!(uri.port, Some(5060));
40//! assert_eq!(uri.transport(), Some("udp"));
41//!
42//! // Create a URI programmatically
43//! let uri = Uri::sip("example.com")
44//!     .with_user("bob")
45//!     .with_port(5060)
46//!     .with_parameter(Param::transport("tcp"));
47//!
48//! assert_eq!(uri.to_string(), "sip:bob@example.com:5060;transport=tcp");
49//! ```
50
51// URI implementation moved from root directory
52// Implements URI types according to RFC 3261
53
54use std::collections::HashMap;
55use std::fmt;
56use std::str::FromStr;
57use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
58
59use nom::{
60    branch::alt,
61    bytes::complete::{tag, take_till, take_until, take_while, take_while1},
62    character::complete::{char, digit1, hex_digit1},
63    combinator::{map, map_res, opt, recognize, verify, all_consuming},
64    multi::{many0, separated_list0},
65    sequence::{delimited, pair, preceded, separated_pair, terminated, tuple},
66    IResult,
67};
68use serde::{Deserialize, Serialize};
69
70use crate::error::{Error, Result};
71use crate::types::param::Param; // Updated import path
72use crate::parser::uri::parse_uri; // Import the nom parser
73
74/// SIP URI scheme types
75///
76/// Represents the scheme component of a URI, which indicates the protocol
77/// or addressing scheme being used.
78///
79/// The most common schemes in SIP are:
80/// - `sip`: Standard SIP (typically over UDP or TCP)
81/// - `sips`: Secure SIP (typically over TLS)
82/// - `tel`: Telephone number
83///
84/// The implementation also supports `http`, `https`, and custom schemes.
85#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
86pub enum Scheme {
87    /// SIP URI (non-secure)
88    Sip,
89    /// SIPS URI (secure SIP)
90    Sips,
91    /// TEL URI (telephone number)
92    Tel,
93    /// HTTP URI
94    Http,
95    /// HTTPS URI
96    Https,
97    /// Custom scheme (any other scheme)
98    Custom(String),
99}
100
101impl Scheme {
102    /// Returns the string representation of the scheme
103    ///
104    /// # Examples
105    ///
106    /// ```
107    /// use rvoip_sip_core::types::uri::Scheme;
108    ///
109    /// assert_eq!(Scheme::Sip.as_str(), "sip");
110    /// assert_eq!(Scheme::Sips.as_str(), "sips");
111    /// assert_eq!(Scheme::Custom("xmpp".to_string()).as_str(), "xmpp");
112    /// ```
113    pub fn as_str(&self) -> &str {
114        match self {
115            Scheme::Sip => "sip",
116            Scheme::Sips => "sips",
117            Scheme::Tel => "tel",
118            Scheme::Http => "http",
119            Scheme::Https => "https",
120            Scheme::Custom(scheme) => scheme,
121        }
122    }
123}
124
125impl fmt::Display for Scheme {
126    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127        f.write_str(self.as_str())
128    }
129}
130
131impl FromStr for Scheme {
132    type Err = Error;
133
134    fn from_str(s: &str) -> Result<Self> {
135        // Check specifically for schemes followed by ':' implicitly
136        // The nom parser `terminated(scheme_parser, char(':'))` ensures this, 
137        // so direct FromStr should handle the base scheme string correctly.
138        match s.to_lowercase().as_str() {
139            "sip" => Ok(Scheme::Sip),
140            "sips" => Ok(Scheme::Sips),
141            "tel" => Ok(Scheme::Tel),
142            "http" => Ok(Scheme::Http),
143            "https" => Ok(Scheme::Https),
144            _ => Ok(Scheme::Custom(s.to_string())), // Support arbitrary schemes
145        }
146    }
147}
148
149/// Represents the host part of a URI.
150///
151/// The host can be either a domain name or an IP address (v4 or v6).
152/// In SIP URIs, the host is the mandatory component that identifies the target
153/// server or endpoint.
154///
155/// # Examples
156///
157/// ```
158/// use rvoip_sip_core::prelude::*;
159/// use std::str::FromStr;
160///
161/// // Domain name
162/// let host = Host::domain("example.com");
163/// assert_eq!(host.to_string(), "example.com");
164///
165/// // IPv4 address
166/// let host = Host::from_str("192.168.1.1").unwrap();
167/// assert!(matches!(host, Host::Address(_)));
168///
169/// // IPv6 address
170/// let host = Host::from_str("[2001:db8::1]").unwrap();
171/// assert!(matches!(host, Host::Address(_)));
172/// ```
173#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
174pub enum Host {
175    /// A domain name (e.g., "example.com").
176    Domain(String),
177    /// An IP address (v4 or v6).
178    Address(IpAddr),
179}
180
181impl Host {
182    /// Create a new host from a domain name
183    ///
184    /// # Parameters
185    /// - `domain`: The domain name string
186    ///
187    /// # Returns
188    /// A new Host instance with the Domain variant
189    pub fn domain(domain: impl Into<String>) -> Self {
190        Host::Domain(domain.into())
191    }
192
193    /// Create a new host from an IPv4 address
194    ///
195    /// # Parameters
196    /// - `ip`: The IPv4 address as a string
197    ///
198    /// # Returns
199    /// A new Host instance with the Address variant
200    ///
201    /// # Panics
202    /// Panics if the input string is not a valid IPv4 address
203    pub fn ipv4(ip: impl Into<String>) -> Self {
204        Host::Address(IpAddr::V4(Ipv4Addr::from_str(ip.into().as_str()).unwrap()))
205    }
206
207    /// Create a new host from an IPv6 address
208    ///
209    /// # Parameters
210    /// - `ip`: The IPv6 address as a string
211    ///
212    /// # Returns
213    /// A new Host instance with the Address variant
214    ///
215    /// # Panics
216    /// Panics if the input string is not a valid IPv6 address
217    pub fn ipv6(ip: impl Into<String>) -> Self {
218        Host::Address(IpAddr::V6(Ipv6Addr::from_str(ip.into().as_str()).unwrap()))
219    }
220
221    /// Get the host as a string slice (only works for domain names).
222    /// For addresses, it converts to String.
223    ///
224    /// # Returns
225    /// The host as a string
226    pub fn as_str(&self) -> String {
227        match self {
228            Host::Domain(domain) => domain.clone(),
229            Host::Address(addr) => addr.to_string(),
230        }
231    }
232}
233
234impl fmt::Display for Host {
235    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236        match self {
237            Host::Domain(domain) => write!(f, "{}", domain),
238            Host::Address(addr) => write!(f, "{}", addr),
239        }
240    }
241}
242
243impl FromStr for Host {
244    type Err = Error;
245
246    fn from_str(s: &str) -> Result<Self> {
247        // Attempt to parse as IP address first
248        if let Ok(addr) = IpAddr::from_str(s) {
249            return Ok(Host::Address(addr));
250        } else if s.starts_with('[') {
251            if s.ends_with(']') {
252                // Properly formatted IPv6 with brackets
253                if let Ok(addr) = Ipv6Addr::from_str(&s[1..s.len()-1]) {
254                    return Ok(Host::Address(IpAddr::V6(addr)));
255                }
256                // If it looked like IPv6 but failed, treat as domain
257                Ok(Host::Domain(s.to_string()))
258            } else {
259                // String starts with '[' but doesn't end with ']' - malformed IPv6
260                Err(Error::InvalidUri(format!("Malformed IPv6 address (unclosed bracket): {}", s)))
261            }
262        } else {
263            // Assume domain name if not a valid IP
264            // TODO: Add stricter domain name validation?
265             if s.is_empty() {
266                 Err(Error::ParseError("Host cannot be empty".to_string()))
267             } else {
268                Ok(Host::Domain(s.to_string()))
269             }
270        }
271    }
272}
273
274impl From<IpAddr> for Host {
275    fn from(addr: IpAddr) -> Self {
276        Host::Address(addr)
277    }
278}
279
280impl From<Ipv4Addr> for Host {
281    fn from(addr: Ipv4Addr) -> Self {
282        Host::Address(IpAddr::V4(addr))
283    }
284}
285
286impl From<Ipv6Addr> for Host {
287    fn from(addr: Ipv6Addr) -> Self {
288        Host::Address(IpAddr::V6(addr))
289    }
290}
291
292/// SIP URI components as defined in RFC 3261
293///
294/// Represents a complete SIP URI with all its components. URIs are used throughout
295/// the SIP protocol to identify endpoints, proxy servers, redirect servers, and
296/// other network elements.
297///
298/// # Structure
299///
300/// A complete SIP URI has the following format:
301/// `sip:user:password@host:port;uri-parameters?headers`
302///
303/// # Examples
304///
305/// ```rust
306/// use rvoip_sip_core::prelude::*;
307/// use std::str::FromStr;
308///
309/// // Parse a URI from a string
310/// let uri = Uri::from_str("sip:alice@example.com").unwrap();
311///
312/// // Create a URI programmatically
313/// let uri = Uri::sip("example.com")
314///     .with_user("bob")
315///     .with_port(5060)
316///     .with_parameter(Param::transport("tcp"));
317///
318/// // Get components
319/// assert_eq!(uri.scheme.as_str(), "sip");
320/// assert_eq!(uri.username(), Some("bob"));
321/// assert_eq!(uri.port, Some(5060));
322/// assert_eq!(uri.transport(), Some("tcp"));
323/// ```
324#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
325pub struct Uri {
326    /// URI scheme (sip, sips, tel)
327    pub scheme: Scheme,
328    /// User part (optional)
329    pub user: Option<String>,
330    /// Password (optional, deprecated)
331    pub password: Option<String>,
332    /// Host (required)
333    pub host: Host,
334    /// Port (optional)
335    pub port: Option<u16>,
336    /// URI parameters (;key=value or ;key)
337    pub parameters: Vec<Param>,
338    /// URI headers (?key=value)
339    pub headers: HashMap<String, String>,
340    /// Raw URI string for custom schemes
341    pub raw_uri: Option<String>,
342}
343
344impl Uri {
345    /// Create a new URI with the minimum required fields
346    ///
347    /// # Parameters
348    /// - `scheme`: The URI scheme
349    /// - `host`: The host part
350    ///
351    /// # Returns
352    /// A new URI instance with the given scheme and host
353    pub fn new(scheme: Scheme, host: Host) -> Self {
354        Uri {
355            scheme,
356            user: None,
357            password: None,
358            host,
359            port: None,
360            parameters: Vec::new(),
361            headers: HashMap::new(),
362            raw_uri: None,
363        }
364    }
365
366    /// Returns the scheme of this URI
367    ///
368    /// # Returns
369    /// The scheme (e.g., Sip, Sips, Tel)
370    pub fn scheme(&self) -> &Scheme {
371        &self.scheme
372    }
373    
374    /// Returns the host and port (if present) formatted as a string
375    ///
376    /// # Returns
377    /// The host and port as a string (e.g., "example.com:5060")
378    pub fn host_port(&self) -> String {
379        match self.port {
380            Some(port) if port > 0 => format!("{}:{}", self.host, port),
381            _ => self.host.to_string()
382        }
383    }
384
385    /// Create a new SIP URI with a domain host
386    ///
387    /// # Parameters
388    /// - `host`: The domain name
389    ///
390    /// # Returns
391    /// A new URI with SIP scheme and the given domain host
392    ///
393    /// # Examples
394    ///
395    /// ```
396    /// use rvoip_sip_core::prelude::*;
397    ///
398    /// let uri = Uri::sip("example.com");
399    /// assert_eq!(uri.to_string(), "sip:example.com");
400    /// ```
401    pub fn sip(host: impl Into<String>) -> Self {
402        Self::new(Scheme::Sip, Host::domain(host))
403    }
404
405    /// Create a new SIP URI with an IPv4 host
406    ///
407    /// # Parameters
408    /// - `host`: The IPv4 address as a string
409    ///
410    /// # Returns
411    /// A new URI with SIP scheme and the given IPv4 host
412    ///
413    /// # Examples
414    ///
415    /// ```
416    /// use rvoip_sip_core::prelude::*;
417    ///
418    /// let uri = Uri::sip_ipv4("192.168.1.1");
419    /// assert_eq!(uri.to_string(), "sip:192.168.1.1");
420    /// ```
421    pub fn sip_ipv4(host: impl Into<String>) -> Self {
422        Self::new(Scheme::Sip, Host::ipv4(host))
423    }
424
425    /// Create a new SIP URI with an IPv6 host
426    ///
427    /// # Parameters
428    /// - `host`: The IPv6 address as a string
429    ///
430    /// # Returns
431    /// A new URI with SIP scheme and the given IPv6 host
432    ///
433    /// # Examples
434    ///
435    /// ```
436    /// use rvoip_sip_core::prelude::*;
437    ///
438    /// let uri = Uri::sip_ipv6("2001:db8::1");
439    /// assert_eq!(uri.to_string(), "sip:[2001:db8::1]");
440    /// ```
441    pub fn sip_ipv6(host: impl Into<String>) -> Self {
442        Self::new(Scheme::Sip, Host::ipv6(host))
443    }
444
445    /// Create a new SIPS URI
446    ///
447    /// # Parameters
448    /// - `host`: The domain name
449    ///
450    /// # Returns
451    /// A new URI with SIPS scheme and the given domain host
452    pub fn sips(host: impl Into<String>) -> Self {
453        Self::new(Scheme::Sips, Host::domain(host))
454    }
455
456    /// Create a new TEL URI
457    ///
458    /// # Parameters
459    /// - `number`: The telephone number
460    ///
461    /// # Returns
462    /// A new URI with TEL scheme and the given number as host
463    pub fn tel(number: impl Into<String>) -> Self {
464        Self::new(Scheme::Tel, Host::domain(number))
465    }
466
467    /// Create a new HTTP URI
468    ///
469    /// # Parameters
470    /// - `host`: The domain name
471    ///
472    /// # Returns
473    /// A new URI with HTTP scheme and the given domain host
474    ///
475    /// # Examples
476    ///
477    /// ```
478    /// use rvoip_sip_core::prelude::*;
479    ///
480    /// let uri = Uri::http("example.com");
481    /// assert_eq!(uri.to_string(), "http:example.com");
482    /// ```
483    pub fn http(host: impl Into<String>) -> Self {
484        Self::new(Scheme::Http, Host::domain(host))
485    }
486
487    /// Create a new HTTPS URI
488    ///
489    /// # Parameters
490    /// - `host`: The domain name
491    ///
492    /// # Returns
493    /// A new URI with HTTPS scheme and the given domain host
494    ///
495    /// # Examples
496    ///
497    /// ```
498    /// use rvoip_sip_core::prelude::*;
499    ///
500    /// let uri = Uri::https("example.com");
501    /// assert_eq!(uri.to_string(), "https:example.com");
502    /// ```
503    pub fn https(host: impl Into<String>) -> Self {
504        Self::new(Scheme::Https, Host::domain(host))
505    }
506
507    /// Create a new URI with a custom scheme by storing the entire URI string
508    /// This is used for schemes that are not explicitly supported (like http, https)
509    /// but need to be preserved in the Call-Info header
510    ///
511    /// # Parameters
512    /// - `uri_string`: The full URI string
513    ///
514    /// # Returns
515    /// A new URI with the appropriate scheme and preserved raw string
516    pub fn custom(uri_string: impl Into<String>) -> Self {
517        let uri_string = uri_string.into();
518        
519        // Try to extract the scheme if possible
520        let scheme = if let Some(colon_pos) = uri_string.find(':') {
521            let scheme_str = &uri_string[0..colon_pos];
522            match scheme_str.to_lowercase().as_str() {
523                "http" => Scheme::Http,
524                "https" => Scheme::Https,
525                "tel" => Scheme::Tel,
526                "sip" => Scheme::Sip,
527                "sips" => Scheme::Sips,
528                _ => Scheme::Custom(scheme_str.to_string()), // Preserve custom schemes
529            }
530        } else {
531            // If no scheme found, create a custom scheme from the whole string
532            Scheme::Custom(uri_string.clone())
533        };
534        
535        Uri {
536            scheme,
537            user: None,
538            password: None,
539            host: Host::domain("unknown.host"), // Placeholder host
540            port: None,
541            parameters: Vec::new(),
542            headers: HashMap::new(),
543            raw_uri: Some(uri_string),
544        }
545    }
546
547    /// Check if this URI has a custom scheme (non-SIP)
548    ///
549    /// # Returns
550    /// `true` if this is a custom URI, `false` otherwise
551    pub fn is_custom(&self) -> bool {
552        self.raw_uri.is_some()
553    }
554
555    /// Get the raw URI string if this is a custom URI
556    ///
557    /// # Returns
558    /// The raw URI string if this is a custom URI, `None` otherwise
559    pub fn as_raw_uri(&self) -> Option<&str> {
560        self.raw_uri.as_deref()
561    }
562
563    /// Get the username part of the URI, if present
564    ///
565    /// # Returns
566    /// The username as a string slice, or `None` if not set
567    pub fn username(&self) -> Option<&str> {
568        self.user.as_deref()
569    }
570
571    /// Set the user part of the URI
572    ///
573    /// # Parameters
574    /// - `user`: The user part to set
575    ///
576    /// # Returns
577    /// Self for method chaining
578    pub fn with_user(mut self, user: impl Into<String>) -> Self {
579        self.user = Some(user.into());
580        self
581    }
582
583    /// Set the password part of the URI (deprecated in SIP)
584    ///
585    /// # Parameters
586    /// - `password`: The password to set
587    ///
588    /// # Returns
589    /// Self for method chaining
590    ///
591    /// # Note
592    /// Passwords in SIP URIs are deprecated for security reasons,
593    /// but supported for compatibility.
594    pub fn with_password(mut self, password: impl Into<String>) -> Self {
595        self.password = Some(password.into());
596        self
597    }
598
599    /// Set the port part of the URI
600    ///
601    /// # Parameters
602    /// - `port`: The port number
603    ///
604    /// # Returns
605    /// Self for method chaining
606    pub fn with_port(mut self, port: u16) -> Self {
607        self.port = Some(port);
608        self
609    }
610
611    /// Add a parameter to the URI
612    ///
613    /// # Parameters
614    /// - `param`: The parameter to add
615    ///
616    /// # Returns
617    /// Self for method chaining
618    ///
619    /// # Examples
620    /// ```
621    /// use rvoip_sip_core::prelude::*;
622    ///
623    /// let uri = Uri::sip("example.com")
624    ///     .with_parameter(Param::transport("tcp"))
625    ///     .with_parameter(Param::ttl(60));
626    ///
627    /// assert_eq!(uri.to_string(), "sip:example.com;transport=tcp;ttl=60");
628    /// ```
629    pub fn with_parameter(mut self, param: Param) -> Self {
630        self.parameters.push(param);
631        self
632    }
633
634    /// Add a header to the URI
635    ///
636    /// # Parameters
637    /// - `key`: The header name
638    /// - `value`: The header value
639    ///
640    /// # Returns
641    /// Self for method chaining
642    ///
643    /// # Examples
644    /// ```
645    /// use rvoip_sip_core::prelude::*;
646    ///
647    /// let uri = Uri::sip("example.com")
648    ///     .with_header("subject", "Meeting")
649    ///     .with_header("priority", "urgent");
650    ///
651    /// // Headers are added to the URI string
652    /// let uri_str = uri.to_string();
653    /// assert!(uri_str.contains("subject=Meeting"));
654    /// assert!(uri_str.contains("priority=urgent"));
655    /// ```
656    pub fn with_header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
657        self.headers.insert(key.into(), value.into());
658        self
659    }
660
661    /// Returns the transport parameter if present
662    ///
663    /// # Returns
664    /// The transport value as a string slice, or `None` if not set
665    ///
666    /// # Examples
667    /// ```
668    /// use rvoip_sip_core::prelude::*;
669    ///
670    /// let uri = Uri::sip("example.com")
671    ///     .with_parameter(Param::transport("tcp"));
672    ///
673    /// assert_eq!(uri.transport(), Some("tcp"));
674    /// ```
675    pub fn transport(&self) -> Option<&str> {
676        self.parameters.iter().find_map(|p| match p {
677            Param::Transport(val) => Some(val.as_str()),
678            _ => None,
679        })
680    }
681
682    /// Returns the user=phone parameter if present
683    ///
684    /// # Returns
685    /// `true` if the URI has the user=phone parameter, `false` otherwise
686    ///
687    /// # Examples
688    /// ```
689    /// use rvoip_sip_core::prelude::*;
690    /// use std::str::FromStr;
691    ///
692    /// let uri = Uri::from_str("sip:+12125551212@example.com;user=phone").unwrap();
693    /// assert!(uri.is_phone_number());
694    ///
695    /// let uri = Uri::sip("example.com").with_user("alice");
696    /// assert!(!uri.is_phone_number());
697    /// ```
698    pub fn is_phone_number(&self) -> bool {
699        self.parameters.iter().any(|p| match p {
700            Param::User(val) if val == "phone" => true,
701            _ => false,
702        })
703    }
704}
705
706impl fmt::Display for Uri {
707    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
708        // If this is a custom URI, just output the raw string
709        if let Some(raw_uri) = &self.raw_uri {
710            return f.write_str(raw_uri);
711        }
712
713        // Normal URI formatting
714        write!(f, "{}:", self.scheme)?;
715        
716        // User info (username and optional password)
717        if let Some(ref user) = self.user {
718            let escaped_user = escape_user_info(user);
719            write!(f, "{}", escaped_user)?;
720            
721            if let Some(ref password) = self.password {
722                let escaped_password = escape_user_info(password);
723                write!(f, ":{}", escaped_password)?;
724            }
725            
726            write!(f, "@")?;
727        }
728        
729        // Host (domain or IP address)
730        match &self.host {
731            Host::Domain(domain) => write!(f, "{}", domain)?,
732            Host::Address(IpAddr::V4(addr)) => write!(f, "{}", addr)?,
733            Host::Address(IpAddr::V6(addr)) => write!(f, "[{}]", addr)?,
734        }
735        
736        // Optional port (only if not 0)
737        if let Some(port) = self.port {
738            // Don't show port 0
739            if port > 0 {
740                write!(f, ":{}", port)?;
741            }
742        }
743        
744        // Parameters (;key=value or ;key)
745        for param in &self.parameters {
746            write!(f, ";{}", param)?;
747        }
748        
749        // Headers (?key=value&key=value)
750        if !self.headers.is_empty() {
751            let mut first = true;
752            for (key, value) in &self.headers {
753                if first {
754                    write!(f, "?")?;
755                    first = false;
756                } else {
757                    write!(f, "&")?;
758                }
759                
760                // URL-encode key and value
761                write!(f, "{}={}", escape_param(key), escape_param(value))?;
762            }
763        }
764        
765        Ok(())
766    }
767}
768
769// Use the internal nom parser for FromStr
770impl FromStr for Uri {
771    type Err = Error;
772
773    fn from_str(s: &str) -> Result<Self> {
774        // Use the nom parser from the parser module
775        match all_consuming(parse_uri)(s.as_bytes()) {
776            Ok((_rem, uri)) => Ok(uri),
777            Err(e) => {
778                // For HTTP and HTTPS URIs, create a special case
779                if s.starts_with("http://") || s.starts_with("https://") {
780                    let scheme = if s.starts_with("https://") { 
781                        Scheme::Https 
782                    } else { 
783                        Scheme::Http 
784                    };
785                    
786                    // Extract host from the URL (simple implementation)
787                    let without_scheme = if s.starts_with("https://") {
788                        &s[8..]
789                    } else {
790                        &s[7..]
791                    };
792                    
793                    let host_part = without_scheme
794                        .split('/')
795                        .next()
796                        .unwrap_or(without_scheme);
797                    
798                    return Ok(Uri {
799                        scheme,
800                        user: None,
801                        password: None,
802                        host: Host::domain(host_part),
803                        port: None,
804                        parameters: Vec::new(),
805                        headers: HashMap::new(),
806                        raw_uri: Some(s.to_string()),
807                    });
808                }
809                
810                // Otherwise return the original error
811                Err(Error::from(e.to_owned())) // Convert nom::Err to crate::error::Error
812            }
813        }
814    }
815}
816
817// Use the internal nom parser for From<&str>
818impl<'a> From<&'a str> for Uri {
819    fn from(s: &'a str) -> Self {
820        // Attempt to parse using the internal nom parser.
821        // If it fails, fall back to a custom URI with the raw string.
822        Uri::from_str(s).unwrap_or_else(|_| {
823            // If parsing fails, create a custom URI to preserve the string
824            Uri::custom(s)
825        })
826    }
827}
828
829// Parser-related functions need to be reimplemented or imported from parser module
830// For now we'll just include the basic utility functions used by the URI implementation
831
832// --- Helper functions (escape/unescape, validation) ---
833
834/// Escape URI user info component according to RFC 3261
835///
836/// This escapes characters in the user info component (username/password)
837/// using percent-encoding as specified in the RFC.
838///
839/// # Parameters
840/// - `s`: The string to escape
841///
842/// # Returns
843/// The escaped string
844fn escape_user_info(s: &str) -> String {
845    let mut result = String::with_capacity(s.len() * 3); // Worst case: all chars need escaping (×3)
846
847    for c in s.chars() {
848        match c {
849            'a'..='z' | 'A'..='Z' | '0'..='9' |
850            '-' | '_' | '.' | '!' | '~' | '*' | '\'' | '(' | ')' => {
851                result.push(c);
852            },
853            _ => {
854                // Escape all other characters
855                for byte in c.to_string().bytes() {
856                    result.push('%');
857                    result.push_str(&format!("{:02X}", byte));
858                }
859            }
860        }
861    }
862
863    result
864}
865
866/// Unescape URI user info component
867fn unescape_user_info(s: &str) -> Result<String> {
868    let mut result = String::with_capacity(s.len());
869    let mut chars = s.chars().peekable();
870
871    while let Some(c) = chars.next() {
872        if c == '%' {
873            let mut hex = String::with_capacity(2);
874
875            if let Some(h1) = chars.next() {
876                hex.push(h1);
877            } else {
878                return Err(Error::MalformedUriComponent {
879                    component: "user info".to_string(),
880                    message: "Incomplete percent encoding".to_string()
881                });
882            }
883
884            if let Some(h2) = chars.next() {
885                hex.push(h2);
886            } else {
887                return Err(Error::MalformedUriComponent {
888                    component: "user info".to_string(),
889                    message: "Incomplete percent encoding".to_string()
890                });
891            }
892
893            if let Ok(byte) = u8::from_str_radix(&hex, 16) {
894                result.push(byte as char);
895            } else {
896                return Err(Error::MalformedUriComponent {
897                    component: "user info".to_string(),
898                    message: format!("Invalid percent encoding: %{}", hex)
899                });
900            }
901        } else {
902            result.push(c);
903        }
904    }
905
906    Ok(result)
907}
908
909/// Escape URI parameters and headers
910fn escape_param(s: &str) -> String {
911    let mut result = String::with_capacity(s.len() * 3);
912
913    for c in s.chars() {
914        match c {
915            'a'..='z' | 'A'..='Z' | '0'..='9' |
916            '-' | '_' | '.' | '!' | '~' | '*' | '\'' | '(' | ')' | '+' => {
917                result.push(c);
918            },
919            _ => {
920                // Escape all other characters
921                for byte in c.to_string().bytes() {
922                    result.push('%');
923                    result.push_str(&format!("{:02X}", byte));
924                }
925            }
926        }
927    }
928
929    result
930}
931
932/// Unescape URI parameters and headers
933fn unescape_param(s: &str) -> Result<String> {
934    unescape_user_info(s) // Same algorithm
935}
936
937/// Check if a string is a valid IPv4 address
938fn is_valid_ipv4(s: &str) -> bool {
939    let parts: Vec<&str> = s.split('.').collect();
940
941    if parts.len() != 4 {
942        return false;
943    }
944
945    for part in parts {
946        match part.parse::<u8>() {
947            Ok(_) => continue,
948            Err(_) => return false,
949        }
950    }
951
952    true
953}
954
955/// Check if a string is a valid IPv6 address (simplified validation)
956fn is_valid_ipv6(s: &str) -> bool {
957    // Check for basic IPv6 format
958    let parts = s.split(':').collect::<Vec<&str>>();
959
960    // IPv6 has 8 parts max, or fewer if contains ::
961    if parts.len() > 8 {
962        return false;
963    }
964
965    // Check for empty parts (::)
966    let empty_parts = parts.iter().filter(|p| p.is_empty()).count();
967
968    // Handle :: (consecutive colons)
969    if empty_parts > 0 {
970        if empty_parts > 2 || (empty_parts == 2 && !s.contains("::")) {
971            return false;
972        }
973    }
974
975    // Validate each part
976    for part in parts {
977        if part.is_empty() {
978            continue; // Empty part due to ::
979        }
980
981        // Check if it's an IPv4 address in the last part (IPv4-mapped IPv6)
982        if part.contains('.') {
983            return is_valid_ipv4(part);
984        }
985
986        // Each part should be a valid hex number with at most 4 digits
987        if part.len() > 4 || !part.chars().all(|c| c.is_ascii_hexdigit()) {
988            return false;
989        }
990    }
991
992    true
993}