00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "request_handler.hpp"
00012 #include <fstream>
00013 #include <sstream>
00014 #include <string>
00015 #include <boost/lexical_cast.hpp>
00016 #include "mime_types.hpp"
00017 #include "reply.hpp"
00018 #include "request.hpp"
00019
00020 namespace http {
00021 namespace server {
00022
00023 request_handler::request_handler(const std::string& doc_root)
00024 : doc_root_(doc_root)
00025 {
00026 }
00027
00028 void request_handler::handle_request(const request& req, reply& rep)
00029 {
00030
00031 std::string request_path;
00032 if (!url_decode(req.uri, request_path))
00033 {
00034 rep = reply::stock_reply(reply::bad_request);
00035 return;
00036 }
00037
00038
00039 if (request_path.empty() || request_path[0] != '/'
00040 || request_path.find("..") != std::string::npos)
00041 {
00042 rep = reply::stock_reply(reply::bad_request);
00043 return;
00044 }
00045
00046
00047 if (request_path[request_path.size() - 1] == '/')
00048 {
00049 request_path += "index.html";
00050 }
00051
00052
00053 std::size_t last_slash_pos = request_path.find_last_of("/");
00054 std::size_t last_dot_pos = request_path.find_last_of(".");
00055 std::string extension;
00056 if (last_dot_pos != std::string::npos && last_dot_pos > last_slash_pos)
00057 {
00058 extension = request_path.substr(last_dot_pos + 1);
00059 }
00060
00061
00062 std::string full_path = doc_root_ + "/" + request_path;
00063 std::ifstream is(full_path.c_str(), std::ios::in | std::ios::binary);
00064 if (!is)
00065 {
00066 rep = reply::stock_reply(reply::not_found);
00067 return;
00068 }
00069
00070
00071 rep.status = reply::ok;
00072 char buf[512];
00073 while (is.read(buf, sizeof(buf)).gcount() > 0)
00074 rep.content.append(buf, is.gcount());
00075 rep.headers.resize(2);
00076 rep.headers[0].name = "Content-Length";
00077 rep.headers[0].value = boost::lexical_cast<std::string>(rep.content.size());
00078 rep.headers[1].name = "Content-Type";
00079 rep.headers[1].value = mime_types::extension_to_type(extension);
00080 }
00081
00082 bool request_handler::url_decode(const std::string& in, std::string& out)
00083 {
00084 out.clear();
00085 out.reserve(in.size());
00086 for (std::size_t i = 0; i < in.size(); ++i)
00087 {
00088 if (in[i] == '%')
00089 {
00090 if (i + 3 <= in.size())
00091 {
00092 int value;
00093 std::istringstream is(in.substr(i + 1, 2));
00094 if (is >> std::hex >> value)
00095 {
00096 out += static_cast<char>(value);
00097 i += 2;
00098 }
00099 else
00100 {
00101 return false;
00102 }
00103 }
00104 else
00105 {
00106 return false;
00107 }
00108 }
00109 else
00110 {
00111 out += in[i];
00112 }
00113 }
00114 return true;
00115 }
00116
00117 }
00118 }