2017-02-14 14 views
1

Я попытался написать статический сервер HTTP-файлов, но я застреваю, когда пытаюсь отправить файл .jpg через TcpStream.Как отправить .jpg как HTTP через TcpStream?

Даже если я read файл как бинарный файл, браузер, кажется, не способен декодировать изображение:

extern crate chunked_transfer; 
use std::net::{TcpListener, TcpStream}; 
use std::io::{Read, Write}; 
use std::thread; 
use std::fs::File; 
use chunked_transfer::Encoder; 

fn main() { 
    let listener = TcpListener::bind("127.0.0.1:9527").unwrap(); 
    println!("Listening for connections on port {}", 9527); 
    for stream in listener.incoming() { 
     match stream { 
      Ok(stream) => { 
       thread::spawn(|| handle_client(stream)); 
      } 
      Err(e) => println!("Unable to connect: {}", e), 
     } 
    } 
} 

fn get_path(mut stream: &TcpStream) -> String { 
    let mut buf = [0u8; 4096]; 
    match stream.read(&mut buf) { 
     Ok(_) => { 
      let req_str = String::from_utf8_lossy(&buf); 
      let path: Vec<&str> = req_str.lines().next().unwrap().split(" ").collect(); 
      println!("GET {}", path[1]); 
      // println!("{}", req_str); 
      path[1].to_string() 
     } 
     Err(e) => { 
      println!("Unable to read stream: {}", e); 
      "/".to_string() 
     } 
    } 
} 

fn response(path: &str, mut stream: TcpStream) { 
    let file_path: &str = &("/home/xinbg/Downloads/wallpaper".to_string() + path); 
    println!("{}", file_path); 
    let mut buf = vec![0u8]; 
    let file = File::open(file_path); 
    file.unwrap().read_to_end(&mut buf); 

    let mut encoded: Vec<u8> = vec![]; 
    { 
     let mut encoder = Encoder::with_chunks_size(&mut encoded, 8); 
     encoder.write_all(&buf); 
    } 

    let headers = 
     ["HTTP/1.1 200 OK", "Content-type: image/jpeg", "Transfer-Encoding: chunked", "\r\n"]; 
    let mut response: Vec<u8> = headers.join("\r\n") 
     .to_string() 
     .into_bytes(); 
    response.extend(encoded); 

    match stream.write(&response) { 
     Ok(_) => println!("Response sent"), 
     Err(e) => println!("Failed sending response: {}", e), 
    } 
} 

fn handle_client(stream: TcpStream) { 
    response(&get_path(&stream), stream); 
} 

Я слышал, что есть какая-то «HTTP сервер стандартной путеводителя» материал , любая идея, где его найти?

ответ

5

Всегда исправляйте предупреждения компилятора, особенно о результатах, которые вы не используете. Вернитесь назад и перечитайте Язык программирования ржавчины глава на error handling, чтобы освежиться на эту тему.

Однако, это не ваша проблема. Я не знаю, что вы думаете, что делает let mut buf = vec![0u8];, но вы этого не хотите. Это выделяет вектор с ровно одним значением в нем, 8-битным нулем. Затем вы отправляете этот байт-бранд перед вашим JPEG, что делает его более недействительным JPEG. Удаление, что позволяет вашей программе работать:

fn response(path: &str, mut stream: TcpStream) { 
    let file_path = format!("/tmp/images/{}", path); 

    let mut buf = Vec::new(); 
    let mut file = File::open(&file_path).unwrap(); 
    file.read_to_end(&mut buf).unwrap(); 

    let mut encoded = Vec::new(); 
    { 
     let mut encoder = Encoder::with_chunks_size(&mut encoded, 8); 
     encoder.write_all(&buf).unwrap(); 
    } 

    let headers = [ 
     "HTTP/1.1 200 OK", 
     "Content-type: image/jpeg", 
     "Transfer-Encoding: chunked", 
     "\r\n" 
    ]; 
    let mut response = headers.join("\r\n") 
     .to_string() 
     .into_bytes(); 
    response.extend(encoded); 

    match stream.write(&response) { 
     Ok(_) => println!("Response sent"), 
     Err(e) => println!("Failed sending response: {}", e), 
    } 
} 

Однако программа имеет отверстие гиганта безопасности известное как path traversal. Вы должны не выставить это в любом месте, где есть ценная информация.

+0

Спасибо за ценную информацию, я перечитаю эти главы. Это '[0u8]' было глупо, я думал, что file.read_to_end уничтожит вектор, а затем использует его как пустую. – FrontMage