1 #include <ail/string.hpp>
2 #include <boost/foreach.hpp>
3 #include <theodwalha/request.hpp>
8 std::string
const delimiter
= "\r\n";
9 std::string end_of_header
= delimiter
+ delimiter
;
12 quality_entry::quality_entry()
16 quality_entry::quality_entry(std::string
const & name
):
22 quality_entry::quality_entry(std::string
const & name
, float quality_value
):
24 quality_value(quality_value
)
28 http_request::http_request():
29 has_content_type(false),
30 has_content_length(false),
37 bool decode_string(std::string
const & input
, std::string
& output
)
39 for(std::size_t i
= 0, end
= input
.size(); i
< end
; i
++)
46 std::size_t const hex_length
= 2;
48 std::size_t remaining_bytes
= end
- i
;
49 if(remaining_bytes
< hex_length
)
52 std::string hex_string
= input
.substr(i
, hex_length
);
55 if(!ail::string_to_number
<char>(hex_string
, hex_byte
, std::ios_base::hex
))
58 output
.push_back(hex_byte
);
61 output
.push_back(byte
);
66 bool parse_quality_entries(std::string
const & input
, quality_entries
& output
, std::string
& error_message
)
68 string_vector argument_tokens
= ail::tokenise(input
, ",");
69 BOOST_FOREACH(std::string token
, argument_tokens
)
71 string_vector quality_tokens
= ail::tokenise(ail::trim(token
), ";q=");
72 switch(quality_tokens
.size())
75 output
.push_back(quality_entry(quality_tokens
[0]));
81 if(!ail::string_to_number(quality_tokens
[1], quality_value
))
83 error_message
= "Failed to parse quality value";
86 if(quality_value
< 0.0f
|| quality_value
> 1.0f
)
88 error_message
= "Quality value out of range";
91 output
.push_back(quality_entry(quality_tokens
[1]));
96 error_message
= "Invalid quality value token count";
103 process_header_result::type
process_header(std::string
const & input
, http_request
& output
, std::string
& error_message
)
105 using namespace process_header_result
;
106 using namespace http_request_method
;
107 using namespace http_protocol
;
108 using namespace http_form_content
;
110 std::size_t offset
= input
.find(end_of_header
);
111 if(offset
== std::string::npos
)
114 output
.header_size
= offset
+ end_of_header
.size();
116 std::string header
= input
.substr(0, offset
);
117 string_vector lines
= ail::tokenise(header
, delimiter
);
120 error_message
= "Invalid line count in the header";
124 string_vector tokens
= ail::tokenise(lines
[0], " ");
126 & method_string
= tokens
[0],
127 & encoded_path
= tokens
[1],
128 & version_string
= tokens
[2];
130 if(method_string
== "GET")
132 else if(method_string
== "POST")
133 output
.method
= post
;
136 error_message
= "Invalid method specified";
140 if(version_string
== "HTTP/1.1")
141 output
.protocol_version
= version_1_1
;
142 else if(version_string
== "HTTP/1.0")
143 output
.protocol_version
= version_1_0
;
146 error_message
= "Invalid protocol specified";
150 if(!decode_string(encoded_path
, output
.path
))
152 error_message
= "Failed to decode path";
156 for(std::size_t i
= 1, end
= lines
.size(); i
< end
; i
++)
158 std::string
const target
= ": ";
159 std::string
const & current_line
= lines
[i
];
160 std::size_t offset
= current_line
.find(target
);
161 if(offset
== std::string::npos
)
163 error_message
= "Unable to detect colon in HTTP header line";
167 std::string name
= current_line
.substr(0, offset
);
168 offset
+= target
.size();
169 std::string argument
= current_line
.substr(offset
);
171 if(name
== "Content-Type")
173 if(argument
== "application/x-www-form-urlencoded")
174 output
.content_type
= application_x_www_form_urlencoded
;
175 else if(argument
== "multipart/form-data")
176 output
.content_type
= multipart_form_data
;
179 error_message
= "Unknown content type specified";
182 output
.has_content_type
= true;
184 else if(name
== "Content-Length")
186 if(!ail::string_to_number
<std::size_t>(argument
, output
.content_length
))
188 error_message
= "Invalid content length specified";
191 output
.has_content_length
= true;
193 else if(name
== "Cookie")
195 string_vector argument_tokens
= ail::tokenise(argument
, ";");
196 BOOST_FOREACH(std::string
const & token
, argument_tokens
)
198 string_vector cookie_tokens
= ail::tokenise(ail::trim(token
), "=");
199 if(cookie_tokens
.size() != 2)
201 error_message
= "Failed to parse a cookie assignment";
210 !decode_string(cookie_tokens
[0], cookie
) ||
211 !decode_string(cookie_tokens
[1], value
)
214 error_message
= "Failed to decode a cookie";
219 else if(name
== "Accept-Encoding")
221 if(!parse_quality_entries(argument
, output
.accepted_encodings
, error_message
))
223 BOOST_FOREACH(quality_entry
& entry
, output
.accepted_encodings
)
224 if(entry
.name
== "gzip" && entry
.quality_value
> 0.0f
)
227 else if(name
== "Connection")
229 string_vector argument_tokens
= ail::tokenise(argument
, ",");
230 BOOST_FOREACH(std::string token
, argument_tokens
)
232 token
= ail::trim(token
);
233 if(token
== "Keep-Alive")
234 output
.keep_alive
= true;