Compare commits
	
		
			2 Commits
		
	
	
		
			master
			...
			ref-lambda
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 00ba212da5 | |||
| 6ac5399822 | 
| @ -1,11 +0,0 @@ | |||||||
| <!DOCTYPE html> |  | ||||||
| <html lang="en"> |  | ||||||
|   <head> |  | ||||||
|     <meta charset="utf-8"> |  | ||||||
|     <title>Not Found!</title> |  | ||||||
|   </head> |  | ||||||
|   <body> |  | ||||||
|     <h1>U2!?</h1> |  | ||||||
|     <p>And you still haven't found what you're lookin' for...</p> |  | ||||||
|   </body> |  | ||||||
| </html> |  | ||||||
| @ -1,64 +0,0 @@ | |||||||
| extern crate httpserve; |  | ||||||
| use httpserve::ThreadPool; |  | ||||||
| 
 |  | ||||||
| use std::io::prelude::*; |  | ||||||
| use std::fs; |  | ||||||
| use std::net::TcpStream; |  | ||||||
| use std::net::TcpListener; |  | ||||||
| use std::sync::{Arc, Mutex}; |  | ||||||
| use std::thread; |  | ||||||
| use std::time::Duration; |  | ||||||
| 
 |  | ||||||
| fn main() { |  | ||||||
|     let addr = "127.0.0.1:7878"; |  | ||||||
|     let listener = TcpListener::bind(&addr).unwrap(); |  | ||||||
|     println!("Listening on http://{}", &addr); |  | ||||||
| 
 |  | ||||||
|     let counter = Arc::new(Mutex::new(0usize)); |  | ||||||
|     let tasks = ThreadPool::new(100); |  | ||||||
| 
 |  | ||||||
|     for stream in listener.incoming()/*.take(2)*/ { |  | ||||||
|         println!("accepted new connection"); |  | ||||||
| 
 |  | ||||||
|         if let Ok(stream) = stream { |  | ||||||
|             let counter = Arc::clone(&counter); |  | ||||||
| 
 |  | ||||||
|             tasks.run(move || { |  | ||||||
|                 handle_connection(counter, stream); |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     println!("Shutting down..."); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| fn handle_connection(counter: Arc<Mutex<usize>>, mut stream: TcpStream) { |  | ||||||
|     let mut buffer = [0; 512]; |  | ||||||
| 
 |  | ||||||
|     stream.read(&mut buffer).unwrap(); |  | ||||||
| 
 |  | ||||||
|     { |  | ||||||
|         // in a subscope to unlock automatically
 |  | ||||||
|         let mut count = counter.lock().unwrap(); |  | ||||||
|         *count += 1; |  | ||||||
|         println!("Request: {}\n{}", count, String::from_utf8_lossy(&buffer[..])); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     let get = b"GET / HTTP/1.1\r\n"; |  | ||||||
|     let sleep = b"GET /sleep HTTP/1.1\r\n"; |  | ||||||
| 
 |  | ||||||
|     let (headers, response) = if buffer.starts_with(get) { |  | ||||||
|         ("HTTP/1.1 200 OK\r\n\r\n", "index.html") |  | ||||||
|     } else if buffer.starts_with(sleep) { |  | ||||||
|         thread::sleep(Duration::from_secs(5)); |  | ||||||
|         ("HTTP/1.1 200 OK\r\n\r\n", "index.html") |  | ||||||
|     } else { |  | ||||||
|         ("HTTP/1.1 404 Not Found\r\n\r\n", "404.html") |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     let response = fs::read(format!("public/{}", response)).unwrap(); |  | ||||||
|     let response = &response[..]; |  | ||||||
|     stream.write(headers.as_bytes()).unwrap(); |  | ||||||
|     stream.write(response).unwrap(); |  | ||||||
|     stream.flush().unwrap(); |  | ||||||
| } |  | ||||||
							
								
								
									
										105
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								src/lib.rs
									
									
									
									
									
								
							| @ -1,105 +0,0 @@ | |||||||
| use std::sync::{Arc, Mutex}; |  | ||||||
| use std::sync::mpsc; |  | ||||||
| use std::thread; |  | ||||||
| 
 |  | ||||||
| trait FnBox { |  | ||||||
|   fn call_box(self: Box<Self>); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<F: FnOnce()> FnBox for F { |  | ||||||
|     fn call_box(self: Box<F>) { |  | ||||||
|         (*self)(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type Job = Box<dyn FnBox + Send + 'static>; |  | ||||||
| 
 |  | ||||||
| struct Worker { |  | ||||||
|     id: usize, |  | ||||||
|     thread: Option<thread::JoinHandle<()>>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| enum Message { |  | ||||||
|   NewJob(Job), |  | ||||||
|   Terminate, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Worker { |  | ||||||
|     pub fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker { |  | ||||||
|         Worker { |  | ||||||
|             id, |  | ||||||
|             thread: Some(thread::spawn(move || { |  | ||||||
|                 loop { |  | ||||||
|                     if let Ok(job) = receiver.lock().expect("unrecoverable poisened panicked thread state").recv() { |  | ||||||
|                         match job { |  | ||||||
|                             Message::NewJob(job) => { |  | ||||||
|                                 println!("such busy, so worker #{}!", id); |  | ||||||
|                                 job.call_box(); |  | ||||||
|                             } |  | ||||||
|                             Message::Terminate => { |  | ||||||
|                                 println!("such sad, so dead #{}!", id); |  | ||||||
|                                 break; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } else { |  | ||||||
|                         // TODO respawn? (unless in terminate mode)
 |  | ||||||
|                         // or why would the recv fail? already terminated?
 |  | ||||||
|                         // thread panic not handled?
 |  | ||||||
|                         break; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             })), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub struct ThreadPool { |  | ||||||
|     workers: Vec<Worker>, |  | ||||||
|     sender: mpsc::Sender<Message>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Drop for ThreadPool { |  | ||||||
|     fn drop(&mut self) { |  | ||||||
|         // Each worker will only receive Terminate once
 |  | ||||||
|         for _ in &mut self.workers { |  | ||||||
|             self.sender.send(Message::Terminate).unwrap(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Each worker will join once complete
 |  | ||||||
|         for worker in &mut self.workers { |  | ||||||
|             println!("Shutting down worker {} ...", worker.id); |  | ||||||
| 
 |  | ||||||
|             if let Some(thread) = worker.thread.take() { |  | ||||||
|                 thread.join().unwrap(); |  | ||||||
|                 println!("Killed {}!", worker.id); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl ThreadPool { |  | ||||||
|     pub fn new(size: usize) -> ThreadPool { |  | ||||||
|         assert!(size > 0); |  | ||||||
| 
 |  | ||||||
|         let (sender, receiver) = mpsc::channel(); |  | ||||||
|         let receiver = Arc::new(Mutex::new(receiver)); |  | ||||||
| 
 |  | ||||||
|         let mut workers = Vec::with_capacity(size); |  | ||||||
| 
 |  | ||||||
|         for id in 0..size { |  | ||||||
|             workers.push(Worker::new(id, Arc::clone(&receiver))) |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         //ThreadPool.max = size;
 |  | ||||||
|         ThreadPool { |  | ||||||
|             workers, |  | ||||||
|             sender, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn run<F: FnOnce() + Send + 'static>(&self, task: F) |  | ||||||
|     { |  | ||||||
|         let task = Box::new(task); |  | ||||||
|         self.sender.send(Message::NewJob(task)).unwrap(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										41
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | use std::io::prelude::*; | ||||||
|  | use std::net::TcpStream; | ||||||
|  | use std::net::TcpListener; | ||||||
|  | use std::fs; | ||||||
|  | 
 | ||||||
|  | fn main() { | ||||||
|  |     let listener = TcpListener::bind("127.0.0.1:7878").unwrap(); | ||||||
|  | 
 | ||||||
|  |     for stream in listener.incoming() { | ||||||
|  |         let stream = stream.unwrap(); | ||||||
|  | 
 | ||||||
|  |         handle_connection(stream); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn handle_connection(mut stream: TcpStream) { | ||||||
|  |     let mut buffer = [0; 512]; | ||||||
|  | 
 | ||||||
|  |     stream.read(&mut buffer).unwrap(); | ||||||
|  | 
 | ||||||
|  |     let get = b"GET / HTTP/1.1\r\n"; | ||||||
|  | 
 | ||||||
|  |     println!("Request: {}", String::from_utf8_lossy(&buffer[..])); | ||||||
|  | 
 | ||||||
|  |     let mut respond = |headers, response| { | ||||||
|  |         stream.write(headers).unwrap(); | ||||||
|  |         stream.write(response).unwrap(); | ||||||
|  |         stream.flush().unwrap(); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     if buffer.starts_with(get) { | ||||||
|  | 
 | ||||||
|  |         let bytes = fs::read_to_string("public/index.html").unwrap(); | ||||||
|  |         respond("HTTP/1.1 200 OK\r\n\r\n".as_bytes(), bytes.as_bytes()) | ||||||
|  | 
 | ||||||
|  |     } else { | ||||||
|  | 
 | ||||||
|  |         respond("HTTP/1.1 404 NOT FOUND\r\n\r\n".as_bytes(), "Couldn't find {}".as_bytes()) | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user