1
1
//! Client Requests
2
2
use std:: marker:: PhantomData ;
3
- use std:: io:: { self , Write , BufWriter } ;
3
+ use std:: io:: { self , Write } ;
4
4
5
5
use url:: Url ;
6
6
7
7
use method:: { self , Method } ;
8
8
use header:: Headers ;
9
- use header:: { self , Host } ;
9
+ use header:: Host ;
10
10
use net:: { NetworkStream , NetworkConnector , HttpConnector , Fresh , Streaming } ;
11
- use http:: { HttpWriter , LINE_ENDING } ;
12
- use http:: HttpWriter :: { ThroughWriter , ChunkedWriter , SizedWriter , EmptyWriter } ;
13
11
use version;
14
12
use client:: { Response , get_host_and_port} ;
15
13
14
+ use message:: { HttpMessage , RequestHead } ;
15
+ use http11:: Http11Message ;
16
+
16
17
17
18
/// A client request to a remote server.
18
19
/// The W type tracks the state of the request, Fresh vs Streaming.
@@ -23,7 +24,7 @@ pub struct Request<W> {
23
24
/// The HTTP version of this request.
24
25
pub version : version:: HttpVersion ,
25
26
26
- body : HttpWriter < BufWriter < Box < NetworkStream + Send > > > ,
27
+ message : Box < HttpMessage > ,
27
28
headers : Headers ,
28
29
method : method:: Method ,
29
30
@@ -41,22 +42,12 @@ impl<W> Request<W> {
41
42
}
42
43
43
44
impl Request < Fresh > {
44
- /// Create a new client request.
45
- pub fn new ( method : method:: Method , url : Url ) -> :: Result < Request < Fresh > > {
46
- let mut conn = HttpConnector ( None ) ;
47
- Request :: with_connector ( method, url, & mut conn)
48
- }
49
-
50
- /// Create a new client request with a specific underlying NetworkStream.
51
- pub fn with_connector < C , S > ( method : method:: Method , url : Url , connector : & C )
52
- -> :: Result < Request < Fresh > > where
53
- C : NetworkConnector < Stream =S > ,
54
- S : Into < Box < NetworkStream + Send > > {
45
+ /// Create a new `Request<Fresh>` that will use the given `HttpMessage` for its communication
46
+ /// with the server. This implies that the given `HttpMessage` instance has already been
47
+ /// properly initialized by the caller (e.g. a TCP connection's already established).
48
+ pub fn with_message ( method : method:: Method , url : Url , message : Box < HttpMessage > )
49
+ -> :: Result < Request < Fresh > > {
55
50
let ( host, port) = try!( get_host_and_port ( & url) ) ;
56
-
57
- let stream = try!( connector. connect ( & * host, port, & * url. scheme ) ) . into ( ) ;
58
- let stream = ThroughWriter ( BufWriter :: new ( stream) ) ;
59
-
60
51
let mut headers = Headers :: new ( ) ;
61
52
headers. set ( Host {
62
53
hostname : host,
@@ -68,77 +59,43 @@ impl Request<Fresh> {
68
59
headers : headers,
69
60
url : url,
70
61
version : version:: HttpVersion :: Http11 ,
71
- body : stream ,
62
+ message : message ,
72
63
_marker : PhantomData ,
73
64
} )
74
65
}
75
66
76
- /// Consume a Fresh Request, writing the headers and method,
77
- /// returning a Streaming Request.
78
- pub fn start ( mut self ) -> :: Result < Request < Streaming > > {
79
- let mut uri = self . url . serialize_path ( ) . unwrap ( ) ;
80
- if let Some ( ref q) = self . url . query {
81
- uri. push ( '?' ) ;
82
- uri. push_str ( & q[ ..] ) ;
83
- }
84
-
85
- debug ! ( "request line: {:?} {:?} {:?}" , self . method, uri, self . version) ;
86
- try!( write ! ( & mut self . body, "{} {} {}{}" ,
87
- self . method, uri, self . version, LINE_ENDING ) ) ;
88
-
89
-
90
- let stream = match self . method {
91
- Method :: Get | Method :: Head => {
92
- debug ! ( "headers={:?}" , self . headers) ;
93
- try!( write ! ( & mut self . body, "{}{}" , self . headers, LINE_ENDING ) ) ;
94
- EmptyWriter ( self . body . into_inner ( ) )
95
- } ,
96
- _ => {
97
- let mut chunked = true ;
98
- let mut len = 0 ;
99
-
100
- match self . headers . get :: < header:: ContentLength > ( ) {
101
- Some ( cl) => {
102
- chunked = false ;
103
- len = * * cl;
104
- } ,
105
- None => ( )
106
- } ;
107
-
108
- // can't do in match above, thanks borrowck
109
- if chunked {
110
- let encodings = match self . headers . get_mut :: < header:: TransferEncoding > ( ) {
111
- Some ( & mut header:: TransferEncoding ( ref mut encodings) ) => {
112
- //TODO: check if chunked is already in encodings. use HashSet?
113
- encodings. push ( header:: Encoding :: Chunked ) ;
114
- false
115
- } ,
116
- None => true
117
- } ;
118
-
119
- if encodings {
120
- self . headers . set :: < header:: TransferEncoding > (
121
- header:: TransferEncoding ( vec ! [ header:: Encoding :: Chunked ] ) )
122
- }
123
- }
67
+ /// Create a new client request.
68
+ pub fn new ( method : method:: Method , url : Url ) -> :: Result < Request < Fresh > > {
69
+ let mut conn = HttpConnector ( None ) ;
70
+ Request :: with_connector ( method, url, & mut conn)
71
+ }
124
72
125
- debug ! ( "headers={:?}" , self . headers) ;
126
- try!( write ! ( & mut self . body, "{}{}" , self . headers, LINE_ENDING ) ) ;
73
+ /// Create a new client request with a specific underlying NetworkStream.
74
+ pub fn with_connector < C , S > ( method : method:: Method , url : Url , connector : & C )
75
+ -> :: Result < Request < Fresh > > where
76
+ C : NetworkConnector < Stream =S > ,
77
+ S : Into < Box < NetworkStream + Send > > {
78
+ let ( host, port) = try!( get_host_and_port ( & url) ) ;
79
+ let stream = try!( connector. connect ( & * host, port, & * url. scheme ) ) . into ( ) ;
127
80
128
- if chunked {
129
- ChunkedWriter ( self . body . into_inner ( ) )
130
- } else {
131
- SizedWriter ( self . body . into_inner ( ) , len)
132
- }
133
- }
134
- } ;
81
+ Request :: with_message ( method, url, Box :: new ( Http11Message :: with_stream ( stream) ) )
82
+ }
135
83
136
- Ok ( Request {
137
- method : self . method ,
84
+ /// Consume a Fresh Request, writing the headers and method,
85
+ /// returning a Streaming Request.
86
+ pub fn start ( mut self ) -> :: Result < Request < Streaming > > {
87
+ let head = try!( self . message . set_outgoing ( RequestHead {
138
88
headers : self . headers ,
89
+ method : self . method ,
139
90
url : self . url ,
91
+ } ) ) ;
92
+
93
+ Ok ( Request {
94
+ method : head. method ,
95
+ headers : head. headers ,
96
+ url : head. url ,
140
97
version : self . version ,
141
- body : stream ,
98
+ message : self . message ,
142
99
_marker : PhantomData ,
143
100
} )
144
101
}
@@ -153,20 +110,19 @@ impl Request<Streaming> {
153
110
///
154
111
/// Consumes the Request.
155
112
pub fn send ( self ) -> :: Result < Response > {
156
- let raw = try!( self . body . end ( ) ) . into_inner ( ) . unwrap ( ) ; // end() already flushes
157
- Response :: new ( raw)
113
+ Response :: with_message ( self . message )
158
114
}
159
115
}
160
116
161
117
impl Write for Request < Streaming > {
162
118
#[ inline]
163
119
fn write ( & mut self , msg : & [ u8 ] ) -> io:: Result < usize > {
164
- self . body . write ( msg)
120
+ self . message . write ( msg)
165
121
}
166
122
167
123
#[ inline]
168
124
fn flush ( & mut self ) -> io:: Result < ( ) > {
169
- self . body . flush ( )
125
+ self . message . flush ( )
170
126
}
171
127
}
172
128
@@ -180,11 +136,15 @@ mod tests {
180
136
use header:: { ContentLength , TransferEncoding , Encoding } ;
181
137
use url:: form_urlencoded;
182
138
use super :: Request ;
139
+ use http11:: Http11Message ;
183
140
184
141
fn run_request ( req : Request < Fresh > ) -> Vec < u8 > {
185
142
let req = req. start ( ) . unwrap ( ) ;
186
- let stream = * req. body . end ( ) . unwrap ( )
187
- . into_inner ( ) . unwrap ( ) . downcast :: < MockStream > ( ) . ok ( ) . unwrap ( ) ;
143
+ let message = req. message ;
144
+ let mut message = message. downcast :: < Http11Message > ( ) . ok ( ) . unwrap ( ) ;
145
+ message. flush_outgoing ( ) . unwrap ( ) ;
146
+ let stream = * message
147
+ . into_inner ( ) . downcast :: < MockStream > ( ) . ok ( ) . unwrap ( ) ;
188
148
stream. write
189
149
}
190
150
0 commit comments