@@ -55,6 +55,17 @@ pub struct Url {
55
55
fragment : Option < ~str >
56
56
}
57
57
58
+ #[ deriving( Clone , Eq ) ]
59
+ pub struct Path {
60
+ /// The path component of a URL, for example `/foo/bar`.
61
+ path : ~str ,
62
+ /// The query component of a URL. `~[(~"baz", ~"qux")]` represents the
63
+ /// fragment `baz=qux` in the above example.
64
+ query : Query ,
65
+ /// The fragment component, such as `quz`. Doesn't include the leading `#` character.
66
+ fragment : Option < ~str >
67
+ }
68
+
58
69
/// An optional subcomponent of a URI authority component.
59
70
#[ deriving( Clone , Eq ) ]
60
71
pub struct UserInfo {
@@ -88,6 +99,19 @@ impl Url {
88
99
}
89
100
}
90
101
102
+ impl Path {
103
+ pub fn new ( path : ~str ,
104
+ query : Query ,
105
+ fragment : Option < ~str > )
106
+ -> Path {
107
+ Path {
108
+ path : path,
109
+ query : query,
110
+ fragment : fragment,
111
+ }
112
+ }
113
+ }
114
+
91
115
impl UserInfo {
92
116
#[ inline]
93
117
pub fn new ( user : ~str , pass : Option < ~str > ) -> UserInfo {
@@ -695,6 +719,21 @@ pub fn from_str(rawurl: &str) -> Result<Url, ~str> {
695
719
Ok ( Url :: new ( scheme, userinfo, host, port, path, query, fragment) )
696
720
}
697
721
722
+ pub fn path_from_str ( rawpath : & str ) -> Result < Path , ~str > {
723
+ let ( path, rest) = match get_path ( rawpath, false ) {
724
+ Ok ( val) => val,
725
+ Err ( e) => return Err ( e)
726
+ } ;
727
+
728
+ // query and fragment
729
+ let ( query, fragment) = match get_query_fragment ( rest) {
730
+ Ok ( val) => val,
731
+ Err ( e) => return Err ( e) ,
732
+ } ;
733
+
734
+ Ok ( Path { path : path, query : query, fragment : fragment } )
735
+ }
736
+
698
737
impl FromStr for Url {
699
738
fn from_str ( s : & str ) -> Option < Url > {
700
739
match from_str ( s) {
@@ -704,6 +743,15 @@ impl FromStr for Url {
704
743
}
705
744
}
706
745
746
+ impl FromStr for Path {
747
+ fn from_str ( s : & str ) -> Option < Path > {
748
+ match path_from_str ( s) {
749
+ Ok ( path) => Some ( path) ,
750
+ Err ( _) => None
751
+ }
752
+ }
753
+ }
754
+
707
755
/**
708
756
* Format a `url` as a string
709
757
*
@@ -749,18 +797,45 @@ pub fn to_str(url: &Url) -> ~str {
749
797
format ! ( "{}:{}{}{}{}" , url. scheme, authority, url. path, query, fragment)
750
798
}
751
799
800
+ pub fn path_to_str( path : & Path ) -> ~str {
801
+ let query = if path. query . is_empty ( ) {
802
+ ~""
803
+ } else {
804
+ format ! ( "?{}" , query_to_str( & path. query) )
805
+ } ;
806
+
807
+ let fragment = match path. fragment {
808
+ Some ( ref fragment) => format ! ( "\\ #{}" , encode_component( * fragment) ) ,
809
+ None => ~"",
810
+ } ;
811
+
812
+ format ! ( "{}{}{}" , path. path, query, fragment)
813
+ }
814
+
752
815
impl ToStr for Url {
753
816
fn to_str ( & self ) -> ~str {
754
817
to_str ( self )
755
818
}
756
819
}
757
820
821
+ impl ToStr for Path {
822
+ fn to_str ( & self ) -> ~str {
823
+ path_to_str ( self )
824
+ }
825
+ }
826
+
758
827
impl IterBytes for Url {
759
828
fn iter_bytes ( & self , lsb0 : bool , f : to_bytes:: Cb ) -> bool {
760
829
self . to_str ( ) . iter_bytes ( lsb0, f)
761
830
}
762
831
}
763
832
833
+ impl IterBytes for Path {
834
+ fn iter_bytes ( & self , lsb0 : bool , f : to_bytes:: Cb ) -> bool {
835
+ self . to_str ( ) . iter_bytes ( lsb0, f)
836
+ }
837
+ }
838
+
764
839
// Put a few tests outside of the 'test' module so they can test the internal
765
840
// functions and those functions don't need 'pub'
766
841
@@ -868,6 +943,17 @@ mod tests {
868
943
assert_eq!(&u.fragment, &Some(~" something"));
869
944
}
870
945
946
+ #[test]
947
+ fn test_path_parse() {
948
+ let path = ~" /doc/~u?s=v#something";
949
+
950
+ let up = path_from_str(path);
951
+ let u = up.unwrap();
952
+ assert_eq!(&u.path, &~" /doc/~u");
953
+ assert_eq!(&u.query, &~[(~" s", ~" v")]);
954
+ assert_eq!(&u.fragment, &Some(~" something"));
955
+ }
956
+
871
957
#[test]
872
958
fn test_url_parse_host_slash() {
873
959
let urlstr = ~" http: //0.42.42.42/";
@@ -876,6 +962,13 @@ mod tests {
876
962
assert!(url.path == ~" /");
877
963
}
878
964
965
+ #[test]
966
+ fn test_path_parse_host_slash() {
967
+ let pathstr = ~" /";
968
+ let path = path_from_str(pathstr).unwrap();
969
+ assert!(path.path == ~" /");
970
+ }
971
+
879
972
#[test]
880
973
fn test_url_host_with_port() {
881
974
let urlstr = ~" scheme: //host:1234";
@@ -899,13 +992,27 @@ mod tests {
899
992
assert!( url. path == ~"/file_name. html");
900
993
}
901
994
995
+ #[test]
996
+ fn test_path_with_underscores() {
997
+ let pathstr = ~" /file_name. html";
998
+ let path = path_from_str(pathstr).unwrap();
999
+ assert!(path.path == ~" /file_name. html");
1000
+ }
1001
+
902
1002
#[test]
903
1003
fn test_url_with_dashes() {
904
1004
let urlstr = ~" http: //dotcom.com/file-name.html";
905
1005
let url = from_str( urlstr) . unwrap( ) ;
906
1006
assert!( url. path == ~"/file-name. html");
907
1007
}
908
1008
1009
+ #[test]
1010
+ fn test_path_with_dashes() {
1011
+ let pathstr = ~" /file-name. html";
1012
+ let path = path_from_str(pathstr).unwrap();
1013
+ assert!(path.path == ~" /file-name. html");
1014
+ }
1015
+
909
1016
#[test]
910
1017
fn test_no_scheme() {
911
1018
assert!(get_scheme(" noschemehere. html").is_err());
@@ -986,6 +1093,14 @@ mod tests {
986
1093
assert!(u.query == ~[(~" ba%d ", ~" #& +")]);
987
1094
}
988
1095
1096
+ #[test]
1097
+ fn test_path_component_encoding() {
1098
+ let path = ~" /doc%20 uments?ba%25 d%20 =%23 %26 %2 B ";
1099
+ let p = path_from_str(path).unwrap();
1100
+ assert!(p.path == ~" /doc uments");
1101
+ assert!(p.query == ~[(~" ba%d ", ~" #& +")]);
1102
+ }
1103
+
989
1104
#[test]
990
1105
fn test_url_without_authority() {
991
1106
let url = ~" mailto: test@email. com";
0 commit comments