summaryrefslogtreecommitdiffhomepage
path: root/response.cpp
blob: 6b7ae6acc080382df4602dee3186e70d689b5e54 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include "response.h"
#include "file.h"

#include <functional>
#include <iostream>
#include <unordered_map>

using namespace std::placeholders;

std::string extend_index_html(std::string path)
{
 if (path.size() && path.back() == '/')
  path.append("index.html");
 return path;
}

namespace {

std::string GetServerParam(const std::string& key, Server& server)
{
 // following are the supported fields:
 // ...
 throw std::runtime_error("Unsupported server param: "s + key);
}

std::unordered_map<std::string, std::function<std::string(request_type&, Server&)>> GetRequestParamFunctions{
 // following are the supported fields:
 {"target", [](request_type& req, Server& server){return std::string{req.target()};}},

 {"rel_target", [](request_type& req, Server& server){
  std::string host{req["host"]};
  std::string target{req.target()};
  return server.GetConfig().GetRelativePath(server.GetSocket(), host, target);
 }},

 {"doc_root", [](request_type& req, Server& server) {
  std::string host{req["host"]};
  std::string target{req.target()};
  return server.GetConfig().DocRoot(server.GetSocket(), host, target);
 }},

 {"method", [](request_type& req, Server& server){
  if (req.method() == http::verb::get)
   return "GET";
  else if (req.method() == http::verb::post)
   return "POST";
  else if (req.method() == http::verb::head)
   return "HEAD";
  else
   return "";
 }},
};

std::string GetRequestParam(const std::string& key, request_type& req, Server& server)
{
 auto it = GetRequestParamFunctions.find(key);
 if (it != GetRequestParamFunctions.end())
  return it->second(req, server);
 throw std::runtime_error("Unsupported request param: "s + key);
}

void SetResponseHeader(const std::string& key, const std::string& value, response_type& res)
{
 // following are the supported fields:
 
 if (key == "status") { // HTTP Status, e.g. "200" (OK)
  res.result(unsigned(stoul(value)));
 } else if (key == "server") { // Server name/version string
  res.set(http::field::server, value);
 } else  if (key == "content_type") { // e.g. text/html
  res.set(http::field::content_type, value);
 } else
  throw std::runtime_error("Unsupported response field: "s + key);
}

} // anonymous namespace

std::string generate_response(request_type& req, response_type& res, Server& server)
{
 std::string host{req["host"]};
 std::string target{req.target()};
 std::string plugin_name { server.GetConfig().GetPlugin(server.GetSocket(), host, target)};
 plugin_type plugin{server.GetPlugin(plugin_name)};

 auto GetServerParamFunction {std::function<std::string(const std::string& key)>(std::bind(GetServerParam, _1, std::ref(server)))};
 auto GetRequestParamFunction {std::function<std::string(const std::string& key)>(std::bind(GetRequestParam, _1, std::ref(req), std::ref(server)))};
 auto SetResponseHeaderFunction{std::function<void(const std::string& key, const std::string& value)>(std::bind(SetResponseHeader, _1, _2, std::ref(res)))};
 
 return plugin->generate_page(GetServerParamFunction, GetRequestParamFunction, SetResponseHeaderFunction);
}