Go to the documentation of this file.00001 #include <boost/regex.hpp>
00002 #include <boost/noncopyable.hpp>
00003 #include <boost/shared_ptr.hpp>
00004 #include <boost/bind.hpp>
00005 #include <boost/enable_shared_from_this.hpp>
00006 #include "async_web_server_cpp/http_request_handler.hpp"
00007 #include "async_web_server_cpp/http_connection.hpp"
00008 #include "async_web_server_cpp/http_reply.hpp"
00009
00010 namespace async_web_server_cpp
00011 {
00012
00013 HttpRequestHandlerGroup::HttpRequestHandlerGroup(HttpServerRequestHandler default_handler)
00014 : default_handler_(default_handler)
00015 {
00016 }
00017
00018 class PathMatcher
00019 {
00020 public:
00021 explicit PathMatcher(const std::string &path_regex_string)
00022 : path_regex_(boost::regex(path_regex_string))
00023 {
00024 }
00025
00026 bool operator()(const HttpRequest &request)
00027 {
00028 return regex_match(request.path, path_regex_);
00029 }
00030
00031 private:
00032 const boost::regex path_regex_;
00033 };
00034
00035 void HttpRequestHandlerGroup::addHandlerForPath(const std::string &path_regex, HttpServerRequestHandler handler)
00036 {
00037 addHandler(PathMatcher(path_regex), handler);
00038 }
00039
00040 void HttpRequestHandlerGroup::addHandler(HandlerPredicate predicate, HttpServerRequestHandler handler)
00041 {
00042 handlers_.push_back(std::make_pair(predicate, handler));
00043 }
00044
00045
00046 bool HttpRequestHandlerGroup::operator()(const HttpRequest &request, boost::shared_ptr<HttpConnection> connection, const char* begin, const char* end)
00047 {
00048 for (int i = 0; i < handlers_.size(); ++i)
00049 {
00050 std::pair<HandlerPredicate, HttpServerRequestHandler> &handler = handlers_[i];
00051 if (handler.first(request))
00052 {
00053 if(handler.second(request, connection, begin, end))
00054 return true;
00055 }
00056 }
00057 return default_handler_(request, connection, begin, end);
00058 }
00059
00060 class BodyCollectingConnection;
00061 typedef boost::shared_ptr<BodyCollectingConnection> BodyCollectingConnectionPtr;
00062 typedef boost::weak_ptr<BodyCollectingConnection> BodyCollectingConnectionWeakPtr;
00063 class BodyCollectingConnection : public boost::enable_shared_from_this<BodyCollectingConnection>,
00064 private boost::noncopyable
00065 {
00066 public:
00067 BodyCollectingConnection(HttpRequestBodyCollector::Handler handler, const HttpRequest &request, boost::shared_ptr<HttpConnection> connection)
00068 : handler_(handler), request_(request), connection_(connection), received_length_(0) {
00069 std::string length_str = request_.get_header_value_or_default("Content-Length", "");
00070 try {
00071 length_ = boost::lexical_cast<ssize_t>(length_str);
00072 }
00073 catch(const boost::bad_lexical_cast &) {
00074 length_ = -1;
00075 }
00076 }
00077
00078 static void static_handle_read(BodyCollectingConnectionPtr _this, const char* begin, const char* end) {
00079 _this->handle_read(begin, end);
00080 }
00081 void handle_read(const char* begin, const char* end) {
00082 if(length_ < 0) {
00083 HttpReply::builder(HttpReply::bad_request).write(connection_);
00084 connection_->write("No Content-Length header");
00085 return;
00086 }
00087 std::string chunk(begin, end-begin);
00088 body_stream_ << chunk;
00089 received_length_ += chunk.length();
00090 if(received_length_ >= length_) {
00091 handler_(request_, connection_, body_stream_.str().substr(0, length_));
00092 }
00093 else {
00094 connection_->async_read(boost::bind(&BodyCollectingConnection::static_handle_read, shared_from_this(), _1, _2));
00095 }
00096 }
00097
00098 private:
00099 HttpRequestBodyCollector::Handler handler_;
00100 const HttpRequest request_;
00101 boost::shared_ptr<HttpConnection> connection_;
00102 std::stringstream body_stream_;
00103 ssize_t length_;
00104 size_t received_length_;
00105 };
00106
00107 HttpRequestBodyCollector::HttpRequestBodyCollector(Handler handler)
00108 : handler_(handler) {}
00109
00110 bool HttpRequestBodyCollector::operator()(const HttpRequest &request, boost::shared_ptr<HttpConnection> connection, const char* begin, const char* end)
00111 {
00112 BodyCollectingConnectionPtr collecting_connection(new BodyCollectingConnection(handler_, request, connection));
00113 collecting_connection->handle_read(begin, end);
00114 return true;
00115 }
00116
00117 }