Chromium Code Reviews| Index: services/http_server/http_server.cc |
| diff --git a/services/http_server/http_server.cc b/services/http_server/http_server.cc |
| index f45644a3dd2951aa5331782d8048bd6265d83bb1..433c0ebf71eaede8eb949eca67aae8aab6e12067 100644 |
| --- a/services/http_server/http_server.cc |
| +++ b/services/http_server/http_server.cc |
| @@ -19,12 +19,14 @@ |
| #include "mojo/public/cpp/application/application_delegate.h" |
| #include "mojo/public/cpp/application/application_impl.h" |
| #include "mojo/public/cpp/application/application_runner.h" |
| +#include "mojo/public/cpp/application/interface_factory.h" |
| #include "mojo/public/cpp/environment/async_waiter.h" |
| #include "mojo/public/cpp/system/data_pipe.h" |
| #include "mojo/services/public/interfaces/network/network_service.mojom.h" |
| #include "services/http_server/http_request_parser.h" |
| #include "services/http_server/public/http_request.mojom.h" |
| #include "services/http_server/public/http_response.mojom.h" |
| +#include "services/http_server/public/http_server.mojom.h" |
| #include "third_party/re2/re2/re2.h" |
| namespace mojo { |
| @@ -32,8 +34,7 @@ namespace examples { |
| class Connection; |
| -typedef base::Callback<HttpResponsePtr( |
| - const HttpRequest& request)> HandleRequestCallback; |
| +typedef base::Callback<void(HttpRequestPtr, Connection*)> HandleRequestCallback; |
| const char* GetHttpReasonPhrase(uint32_t code_in) { |
| switch (code_in) { |
| @@ -54,7 +55,7 @@ class Connection { |
| public: |
| // Callback called when a request is parsed. Response should be sent |
| // using Connection::SendResponse() on the |connection| argument. |
| - typedef base::Callback<void(Connection*, const HttpRequest&)> Callback; |
| + typedef base::Callback<void(Connection*, HttpRequestPtr)> Callback; |
| Connection(TCPConnectedSocketPtr conn, |
| ScopedDataPipeProducerHandle sender, |
| @@ -116,7 +117,6 @@ class Connection { |
| uint32_t num_bytes = 0; |
| result = ReadDataRaw(receiver_.get(), NULL, &num_bytes, |
| MOJO_READ_DATA_FLAG_QUERY); |
| - printf("ReadDataRaw result = %d, num_bytes = %d\n", result, num_bytes); |
| if (!num_bytes) |
| return; |
| @@ -126,8 +126,7 @@ class Connection { |
| request_parser_.ProcessChunk(reinterpret_cast<char*>(buffer.get())); |
| if (request_parser_.ParseRequest() == HttpRequestParser::ACCEPTED) { |
| - HttpRequestPtr http_request = request_parser_.GetRequest(); |
| - handle_request_callback_.Run(this, *http_request.get()); |
| + handle_request_callback_.Run(this, request_parser_.GetRequest()); |
| } |
| } |
| @@ -235,7 +234,7 @@ class Connection { |
| size_t response_offset_; |
| }; |
| -HttpResponsePtr CreateResponse(int code, const std::string& data) { |
| +HttpResponsePtr CreateResponseHelper(int code, const std::string& data) { |
| HttpResponsePtr response = HttpResponse::New(); |
| ScopedDataPipeProducerHandle producer_handle; |
| @@ -255,15 +254,54 @@ HttpResponsePtr CreateResponse(int code, const std::string& data) { |
| return response.Pass(); |
| } |
| -HttpResponsePtr FooHandler(const HttpRequest& request) { |
| - return CreateResponse(200, "Foo").Pass(); |
| +void FooHandler(HttpRequestPtr request, Connection* connection) { |
| + connection->SendResponse(CreateResponseHelper(200, "Foo").Pass()); |
| } |
| -HttpResponsePtr BarHandler(const HttpRequest& request) { |
| - return CreateResponse(200, "Bar").Pass(); |
| +void BarHandler(HttpRequestPtr request, Connection* connection) { |
| + connection->SendResponse(CreateResponseHelper(200, "Bar").Pass()); |
| } |
| -class HttpServerApp : public ApplicationDelegate { |
| +class HttpServerApp; |
| + |
| +class HttpServerServiceImpl : public InterfaceImpl<HttpServerService> { |
| + public: |
| + HttpServerServiceImpl(ApplicationConnection* connection, |
| + HttpServerApp* app) |
| + : app_(app) {} |
| + virtual ~HttpServerServiceImpl(); |
| + |
| + private: |
| + // HttpServerService: |
| + void AddHandler(const mojo::String& path, |
| + const mojo::Callback<void(bool)>& callback) override; |
| + void RemoveHandler(const mojo::String& path, |
| + const mojo::Callback<void(bool)>& callback) override; |
| + |
| + void CreateResponse( |
| + uint32_t status_code, |
| + const mojo::String& body, |
| + const mojo::Callback<void(mojo::HttpResponsePtr)>& callback) { |
| + callback.Run(CreateResponseHelper(status_code, body)); |
| + } |
| + |
| + void OnRequest(HttpRequestPtr request, Connection* connection) { |
| + client()->OnHandleRequest( |
| + request.Pass(), |
| + base::Bind(&HttpServerServiceImpl::OnResponse, base::Unretained(this), |
| + connection)); |
| + } |
| + |
| + void OnResponse(Connection* connection, HttpResponsePtr response) { |
| + connection->SendResponse(response.Pass()); |
| + } |
| + |
| + HttpServerApp* app_; |
| + std::vector<std::string> paths_; |
| +}; |
| + |
| +class HttpServerApp : public ApplicationDelegate, |
| + public InterfaceFactory<HttpServerService> { |
| public: |
| HttpServerApp() : weak_ptr_factory_(this) {} |
| virtual void Initialize(ApplicationImpl* app) override { |
| @@ -276,12 +314,42 @@ class HttpServerApp : public ApplicationDelegate { |
| } |
| // Add a handler for the given regex path. |
| - void AddHandler(const std::string& path, |
| + bool AddHandler(const std::string& path, |
| const HandleRequestCallback& handler) { |
| + for (auto& handler : handlers_) { |
| + if (handler.pattern->pattern() == path) |
| + return false; |
| + } |
| + |
| handlers_.push_back(Handler(path, handler)); |
| + return true; |
| + } |
| + |
| + bool RemoveHandler(const std::string& path) { |
| + for (size_t i = 0; i < handlers_.size(); ++i) { |
|
yzshen1
2014/11/12 17:38:33
nit: using iterator here might be a little more cl
jam
2014/11/12 20:48:40
Done.
|
| + if (handlers_[i].pattern->pattern() == path) { |
| + handlers_.erase(handlers_.begin() + i); |
| + return true; |
| + } |
| + } |
| + |
| + return false; |
| } |
| private: |
| + // ApplicationDelegate: |
| + bool ConfigureIncomingConnection( |
| + ApplicationConnection* connection) override { |
| + connection->AddService(this); |
| + return true; |
| + } |
| + |
| + // InterfaceFactory<HttpServerService>: |
| + void Create(ApplicationConnection* connection, |
| + InterfaceRequest<HttpServerService> request) override { |
| + mojo::BindToRequest(new HttpServerServiceImpl(connection, this), &request); |
| + } |
| + |
| void OnSocketBound(NetworkErrorPtr err, NetAddressPtr bound_address) { |
| if (err->code != 0) { |
| printf("Bound err = %d\n", err->code); |
| @@ -349,7 +417,7 @@ class HttpServerApp : public ApplicationDelegate { |
| net_address->ipv4->addr[1] = 0; |
| net_address->ipv4->addr[2] = 0; |
| net_address->ipv4->addr[3] = 1; |
| - net_address->ipv4->port = 0; |
| + net_address->ipv4->port = 80; |
|
yzshen1
2014/11/12 17:38:33
This requires that there is nothing occupying that
jam
2014/11/12 20:48:40
I think right now it's easier if it's 80 so that w
|
| // Note that we can start using the proxies right away even thought the |
| // callbacks have not been called yet. If a previous step fails, they'll |
| @@ -364,17 +432,16 @@ class HttpServerApp : public ApplicationDelegate { |
| WaitForNextConnection(); |
| } |
| - void HandleRequest(Connection* connection, const HttpRequest& request) { |
| - printf("HandleRequest for %s\n", request.relative_url.data()); |
| + void HandleRequest(Connection* connection, HttpRequestPtr request) { |
| for (auto& handler : handlers_) { |
| - if (RE2::FullMatch(request.relative_url.data(), *handler.pattern)) { |
| - connection->SendResponse(handler.callback.Run(request).Pass()); |
| + if (RE2::FullMatch(request->relative_url.data(), *handler.pattern)) { |
| + handler.callback.Run(request.Pass(), connection); |
| return; |
| } |
| } |
| connection->SendResponse( |
| - CreateResponse(404, "No registered handler").Pass()); |
| + CreateResponseHelper(404, "No registered handler").Pass()); |
| } |
| struct Handler { |
| @@ -408,6 +475,35 @@ class HttpServerApp : public ApplicationDelegate { |
| std::vector<Handler> handlers_; |
| }; |
| +HttpServerServiceImpl::~HttpServerServiceImpl() { |
| + for (auto& path : paths_) |
| + app_->RemoveHandler(path); |
| +} |
| + |
| +void HttpServerServiceImpl::AddHandler( |
| + const mojo::String& path, |
| + const mojo::Callback<void(bool)>& callback) { |
| + bool rv = app_->AddHandler(path, |
| + base::Bind(&HttpServerServiceImpl::OnRequest, |
| + base::Unretained(this))); |
| + callback.Run(rv); |
| + if (rv) |
| + paths_.push_back(path); |
| +} |
| + |
| +void HttpServerServiceImpl::RemoveHandler( |
| + const mojo::String& path, |
| + const mojo::Callback<void(bool)>& callback) { |
| + bool rv = app_->RemoveHandler(path); |
| + callback.Run(rv); |
| + for (size_t i = 0; i < paths_.size(); ++i) { |
| + if (paths_[i] == path) { |
| + paths_.erase(paths_.begin() + i); |
| + break; |
| + } |
| + } |
| +} |
| + |
| } // namespace examples |
| } // namespace mojo |