2016-01-02 11:13:44 -05:00
|
|
|
#include "server/connection.hpp"
|
|
|
|
#include "server/request_handler.hpp"
|
|
|
|
#include "server/request_parser.hpp"
|
2015-01-27 06:35:29 -05:00
|
|
|
|
|
|
|
#include <boost/assert.hpp>
|
|
|
|
#include <boost/bind.hpp>
|
|
|
|
#include <boost/iostreams/filter/gzip.hpp>
|
2016-05-27 15:05:04 -04:00
|
|
|
#include <boost/iostreams/filtering_stream.hpp>
|
2015-01-27 06:35:29 -05:00
|
|
|
|
2016-04-12 09:00:08 -04:00
|
|
|
#include <iterator>
|
2015-01-27 06:35:29 -05:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
2016-01-05 10:51:13 -05:00
|
|
|
namespace osrm
|
|
|
|
{
|
|
|
|
namespace server
|
2015-01-27 06:35:29 -05:00
|
|
|
{
|
|
|
|
|
|
|
|
Connection::Connection(boost::asio::io_service &io_service, RequestHandler &handler)
|
|
|
|
: strand(io_service), TCP_socket(io_service), request_handler(handler)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::asio::ip::tcp::socket &Connection::socket() { return TCP_socket; }
|
|
|
|
|
|
|
|
/// Start the first asynchronous operation for the connection.
|
|
|
|
void Connection::start()
|
|
|
|
{
|
|
|
|
TCP_socket.async_read_some(
|
|
|
|
boost::asio::buffer(incoming_data_buffer),
|
2016-05-27 15:05:04 -04:00
|
|
|
strand.wrap(boost::bind(&Connection::handle_read,
|
|
|
|
this->shared_from_this(),
|
2015-01-27 06:35:29 -05:00
|
|
|
boost::asio::placeholders::error,
|
|
|
|
boost::asio::placeholders::bytes_transferred)));
|
|
|
|
}
|
|
|
|
|
|
|
|
void Connection::handle_read(const boost::system::error_code &error, std::size_t bytes_transferred)
|
|
|
|
{
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// no error detected, let's parse the request
|
2016-01-05 10:51:13 -05:00
|
|
|
http::compression_type compression_type(http::no_compression);
|
2016-01-29 17:02:18 -05:00
|
|
|
RequestParser::RequestStatus result;
|
2015-01-27 06:52:55 -05:00
|
|
|
std::tie(result, compression_type) =
|
2016-05-27 15:05:04 -04:00
|
|
|
request_parser.parse(current_request,
|
|
|
|
incoming_data_buffer.data(),
|
2015-02-19 03:19:51 -05:00
|
|
|
incoming_data_buffer.data() + bytes_transferred);
|
2015-01-27 06:35:29 -05:00
|
|
|
|
|
|
|
// the request has been parsed
|
2016-01-29 17:02:18 -05:00
|
|
|
if (result == RequestParser::RequestStatus::valid)
|
2015-01-27 06:35:29 -05:00
|
|
|
{
|
2015-01-27 06:52:55 -05:00
|
|
|
current_request.endpoint = TCP_socket.remote_endpoint().address();
|
2016-01-28 10:28:44 -05:00
|
|
|
request_handler.HandleRequest(current_request, current_reply);
|
2015-01-27 06:35:29 -05:00
|
|
|
|
|
|
|
// compress the result w/ gzip/deflate if requested
|
|
|
|
switch (compression_type)
|
|
|
|
{
|
2016-01-05 10:51:13 -05:00
|
|
|
case http::deflate_rfc1951:
|
2015-01-27 06:35:29 -05:00
|
|
|
// use deflate for compression
|
2015-01-27 06:52:55 -05:00
|
|
|
current_reply.headers.insert(current_reply.headers.begin(),
|
|
|
|
{"Content-Encoding", "deflate"});
|
|
|
|
compressed_output = compress_buffers(current_reply.content, compression_type);
|
|
|
|
current_reply.set_size(static_cast<unsigned>(compressed_output.size()));
|
|
|
|
output_buffer = current_reply.headers_to_buffers();
|
2015-01-27 06:35:29 -05:00
|
|
|
output_buffer.push_back(boost::asio::buffer(compressed_output));
|
|
|
|
break;
|
2016-01-05 10:51:13 -05:00
|
|
|
case http::gzip_rfc1952:
|
2015-01-27 06:35:29 -05:00
|
|
|
// use gzip for compression
|
2015-01-27 06:52:55 -05:00
|
|
|
current_reply.headers.insert(current_reply.headers.begin(),
|
|
|
|
{"Content-Encoding", "gzip"});
|
|
|
|
compressed_output = compress_buffers(current_reply.content, compression_type);
|
|
|
|
current_reply.set_size(static_cast<unsigned>(compressed_output.size()));
|
|
|
|
output_buffer = current_reply.headers_to_buffers();
|
2015-01-27 06:35:29 -05:00
|
|
|
output_buffer.push_back(boost::asio::buffer(compressed_output));
|
|
|
|
break;
|
2016-01-05 10:51:13 -05:00
|
|
|
case http::no_compression:
|
2015-01-27 06:35:29 -05:00
|
|
|
// don't use any compression
|
2015-01-27 06:52:55 -05:00
|
|
|
current_reply.set_uncompressed_size();
|
|
|
|
output_buffer = current_reply.to_buffers();
|
2015-01-27 06:35:29 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
// write result to stream
|
2016-05-27 15:05:04 -04:00
|
|
|
boost::asio::async_write(TCP_socket,
|
|
|
|
output_buffer,
|
|
|
|
strand.wrap(boost::bind(&Connection::handle_write,
|
|
|
|
this->shared_from_this(),
|
|
|
|
boost::asio::placeholders::error)));
|
2015-01-27 06:35:29 -05:00
|
|
|
}
|
2016-01-29 17:02:18 -05:00
|
|
|
else if (result == RequestParser::RequestStatus::invalid)
|
2015-01-27 06:35:29 -05:00
|
|
|
{ // request is not parseable
|
2016-01-05 10:51:13 -05:00
|
|
|
current_reply = http::reply::stock_reply(http::reply::bad_request);
|
2015-01-27 06:35:29 -05:00
|
|
|
|
2016-05-27 15:05:04 -04:00
|
|
|
boost::asio::async_write(TCP_socket,
|
|
|
|
current_reply.to_buffers(),
|
|
|
|
strand.wrap(boost::bind(&Connection::handle_write,
|
|
|
|
this->shared_from_this(),
|
|
|
|
boost::asio::placeholders::error)));
|
2015-01-27 06:35:29 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// we don't have a result yet, so continue reading
|
|
|
|
TCP_socket.async_read_some(
|
|
|
|
boost::asio::buffer(incoming_data_buffer),
|
2016-05-27 15:05:04 -04:00
|
|
|
strand.wrap(boost::bind(&Connection::handle_read,
|
|
|
|
this->shared_from_this(),
|
2015-01-27 06:35:29 -05:00
|
|
|
boost::asio::placeholders::error,
|
|
|
|
boost::asio::placeholders::bytes_transferred)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Handle completion of a write operation.
|
|
|
|
void Connection::handle_write(const boost::system::error_code &error)
|
|
|
|
{
|
|
|
|
if (!error)
|
|
|
|
{
|
|
|
|
// Initiate graceful connection closure.
|
|
|
|
boost::system::error_code ignore_error;
|
|
|
|
TCP_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignore_error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<char> Connection::compress_buffers(const std::vector<char> &uncompressed_data,
|
2016-01-05 10:51:13 -05:00
|
|
|
const http::compression_type compression_type)
|
2015-01-27 06:35:29 -05:00
|
|
|
{
|
|
|
|
boost::iostreams::gzip_params compression_parameters;
|
|
|
|
|
|
|
|
// there's a trade-off between speed and size. speed wins
|
|
|
|
compression_parameters.level = boost::iostreams::zlib::best_speed;
|
|
|
|
// check which compression flavor is used
|
2016-01-05 10:51:13 -05:00
|
|
|
if (http::deflate_rfc1951 == compression_type)
|
2015-01-27 06:35:29 -05:00
|
|
|
{
|
|
|
|
compression_parameters.noheader = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<char> compressed_data;
|
|
|
|
// plug data into boost's compression stream
|
|
|
|
boost::iostreams::filtering_ostream gzip_stream;
|
|
|
|
gzip_stream.push(boost::iostreams::gzip_compressor(compression_parameters));
|
|
|
|
gzip_stream.push(boost::iostreams::back_inserter(compressed_data));
|
|
|
|
gzip_stream.write(&uncompressed_data[0], uncompressed_data.size());
|
|
|
|
boost::iostreams::close(gzip_stream);
|
|
|
|
|
|
|
|
return compressed_data;
|
|
|
|
}
|
|
|
|
}
|
2016-01-05 10:51:13 -05:00
|
|
|
}
|