@@ -64,20 +64,18 @@ where
64
64
let version = version. ok_or_else ( || format_err ! ( "No version found" ) ) ?;
65
65
ensure_eq ! ( version, HTTP_1_1_VERSION , "Unsupported HTTP version" ) ;
66
66
67
- let mut req = Request :: new ( Method :: from_str ( method) ?, url:: Url :: parse ( "x:" ) . unwrap ( ) ) ;
67
+ let mut req = Request :: new (
68
+ Method :: from_str ( method) ?,
69
+ url:: Url :: parse ( "http://_" ) . unwrap ( ) . join ( path) ?,
70
+ ) ;
68
71
69
72
for header in httparse_req. headers . iter ( ) {
70
73
let name = HeaderName :: from_str ( header. name ) ?;
71
74
let value = HeaderValue :: from_str ( std:: str:: from_utf8 ( header. value ) ?) ?;
72
75
req. insert_header ( name, value) ?;
73
76
}
74
77
75
- let host = req
76
- . header ( & HOST )
77
- . and_then ( |header| header. last ( ) )
78
- . ok_or_else ( || format_err ! ( "Mandatory host header missing" ) ) ?;
79
-
80
- * req. url_mut ( ) = url:: Url :: parse ( & format ! ( "http://{}" , host. as_str( ) ) ) ?. join ( path) ?;
78
+ set_url_and_port_from_host_header ( & mut req) ?;
81
79
82
80
let content_length = req. header ( & CONTENT_LENGTH ) ;
83
81
let transfer_encoding = req. header ( & TRANSFER_ENCODING ) ;
@@ -106,3 +104,103 @@ where
106
104
107
105
Ok ( Some ( req) )
108
106
}
107
+
108
+ fn set_url_and_port_from_host_header ( req : & mut Request ) -> http_types:: Result < ( ) > {
109
+ let host = req
110
+ . header ( & HOST )
111
+ . and_then ( |header| header. last ( ) ) // There must only exactly one Host header, so this is permissive
112
+ . ok_or_else ( || format_err ! ( "Mandatory Host header missing" ) ) ?; // https://tools.ietf.org/html/rfc7230#section-5.4
113
+
114
+ let host = host. to_string ( ) ;
115
+ if let Some ( colon) = host. find ( ":" ) {
116
+ req. url_mut ( ) . set_host ( Some ( & host[ 0 ..colon] ) ) ?;
117
+ req. url_mut ( )
118
+ . set_port ( host[ colon + 1 ..] . parse ( ) . ok ( ) )
119
+ . unwrap ( ) ;
120
+ } else {
121
+ req. url_mut ( ) . set_host ( Some ( & host) ) ?;
122
+ }
123
+
124
+ Ok ( ( ) )
125
+ }
126
+
127
+ #[ cfg( test) ]
128
+ mod tests {
129
+ use super :: * ;
130
+
131
+ fn request_with_host_header ( host : & str ) -> Request {
132
+ let mut req = Request :: new (
133
+ Method :: from_str ( "GET" ) . unwrap ( ) ,
134
+ url:: Url :: parse ( "http://_" )
135
+ . unwrap ( )
136
+ . join ( "/some/path" )
137
+ . unwrap ( ) ,
138
+ ) ;
139
+
140
+ req. insert_header ( HOST , host) . unwrap ( ) ;
141
+
142
+ req
143
+ }
144
+
145
+ #[ test]
146
+ fn test_setting_host_with_no_port ( ) {
147
+ let mut request = request_with_host_header ( "subdomain.mydomain.tld" ) ;
148
+ set_url_and_port_from_host_header ( & mut request) . unwrap ( ) ;
149
+ assert_eq ! (
150
+ request. url( ) ,
151
+ & url:: Url :: parse( "http://subdomain.mydomain.tld/some/path" ) . unwrap( )
152
+ ) ;
153
+ }
154
+
155
+ #[ test]
156
+ fn test_setting_host_with_a_port ( ) {
157
+ let mut request = request_with_host_header ( "subdomain.mydomain.tld:8080" ) ;
158
+ set_url_and_port_from_host_header ( & mut request) . unwrap ( ) ;
159
+ assert_eq ! (
160
+ request. url( ) ,
161
+ & url:: Url :: parse( "http://subdomain.mydomain.tld:8080/some/path" ) . unwrap( )
162
+ ) ;
163
+ }
164
+
165
+ #[ test]
166
+ fn test_setting_host_with_an_ip_and_port ( ) {
167
+ let mut request = request_with_host_header ( "12.34.56.78:90" ) ;
168
+ set_url_and_port_from_host_header ( & mut request) . unwrap ( ) ;
169
+ assert_eq ! (
170
+ request. url( ) ,
171
+ & url:: Url :: parse( "http://12.34.56.78:90/some/path" ) . unwrap( )
172
+ ) ;
173
+ }
174
+
175
+ #[ test]
176
+ fn test_malformed_nonnumeric_port_is_ignored ( ) {
177
+ let mut request = request_with_host_header ( "hello.world:uh-oh" ) ;
178
+ set_url_and_port_from_host_header ( & mut request) . unwrap ( ) ;
179
+ assert_eq ! (
180
+ request. url( ) ,
181
+ & url:: Url :: parse( "http://hello.world/some/path" ) . unwrap( )
182
+ ) ;
183
+ }
184
+
185
+ #[ test]
186
+ fn test_malformed_trailing_colon_is_ignored ( ) {
187
+ let mut request = request_with_host_header ( "edge.cases:" ) ;
188
+ set_url_and_port_from_host_header ( & mut request) . unwrap ( ) ;
189
+ assert_eq ! (
190
+ request. url( ) ,
191
+ & url:: Url :: parse( "http://edge.cases/some/path" ) . unwrap( )
192
+ ) ;
193
+ }
194
+
195
+ #[ test]
196
+ fn test_malformed_leading_colon_is_invalid_host_value ( ) {
197
+ let mut request = request_with_host_header ( ":300" ) ;
198
+ assert ! ( set_url_and_port_from_host_header( & mut request) . is_err( ) ) ;
199
+ }
200
+
201
+ #[ test]
202
+ fn test_malformed_invalid_url_host_is_invalid_host_header_value ( ) {
203
+ let mut request = request_with_host_header ( " " ) ;
204
+ assert ! ( set_url_and_port_from_host_header( & mut request) . is_err( ) ) ;
205
+ }
206
+ }
0 commit comments