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