1
1
//! HTTP Server
2
- use std:: io:: { BufReader , BufWriter } ;
2
+ use std:: io:: { BufReader , BufWriter , Write } ;
3
3
use std:: marker:: PhantomData ;
4
4
use std:: net:: { IpAddr , SocketAddr } ;
5
5
use std:: path:: Path ;
@@ -14,9 +14,12 @@ pub use net::{Fresh, Streaming};
14
14
15
15
use HttpError :: HttpIoError ;
16
16
use { HttpResult } ;
17
- use header:: Connection ;
17
+ use header:: { Headers , Connection , Expect } ;
18
18
use header:: ConnectionOption :: { Close , KeepAlive } ;
19
+ use method:: Method ;
19
20
use net:: { NetworkListener , NetworkStream , HttpListener } ;
21
+ use status:: StatusCode ;
22
+ use uri:: RequestUri ;
20
23
use version:: HttpVersion :: { Http10 , Http11 } ;
21
24
22
25
use self :: listener:: ListenerPool ;
@@ -99,7 +102,7 @@ S: NetworkStream + Clone + Send> Server<'a, H, L> {
99
102
100
103
debug ! ( "threads = {:?}" , threads) ;
101
104
let pool = ListenerPool :: new ( listener. clone ( ) ) ;
102
- let work = move |stream| keep_alive_loop ( stream, & handler) ;
105
+ let work = move |mut stream| handle_connection ( & mut stream, & handler) ;
103
106
104
107
let guard = thread:: scoped ( move || pool. accept ( work, threads) ) ;
105
108
@@ -111,7 +114,7 @@ S: NetworkStream + Clone + Send> Server<'a, H, L> {
111
114
}
112
115
113
116
114
- fn keep_alive_loop < ' h , S , H > ( mut stream : S , handler : & ' h H )
117
+ fn handle_connection < ' h , S , H > ( mut stream : & mut S , handler : & ' h H )
115
118
where S : NetworkStream + Clone , H : Handler {
116
119
debug ! ( "Incoming stream" ) ;
117
120
let addr = match stream. peer_addr ( ) {
@@ -128,39 +131,45 @@ where S: NetworkStream + Clone, H: Handler {
128
131
129
132
let mut keep_alive = true ;
130
133
while keep_alive {
131
- keep_alive = handle_connection ( addr, & mut rdr, & mut wrt, handler) ;
132
- debug ! ( "keep_alive = {:?}" , keep_alive) ;
133
- }
134
- }
134
+ let req = match Request :: new ( & mut rdr, addr) {
135
+ Ok ( req) => req,
136
+ Err ( e@HttpIoError ( _) ) => {
137
+ debug ! ( "ioerror in keepalive loop = {:?}" , e) ;
138
+ break ;
139
+ }
140
+ Err ( e) => {
141
+ //TODO: send a 400 response
142
+ error ! ( "request error = {:?}" , e) ;
143
+ break ;
144
+ }
145
+ } ;
135
146
136
- fn handle_connection < ' a , ' aa , ' h , S , H > (
137
- addr : SocketAddr ,
138
- rdr : & ' a mut BufReader < & ' aa mut NetworkStream > ,
139
- wrt : & mut BufWriter < S > ,
140
- handler : & ' h H
141
- ) -> bool where ' aa : ' a , S : NetworkStream , H : Handler {
142
- let mut res = Response :: new ( wrt) ;
143
- let req = match Request :: < ' a , ' aa > :: new ( rdr, addr) {
144
- Ok ( req) => req,
145
- Err ( e@HttpIoError ( _) ) => {
146
- debug ! ( "ioerror in keepalive loop = {:?}" , e) ;
147
- return false ;
148
- }
149
- Err ( e) => {
150
- //TODO: send a 400 response
151
- error ! ( "request error = {:?}" , e) ;
152
- return false ;
147
+ if req. version == Http11 && req. headers . get ( ) == Some ( & Expect :: Continue ) {
148
+ let status = handler. check_continue ( ( & req. method , & req. uri , & req. headers ) ) ;
149
+ match write ! ( & mut wrt, "{} {}\r \n \r \n " , Http11 , status) {
150
+ Ok ( ..) => ( ) ,
151
+ Err ( e) => {
152
+ error ! ( "error writing 100-continue: {:?}" , e) ;
153
+ break ;
154
+ }
155
+ }
156
+
157
+ if status != StatusCode :: Continue {
158
+ debug ! ( "non-100 status ({}) for Expect 100 request" , status) ;
159
+ break ;
160
+ }
153
161
}
154
- } ;
155
162
156
- let keep_alive = match ( req. version , req. headers . get :: < Connection > ( ) ) {
157
- ( Http10 , Some ( conn) ) if !conn. contains ( & KeepAlive ) => false ,
158
- ( Http11 , Some ( conn) ) if conn. contains ( & Close ) => false ,
159
- _ => true
160
- } ;
161
- res. version = req. version ;
162
- handler. handle ( req, res) ;
163
- keep_alive
163
+ keep_alive = match ( req. version , req. headers . get :: < Connection > ( ) ) {
164
+ ( Http10 , Some ( conn) ) if !conn. contains ( & KeepAlive ) => false ,
165
+ ( Http11 , Some ( conn) ) if conn. contains ( & Close ) => false ,
166
+ _ => true
167
+ } ;
168
+ let mut res = Response :: new ( & mut wrt) ;
169
+ res. version = req. version ;
170
+ handler. handle ( req, res) ;
171
+ debug ! ( "keep_alive = {:?}" , keep_alive) ;
172
+ }
164
173
}
165
174
166
175
/// A listening server, which can later be closed.
@@ -184,11 +193,78 @@ pub trait Handler: Sync + Send {
184
193
/// Receives a `Request`/`Response` pair, and should perform some action on them.
185
194
///
186
195
/// This could reading from the request, and writing to the response.
187
- fn handle < ' a , ' aa , ' b , ' s > ( & ' s self , Request < ' aa , ' a > , Response < ' b , Fresh > ) ;
196
+ fn handle < ' a , ' k > ( & ' a self , Request < ' a , ' k > , Response < ' a , Fresh > ) ;
197
+
198
+ /// Called when a Request includes a `Expect: 100-continue` header.
199
+ ///
200
+ /// By default, this will always immediately response with a `StatusCode::Continue`,
201
+ /// but can be overridden with custom behavior.
202
+ fn check_continue ( & self , _: ( & Method , & RequestUri , & Headers ) ) -> StatusCode {
203
+ StatusCode :: Continue
204
+ }
188
205
}
189
206
190
207
impl < F > Handler for F where F : Fn ( Request , Response < Fresh > ) , F : Sync + Send {
191
- fn handle < ' a , ' aa , ' b , ' s > ( & ' s self , req : Request < ' a , ' aa > , res : Response < ' b , Fresh > ) {
208
+ fn handle < ' a , ' k > ( & ' a self , req : Request < ' a , ' k > , res : Response < ' a , Fresh > ) {
192
209
self ( req, res)
193
210
}
194
211
}
212
+
213
+ #[ cfg( test) ]
214
+ mod tests {
215
+ use header:: Headers ;
216
+ use method:: Method ;
217
+ use mock:: MockStream ;
218
+ use status:: StatusCode ;
219
+ use uri:: RequestUri ;
220
+
221
+ use super :: { Request , Response , Fresh , Handler , handle_connection} ;
222
+
223
+ #[ test]
224
+ fn test_check_continue_default ( ) {
225
+ let mut mock = MockStream :: with_input ( b"\
226
+ POST /upload HTTP/1.1\r \n \
227
+ Host: example.domain\r \n \
228
+ Expect: 100-continue\r \n \
229
+ Content-Length: 10\r \n \
230
+ \r \n \
231
+ 1234567890\
232
+ ") ;
233
+
234
+ fn handle ( _: Request , res : Response < Fresh > ) {
235
+ res. start ( ) . unwrap ( ) . end ( ) . unwrap ( ) ;
236
+ }
237
+
238
+ handle_connection ( & mut mock, & handle) ;
239
+ let cont = b"HTTP/1.1 100 Continue\r \n \r \n " ;
240
+ assert_eq ! ( & mock. write[ ..cont. len( ) ] , cont) ;
241
+ let res = b"HTTP/1.1 200 OK\r \n " ;
242
+ assert_eq ! ( & mock. write[ cont. len( ) ..cont. len( ) + res. len( ) ] , res) ;
243
+ }
244
+
245
+ #[ test]
246
+ fn test_check_continue_reject ( ) {
247
+ struct Reject ;
248
+ impl Handler for Reject {
249
+ fn handle < ' a , ' k > ( & ' a self , _: Request < ' a , ' k > , res : Response < ' a , Fresh > ) {
250
+ res. start ( ) . unwrap ( ) . end ( ) . unwrap ( ) ;
251
+ }
252
+
253
+ fn check_continue ( & self , _: ( & Method , & RequestUri , & Headers ) ) -> StatusCode {
254
+ StatusCode :: ExpectationFailed
255
+ }
256
+ }
257
+
258
+ let mut mock = MockStream :: with_input ( b"\
259
+ POST /upload HTTP/1.1\r \n \
260
+ Host: example.domain\r \n \
261
+ Expect: 100-continue\r \n \
262
+ Content-Length: 10\r \n \
263
+ \r \n \
264
+ 1234567890\
265
+ ") ;
266
+
267
+ handle_connection ( & mut mock, & Reject ) ;
268
+ assert_eq ! ( mock. write, b"HTTP/1.1 417 Expectation Failed\r \n \r \n " ) ;
269
+ }
270
+ }
0 commit comments