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