@@ -5,6 +5,7 @@ use std::thread;
5
5
6
6
use itertools:: Itertools ;
7
7
use nom:: branch:: alt;
8
+ use nom:: bytes:: complete:: take_until1;
8
9
use nom:: bytes:: streaming:: { tag_no_case as tag, take_until} ;
9
10
use nom:: IResult ;
10
11
use thiserror:: Error ;
@@ -73,41 +74,70 @@ fn not_found(stream: &mut TcpStream) -> Result<(), std::io::Error> {
73
74
Ok ( ( ) )
74
75
}
75
76
77
+ fn ok ( stream : & mut TcpStream ) -> Result < ( ) , std:: io:: Error > {
78
+ stream. write ( "HTTP/1.1 200 OK\r \n \r \n " . as_bytes ( ) ) ?;
79
+ Ok ( ( ) )
80
+ }
81
+
82
+ fn created ( stream : & mut TcpStream ) -> Result < ( ) , std:: io:: Error > {
83
+ stream. write ( "HTTP/1.1 201 Created\r \n \r \n " . as_bytes ( ) ) ?;
84
+ Ok ( ( ) )
85
+ }
86
+
76
87
fn handle_connection ( mut stream : TcpStream , path : Option < PathBuf > ) -> Result < ( ) , ConnectionError > {
77
- let mut buffer = [ 0 ; 1024 ] ;
78
- let len = stream. read ( & mut buffer) ?; // read 1K bytes for now
88
+ let mut buffer = [ 0 ; 10000 ] ;
89
+ let len = stream. read ( & mut buffer) ?;
79
90
80
- let utf8 = String :: from_utf8_lossy ( & buffer[ ..= len] ) ;
91
+ let utf8 = String :: from_utf8_lossy ( & buffer[ ..len] ) ;
81
92
let req = parse_request ( & utf8)
82
93
. map_err ( |e| ConnectionError :: ParsingError ( e. to_string ( ) ) ) ?
83
94
. 1 ;
84
95
85
96
println ! ( "Request: {req:?}" ) ;
86
97
87
- if req. path == "/" {
88
- stream. write ( "HTTP/1.1 200 OK\r \n \r \n " . as_bytes ( ) ) . unwrap ( ) ;
89
- } else if req. path . starts_with ( "/echo/" ) {
90
- let txt = & req. path [ 6 ..] ;
91
- send_text_content ( & mut stream, txt) ?;
92
- } else if req. path . starts_with ( "/files/" ) {
93
- let path = path. unwrap_or_else ( || PathBuf :: from ( "." ) ) ;
94
- let file_path = path. join ( & req. path [ 7 ..] ) ;
95
-
96
- match std:: fs:: read_to_string ( file_path) {
97
- Ok ( file) => send_content ( & mut stream, "application/octet-stream" , & file) ?,
98
- Err ( _) => not_found ( & mut stream) ?,
98
+ match req {
99
+ Request { path : "/" , .. } => {
100
+ ok ( & mut stream) ?;
101
+ }
102
+ _ if req. path . starts_with ( "/echo/" ) => {
103
+ let txt = & req. path [ 6 ..] ;
104
+ send_text_content ( & mut stream, txt) ?;
105
+ }
106
+ req @ Request { method : "GET" , .. } if req. path . starts_with ( "/files/" ) => {
107
+ let path = path. unwrap_or_else ( || PathBuf :: from ( "." ) ) ;
108
+ let file_path = path. join ( & req. path [ 7 ..] ) ;
109
+
110
+ match std:: fs:: read_to_string ( file_path) {
111
+ Ok ( file) => send_content ( & mut stream, "application/octet-stream" , & file) ?,
112
+ Err ( _) => not_found ( & mut stream) ?,
113
+ } ;
114
+ }
115
+ req @ Request { method : "POST" , .. } if req. path . starts_with ( "/files/" ) => {
116
+ let path = path. unwrap_or_else ( || PathBuf :: from ( "." ) ) ;
117
+ let file_path = path. join ( & req. path [ 7 ..] ) ;
118
+
119
+ if let Ok ( ( ) ) = std:: fs:: write ( file_path, req. body ) {
120
+ created ( & mut stream) ?;
121
+ } else {
122
+ not_found ( & mut stream) ?; // todo: fix
123
+ }
124
+ }
125
+ req @ Request {
126
+ path : "/user-agent" ,
127
+ ..
128
+ } => {
129
+ let ua = req
130
+ . headers
131
+ . iter ( )
132
+ . find ( |( k, _) | * k == "User-Agent" )
133
+ . map ( |( _, v) | v)
134
+ . unwrap_or ( & "Unknown" ) ;
135
+
136
+ send_text_content ( & mut stream, ua) ?;
137
+ }
138
+ _ => {
139
+ not_found ( & mut stream) ?;
99
140
}
100
- } else if req. path == "/user-agent" {
101
- let ua = req
102
- . headers
103
- . iter ( )
104
- . find ( |( k, _) | * k == "User-Agent" )
105
- . map ( |( _, v) | v)
106
- . unwrap_or ( & "Unknown" ) ;
107
-
108
- send_text_content ( & mut stream, ua) ?;
109
- } else {
110
- not_found ( & mut stream) ?;
111
141
}
112
142
113
143
stream. flush ( ) ?;
@@ -124,6 +154,7 @@ pub struct Request<'a> {
124
154
path : & ' a str ,
125
155
version : & ' a str ,
126
156
headers : Vec < ( & ' a str , & ' a str ) > ,
157
+ body : & ' a str ,
127
158
}
128
159
129
160
fn parse_headers ( input : & str ) -> IResult < & str , Vec < ( & str , & str ) > > {
@@ -132,7 +163,7 @@ fn parse_headers(input: &str) -> IResult<&str, Vec<(&str, &str)>> {
132
163
let mut rest = input;
133
164
134
165
loop {
135
- let Ok ( ( rst, name) ) : IResult < & str , & str > = take_until ( ":" ) ( rest) else {
166
+ let Ok ( ( rst, name) ) : IResult < & str , & str > = take_until1 ( ":" ) ( rest) else {
136
167
break ;
137
168
} ;
138
169
let ( rst, _) = tag ( ": " ) ( rst) ?;
@@ -156,6 +187,7 @@ fn parse_request(input: &str) -> IResult<&str, Request> {
156
187
let ( rest, _) = tag ( "\r \n " ) ( rest) ?;
157
188
158
189
let ( rest, headers) = parse_headers ( rest) ?;
190
+ let ( rest, _) = tag ( "\r \n " ) ( rest) ?;
159
191
160
192
return Ok ( (
161
193
rest,
@@ -164,6 +196,7 @@ fn parse_request(input: &str) -> IResult<&str, Request> {
164
196
path,
165
197
version,
166
198
headers,
199
+ body : rest,
167
200
} ,
168
201
) ) ;
169
202
}
0 commit comments