src/examples/cpp03/http/server/request_handler.cpp | src/examples/cpp11/http/server/request_handler.cpp |
⋮ | ⋮ |
1 | // | 1 | // |
2 | //·request_handler.cpp | 2 | //·request_handler.cpp |
3 | //·~~~~~~~~~~~~~~~~~~~ | 3 | //·~~~~~~~~~~~~~~~~~~~ |
4 | // | 4 | // |
5 | //·Copyright·(c)·2003-2020·Christopher·M.·Kohlhoff·(chris·at·kohlhoff·dot·com) | 5 | //·Copyright·(c)·2003-2020·Christopher·M.·Kohlhoff·(chris·at·kohlhoff·dot·com) |
6 | // | 6 | // |
7 | //·Distributed·under·the·Boost·Software·License,·Version·1.0.·(See·accompanying | 7 | //·Distributed·under·the·Boost·Software·License,·Version·1.0.·(See·accompanying |
8 | //·file·LICENSE_1_0.txt·or·copy·at·http://www.boost.org/LICENSE_1_0.txt) | 8 | //·file·LICENSE_1_0.txt·or·copy·at·http://www.boost.org/LICENSE_1_0.txt) |
9 | // | 9 | // |
10 | | 10 | |
11 | #include·"request_handler.hpp" | 11 | #include·"request_handler.hpp" |
12 | #include·<fstream> | 12 | #include·<fstream> |
13 | #include·<sstream> | 13 | #include·<sstream> |
14 | #include·<string> | 14 | #include·<string> |
15 | #include·<boost/lexical_cast.hpp> | |
16 | #include·"mime_types.hpp" | 15 | #include·"mime_types.hpp" |
17 | #include·"reply.hpp" | 16 | #include·"reply.hpp" |
18 | #include·"request.hpp" | 17 | #include·"request.hpp" |
19 | | 18 | |
20 | namespace·http·{ | 19 | namespace·http·{ |
21 | namespace·server·{ | 20 | namespace·server·{ |
22 | | 21 | |
23 | request_handler::request_handler(const·std::string&·doc_root) | 22 | request_handler::request_handler(const·std::string&·doc_root) |
24 | ··:·doc_root_(doc_root) | 23 | ··:·doc_root_(doc_root) |
25 | { | 24 | { |
26 | } | 25 | } |
27 | | 26 | |
28 | void·request_handler::handle_request(const·request&·req,·reply&·rep) | 27 | void·request_handler::handle_request(const·request&·req,·reply&·rep) |
29 | { | 28 | { |
30 | ··//·Decode·url·to·path. | 29 | ··//·Decode·url·to·path. |
31 | ··std::string·request_path; | 30 | ··std::string·request_path; |
32 | ··if·(!url_decode(req.uri,·request_path)) | 31 | ··if·(!url_decode(req.uri,·request_path)) |
33 | ··{ | 32 | ··{ |
34 | ····rep·=·reply::stock_reply(reply::bad_request); | 33 | ····rep·=·reply::stock_reply(reply::bad_request); |
35 | ····return; | 34 | ····return; |
36 | ··} | 35 | ··} |
37 | | 36 | |
38 | ··//·Request·path·must·be·absolute·and·not·contain·"..". | 37 | ··//·Request·path·must·be·absolute·and·not·contain·"..". |
39 | ··if·(request_path.empty()·||·request_path[0]·!=·'/' | 38 | ··if·(request_path.empty()·||·request_path[0]·!=·'/' |
40 | ······||·request_path.find("..")·!=·std::string::npos) | 39 | ······||·request_path.find("..")·!=·std::string::npos) |
41 | ··{ | 40 | ··{ |
42 | ····rep·=·reply::stock_reply(reply::bad_request); | 41 | ····rep·=·reply::stock_reply(reply::bad_request); |
43 | ····return; | 42 | ····return; |
44 | ··} | 43 | ··} |
45 | | 44 | |
46 | ··//·If·path·ends·in·slash·(i.e.·is·a·directory)·then·add·"index.html". | 45 | ··//·If·path·ends·in·slash·(i.e.·is·a·directory)·then·add·"index.html". |
47 | ··if·(request_path[request_path.size()·-·1]·==·'/') | 46 | ··if·(request_path[request_path.size()·-·1]·==·'/') |
48 | ··{ | 47 | ··{ |
49 | ····request_path·+=·"index.html"; | 48 | ····request_path·+=·"index.html"; |
50 | ··} | 49 | ··} |
51 | | 50 | |
52 | ··//·Determine·the·file·extension. | 51 | ··//·Determine·the·file·extension. |
53 | ··std::size_t·last_slash_pos·=·request_path.find_last_of("/"); | 52 | ··std::size_t·last_slash_pos·=·request_path.find_last_of("/"); |
54 | ··std::size_t·last_dot_pos·=·request_path.find_last_of("."); | 53 | ··std::size_t·last_dot_pos·=·request_path.find_last_of("."); |
55 | ··std::string·extension; | 54 | ··std::string·extension; |
56 | ··if·(last_dot_pos·!=·std::string::npos·&&·last_dot_pos·>·last_slash_pos) | 55 | ··if·(last_dot_pos·!=·std::string::npos·&&·last_dot_pos·>·last_slash_pos) |
57 | ··{ | 56 | ··{ |
58 | ····extension·=·request_path.substr(last_dot_pos·+·1); | 57 | ····extension·=·request_path.substr(last_dot_pos·+·1); |
59 | ··} | 58 | ··} |
60 | | 59 | |
61 | ··//·Open·the·file·to·send·back. | 60 | ··//·Open·the·file·to·send·back. |
62 | ··std::string·full_path·=·doc_root_·+·request_path; | 61 | ··std::string·full_path·=·doc_root_·+·request_path; |
63 | ··std::ifstream·is(full_path.c_str(),·std::ios::in·|·std::ios::binary); | 62 | ··std::ifstream·is(full_path.c_str(),·std::ios::in·|·std::ios::binary); |
64 | ··if·(!is) | 63 | ··if·(!is) |
65 | ··{ | 64 | ··{ |
66 | ····rep·=·reply::stock_reply(reply::not_found); | 65 | ····rep·=·reply::stock_reply(reply::not_found); |
67 | ····return; | 66 | ····return; |
68 | ··} | 67 | ··} |
69 | | 68 | |
70 | ··//·Fill·out·the·reply·to·be·sent·to·the·client. | 69 | ··//·Fill·out·the·reply·to·be·sent·to·the·client. |
71 | ··rep.status·=·reply::ok; | 70 | ··rep.status·=·reply::ok; |
72 | ··char·buf[512]; | 71 | ··char·buf[512]; |
73 | ··while·(is.read(buf,·sizeof(buf)).gcount()·>·0) | 72 | ··while·(is.read(buf,·sizeof(buf)).gcount()·>·0) |
74 | ····rep.content.append(buf,·is.gcount()); | 73 | ····rep.content.append(buf,·is.gcount()); |
75 | ··rep.headers.resize(2); | 74 | ··rep.headers.resize(2); |
76 | ··rep.headers[0].name·=·"Content-Length"; | 75 | ··rep.headers[0].name·=·"Content-Length"; |
77 | ··rep.headers[0].value·=·boost::lexical_cast<std::string>(rep.content.size()); | 76 | ··rep.headers[0].value·=·std::to_string(rep.content.size()); |
78 | ··rep.headers[1].name·=·"Content-Type"; | 77 | ··rep.headers[1].name·=·"Content-Type"; |
79 | ··rep.headers[1].value·=·mime_types::extension_to_type(extension); | 78 | ··rep.headers[1].value·=·mime_types::extension_to_type(extension); |
80 | } | 79 | } |
81 | | 80 | |
82 | bool·request_handler::url_decode(const·std::string&·in,·std::string&·out) | 81 | bool·request_handler::url_decode(const·std::string&·in,·std::string&·out) |
83 | { | 82 | { |
84 | ··out.clear(); | 83 | ··out.clear(); |
85 | ··out.reserve(in.size()); | 84 | ··out.reserve(in.size()); |
86 | ··for·(std::size_t·i·=·0;·i·<·in.size();·++i) | 85 | ··for·(std::size_t·i·=·0;·i·<·in.size();·++i) |
87 | ··{ | 86 | ··{ |
88 | ····if·(in[i]·==·'%') | 87 | ····if·(in[i]·==·'%') |
89 | ····{ | 88 | ····{ |
90 | ······if·(i·+·3·<=·in.size()) | 89 | ······if·(i·+·3·<=·in.size()) |
91 | ······{ | 90 | ······{ |
92 | ········int·value·=·0; | 91 | ········int·value·=·0; |
93 | ········std::istringstream·is(in.substr(i·+·1,·2)); | 92 | ········std::istringstream·is(in.substr(i·+·1,·2)); |
94 | ········if·(is·>>·std::hex·>>·value) | 93 | ········if·(is·>>·std::hex·>>·value) |
95 | ········{ | 94 | ········{ |
96 | ··········out·+=·static_cast<char>(value); | 95 | ··········out·+=·static_cast<char>(value); |
97 | ··········i·+=·2; | 96 | ··········i·+=·2; |
98 | ········} | 97 | ········} |
99 | ········else | 98 | ········else |
100 | ········{ | 99 | ········{ |
101 | ··········return·false; | 100 | ··········return·false; |
102 | ········} | 101 | ········} |
103 | ······} | 102 | ······} |
104 | ······else | 103 | ······else |
105 | ······{ | 104 | ······{ |
106 | ········return·false; | 105 | ········return·false; |
107 | ······} | 106 | ······} |
108 | ····} | 107 | ····} |
109 | ····else·if·(in[i]·==·'+') | 108 | ····else·if·(in[i]·==·'+') |
110 | ····{ | 109 | ····{ |
111 | ······out·+=·'·'; | 110 | ······out·+=·'·'; |
112 | ····} | 111 | ····} |
113 | ····else | 112 | ····else |
114 | ····{ | 113 | ····{ |
115 | ······out·+=·in[i]; | 114 | ······out·+=·in[i]; |
116 | ····} | 115 | ····} |
117 | ··} | 116 | ··} |
118 | ··return·true; | 117 | ··return·true; |
119 | } | 118 | } |
120 | | 119 | |
121 | }·//·namespace·server | 120 | }·//·namespace·server |
122 | }·//·namespace·http | 121 | }·//·namespace·http |