blob: f527425822cfcd9bc42de933185376a49a85163b [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "mojo/data_pipe_utils/data_pipe_utils.h"
#include "mojo/public/cpp/application/application_test_base.h"
#include "mojo/public/cpp/application/connect.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/synchronous_interface_ptr.h"
#include "mojo/public/cpp/system/macros.h"
#include "mojo/services/http_server/cpp/http_server_util.h"
#include "mojo/services/http_server/interfaces/http_server.mojom-sync.h"
#include "mojo/services/http_server/interfaces/http_server_factory.mojom.h"
#include "mojo/services/network/interfaces/net_address.mojom.h"
#include "mojo/services/network/interfaces/network_service.mojom.h"
#include "mojo/services/network/interfaces/url_loader.mojom.h"
namespace http_server {
namespace {
void WriteMessageToDataPipe(
const std::string message,
mojo::ScopedDataPipeConsumerHandle* data_pipe_consumer) {
mojo::ScopedDataPipeProducerHandle producer_handle_;
MojoCreateDataPipeOptions options = {sizeof(MojoCreateDataPipeOptions),
MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE,
1,
static_cast<uint32_t>(message.size())};
MojoResult result =
CreateDataPipe(&options, &producer_handle_, data_pipe_consumer);
ASSERT_EQ(MOJO_RESULT_OK, result);
uint32_t bytes = message.size();
result = WriteDataRaw(producer_handle_.get(), message.data(), &bytes,
MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
ASSERT_EQ(result, MOJO_RESULT_OK);
ASSERT_EQ(message.size(), bytes);
}
const char kExampleMessage[] = "Hello, world!";
} // namespace
// Test handler that responds to all requests with the status OK and
// kExampleMessage.
class GetHandler : public http_server::HttpHandler {
public:
GetHandler(mojo::InterfaceRequest<HttpHandler> request)
: binding_(this, request.Pass()) {}
~GetHandler() override {}
private:
// http_server::HttpHandler:
void HandleRequest(http_server::HttpRequestPtr request,
const mojo::Callback<void(http_server::HttpResponsePtr)>&
callback) override {
callback.Run(http_server::CreateHttpResponse(200, kExampleMessage));
}
mojo::Binding<http_server::HttpHandler> binding_;
MOJO_DISALLOW_COPY_AND_ASSIGN(GetHandler);
};
// Test handler that responds to POST requests with the status OK and message
// read from the payload of the request.
class PostHandler : public http_server::HttpHandler {
public:
PostHandler(mojo::InterfaceRequest<HttpHandler> request)
: binding_(this, request.Pass()) {}
~PostHandler() override {}
private:
// http_server::HttpHandler:
void HandleRequest(http_server::HttpRequestPtr request,
const mojo::Callback<void(http_server::HttpResponsePtr)>&
callback) override {
DCHECK_EQ("POST", request->method);
std::string message;
mojo::common::BlockingCopyToString(request->body.Pass(), &message);
callback.Run(http_server::CreateHttpResponse(200, message));
}
mojo::Binding<http_server::HttpHandler> binding_;
MOJO_DISALLOW_COPY_AND_ASSIGN(PostHandler);
};
class HttpServerApplicationTest : public mojo::test::ApplicationTestBase {
public:
HttpServerApplicationTest() : ApplicationTestBase() {}
~HttpServerApplicationTest() override {}
protected:
// ApplicationTestBase:
void SetUp() override {
ApplicationTestBase::SetUp();
mojo::ConnectToService(shell(), "mojo:http_server",
GetProxy(&http_server_factory_));
mojo::ConnectToService(shell(), "mojo:network_service",
GetProxy(&network_service_));
}
mojo::SynchronousInterfacePtr<http_server::HttpServer> CreateHttpServer();
http_server::HttpServerFactoryPtr http_server_factory_;
mojo::NetworkServicePtr network_service_;
private:
MOJO_DISALLOW_COPY_AND_ASSIGN(HttpServerApplicationTest);
};
mojo::SynchronousInterfacePtr<http_server::HttpServer>
HttpServerApplicationTest::CreateHttpServer() {
mojo::SynchronousInterfacePtr<http_server::HttpServer> http_server;
mojo::NetAddressPtr local_address(mojo::NetAddress::New());
local_address->family = mojo::NetAddressFamily::IPV4;
local_address->ipv4 = mojo::NetAddressIPv4::New();
local_address->ipv4->addr.resize(4);
local_address->ipv4->addr[0] = 127;
local_address->ipv4->addr[1] = 0;
local_address->ipv4->addr[2] = 0;
local_address->ipv4->addr[3] = 1;
local_address->ipv4->port = 0;
http_server_factory_->CreateHttpServer(GetSynchronousProxy(&http_server),
local_address.Pass());
return http_server;
}
void CheckServerResponse(mojo::URLResponsePtr response) {
EXPECT_EQ(200u, response->status_code);
std::string response_body;
mojo::common::BlockingCopyToString(response->body.Pass(), &response_body);
EXPECT_EQ(kExampleMessage, response_body);
base::MessageLoop::current()->Quit();
}
// Verifies that the server responds to http GET requests using example
// GetHandler.
TEST_F(HttpServerApplicationTest, ServerResponse) {
auto http_server = CreateHttpServer();
uint16_t assigned_port = 0;
EXPECT_TRUE(http_server->GetPort(&assigned_port));
EXPECT_NE(assigned_port, 0u);
HttpHandlerPtr http_handler_ptr;
GetHandler handler(GetProxy(&http_handler_ptr).Pass());
// Set the test handler and wait for confirmation.
bool result = false;
EXPECT_TRUE(
http_server->SetHandler("/test", http_handler_ptr.Pass(), &result));
EXPECT_TRUE(result);
mojo::URLLoaderPtr url_loader;
network_service_->CreateURLLoader(GetProxy(&url_loader));
mojo::URLRequestPtr url_request = mojo::URLRequest::New();
url_request->url =
base::StringPrintf("http://127.0.0.1:%u/test", assigned_port);
url_loader->Start(url_request.Pass(), base::Bind(&CheckServerResponse));
base::RunLoop run_loop;
run_loop.Run();
}
// Verifies that the server correctly passes the POST request payload using
// example PostHandler.
TEST_F(HttpServerApplicationTest, PostData) {
auto http_server = CreateHttpServer();
uint16_t assigned_port = 0;
EXPECT_TRUE(http_server->GetPort(&assigned_port));
EXPECT_NE(assigned_port, 0u);
HttpHandlerPtr http_handler_ptr;
PostHandler handler(GetProxy(&http_handler_ptr).Pass());
// Set the test handler and wait for confirmation.
bool result = false;
EXPECT_TRUE(
http_server->SetHandler("/post", http_handler_ptr.Pass(), &result));
EXPECT_TRUE(result);
mojo::URLLoaderPtr url_loader;
network_service_->CreateURLLoader(GetProxy(&url_loader));
mojo::URLRequestPtr url_request = mojo::URLRequest::New();
url_request->url =
base::StringPrintf("http://127.0.0.1:%u/post", assigned_port);
url_request->method = "POST";
url_request->body.resize(1);
WriteMessageToDataPipe(kExampleMessage, &url_request->body[0]);
url_loader->Start(url_request.Pass(), base::Bind(&CheckServerResponse));
base::RunLoop run_loop;
run_loop.Run();
}
} // namespace http_server