Line data Source code
1 : #include "headers.hpp"
2 : #include <regex>
3 : #include "../../util/logger.hpp"
4 :
5 : namespace thinger::http{
6 :
7 4580 : void headers::process_header(std::string key, std::string value){
8 4580 : if(boost::indeterminate(keep_alive_) && is_header(key, header::connection)){
9 : /*
10 : * Firefox send both keep-alive and upgrade values in Connection header, i.e., when opening a WebSocket,
11 : * so it is necessary to test values separately.
12 : */
13 895 : std::vector<std::string> strs;
14 895 : boost::split(strs, value, boost::is_any_of(","));
15 1793 : for(auto& str:strs){
16 898 : boost::algorithm::trim(str);
17 898 : if(is_header(str, connection::keep_alive)){
18 833 : keep_alive_ = true;
19 : }
20 65 : else if (is_header(str, connection::close)){
21 21 : keep_alive_ = false;
22 : }
23 44 : else if(is_header(str, connection::upgrade)){
24 44 : upgrade_ = true;
25 : }
26 : }
27 895 : }
28 :
29 4580 : if(is_header(key, header::accept)){
30 6 : stream_ = boost::iequals(value, accept::event_stream);
31 4574 : }else if(is_header(key, header::content_length)){
32 : try{
33 846 : content_length_ = boost::lexical_cast<unsigned long>(value);
34 3 : }catch(const boost::bad_lexical_cast &)
35 : {
36 3 : content_length_ = 0;
37 3 : }
38 : }
39 :
40 4580 : headers_.emplace_back(std::move(key), std::move(value));
41 4580 : }
42 :
43 7040 : void headers::add_header(std::string key, std::string value){
44 7040 : if(key.empty()) return;
45 7040 : headers_.emplace_back(std::move(key), std::move(value));
46 : }
47 :
48 21 : void headers::add_proxy(std::string key, std::string value){
49 21 : if(key.empty()) return;
50 18 : proxy_headers_.emplace_back(std::move(key), std::move(value));
51 : }
52 :
53 6111 : void headers::set_header(std::string key, std::string value){
54 9739 : for(auto & header : headers_)
55 : {
56 4861 : if(is_header(header.first, key)){
57 1233 : header.second = std::move(value);
58 1233 : return;
59 : }
60 : }
61 4878 : add_header(std::move(key), std::move(value));
62 : }
63 :
64 6 : void headers::set_proxy(std::string key, std::string value){
65 6 : for(auto & header : proxy_headers_)
66 : {
67 3 : if(is_header(header.first, key)){
68 3 : header.second = std::move(value);
69 3 : return;
70 : }
71 : }
72 3 : add_proxy(std::move(key), std::move(value));
73 : }
74 :
75 12 : bool headers::upgrade() const{
76 12 : return upgrade_;
77 : }
78 :
79 9 : bool headers::stream() const{
80 9 : return stream_;
81 : }
82 :
83 2980 : bool headers::has_header(std::string_view key) const{
84 9417 : for(const auto & header : headers_)
85 : {
86 6686 : if(is_header(header.first, key)){
87 249 : return true;
88 : }
89 : }
90 2731 : return false;
91 : }
92 :
93 561 : const std::string& headers::get_header(std::string_view key) const
94 : {
95 1809 : for(const auto & header : headers_)
96 : {
97 1746 : if(is_header(header.first, key)){
98 498 : return header.second;
99 : }
100 : }
101 63 : static std::string emtpy;
102 63 : return emtpy;
103 : }
104 :
105 52 : std::vector<std::string> headers::get_headers_with_key(std::string_view key) const{
106 52 : std::vector<std::string> headers;
107 156 : for(const auto & header : headers_)
108 : {
109 104 : if(is_header(header.first, key)){
110 12 : headers.push_back(header.second);
111 : }
112 : }
113 52 : return headers;
114 0 : }
115 :
116 0 : const std::vector<headers::http_header>& headers::get_headers() const{
117 0 : return headers_;
118 : }
119 :
120 80 : std::vector<headers::http_header>& headers::get_headers(){
121 80 : return headers_;
122 : }
123 :
124 57 : bool headers::remove_header(std::string_view key)
125 : {
126 192 : for(auto it=headers_.begin(); it!=headers_.end(); ++it){
127 189 : if(is_header(it->first, key)){
128 54 : headers_.erase(it);
129 54 : return true;
130 : }
131 : }
132 3 : return false;
133 : }
134 :
135 6 : const std::string& headers::get_authorization() const
136 : {
137 6 : return get_header(header::authorization);
138 : }
139 :
140 6 : const std::string& headers::get_cookie() const
141 : {
142 6 : return get_header(header::cookie);
143 : }
144 :
145 6 : const std::string& headers::get_user_agent() const{
146 6 : return get_header(header::user_agent);
147 : }
148 :
149 57 : const std::string& headers::get_content_type() const
150 : {
151 57 : return get_header(header::content_type);
152 : }
153 :
154 9 : bool headers::is_content_type(const std::string& value) const
155 : {
156 9 : return boost::istarts_with(get_header(header::content_type), value);
157 : }
158 :
159 5470 : bool headers::empty_headers() const{
160 5470 : return headers_.empty();
161 : }
162 :
163 3 : void headers::debug_headers(std::ostream& os) const{
164 9 : for(const std::pair<std::string, std::string>& t: headers_){
165 6 : os << "\t> " << t.first << ": " << t.second << std::endl;
166 : }
167 3 : }
168 :
169 0 : void headers::log(const char* scope, int level) const{
170 0 : LOG_DEBUG("[{}] Headers:", scope);
171 0 : for(const auto& t: headers_){
172 0 : LOG_DEBUG(" {}: {}", t.first, t.second);
173 : }
174 0 : for(const auto& t: proxy_headers_){
175 0 : LOG_DEBUG(" (PROXY REPLACE) {}: {}", t.first, t.second);
176 : }
177 0 : }
178 :
179 3477 : size_t headers::get_content_length() const{
180 3477 : return content_length_;
181 : }
182 :
183 2622 : bool headers::keep_alive() const
184 : {
185 2622 : if(boost::indeterminate(keep_alive_)){
186 1736 : return http_version_major_>=1 && http_version_minor_>=1;
187 : }else{
188 886 : return (bool) keep_alive_;
189 : }
190 : }
191 :
192 880 : void headers::set_keep_alive(bool keep_alive){
193 880 : keep_alive_ = keep_alive;
194 880 : set_header(http::header::connection, (keep_alive ? "Keep-Alive" : "Close"));
195 880 : }
196 :
197 1739 : void headers::set_http_version_major(uint8_t http_version_major) {
198 1739 : http_version_major_ = http_version_major;
199 1739 : }
200 :
201 1739 : void headers::set_http_version_minor(uint8_t http_version_minor) {
202 1739 : http_version_minor_ = http_version_minor;
203 1739 : }
204 :
205 6 : int headers::get_http_version_major() const {
206 6 : return http_version_major_;
207 : }
208 :
209 6 : int headers::get_http_version_minor() const {
210 6 : return http_version_minor_;
211 : }
212 :
213 24 : std::string headers::get_parameter(const std::string& header_value, std::string_view name) {
214 :
215 24 : auto start = header_value.begin();
216 24 : auto end = header_value.end();
217 :
218 30 : if(start==end) return "";
219 :
220 21 : static std::regex cookie_regex("([^;^\\s]+)=\"?([^;^\"]*)\"?");
221 21 : std::smatch what;
222 :
223 36 : while (std::regex_search(start, end, what, cookie_regex))
224 : {
225 66 : std::string key(what[1].first, what[1].second);
226 33 : std::string value(what[2].first, what[2].second);
227 :
228 33 : if(key==name) return value;
229 :
230 15 : start = what[0].second;
231 51 : }
232 :
233 6 : return "";
234 21 : }
235 :
236 26640 : bool inline headers::is_header(std::string_view key, std::string_view header) const{
237 26640 : return boost::iequals(key, header);
238 : }
239 : }
|