1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/base_paths.h"
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/path_service.h"
10 #include "base/run_loop.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/stringprintf.h"
13 #include "mojo/application/public/cpp/application_impl.h"
14 #include "mojo/application/public/cpp/application_test_base.h"
15 #include "mojo/common/data_pipe_utils.h"
16 #include "mojo/public/cpp/system/macros.h"
17 #include "mojo/runner/kPingable.h"
18 #include "mojo/runner/test/pingable.mojom.h"
19 #include "mojo/services/http_server/public/cpp/http_server_util.h"
20 #include "mojo/services/http_server/public/interfaces/http_server.mojom.h"
21 #include "mojo/services/http_server/public/interfaces/http_server_factory.mojom.h"
22 #include "mojo/services/network/public/interfaces/net_address.mojom.h"
27 std::string
GetURL(uint16_t port
, const std::string
& path
) {
28 return base::StringPrintf("http://127.0.0.1:%u/%s",
29 static_cast<unsigned>(port
), path
.c_str());
32 class GetHandler
: public http_server::HttpHandler
{
34 GetHandler(InterfaceRequest
<http_server::HttpHandler
> request
, uint16_t port
)
35 : binding_(this, request
.Pass()), port_(port
) {
37 ~GetHandler() override
{}
40 // http_server::HttpHandler:
42 http_server::HttpRequestPtr request
,
43 const Callback
<void(http_server::HttpResponsePtr
)>& callback
) override
{
44 http_server::HttpResponsePtr response
;
45 if (StartsWithASCII(request
->relative_url
, "/app", true)) {
46 response
= http_server::CreateHttpResponse(
47 200, std::string(kPingable
.data
, kPingable
.size
));
48 response
->content_type
= "application/octet-stream";
49 } else if (request
->relative_url
== "/redirect") {
50 response
= http_server::HttpResponse::New();
51 response
->status_code
= 302;
52 response
->custom_headers
.insert("Location", GetURL(port_
, "app"));
57 callback
.Run(response
.Pass());
60 Binding
<http_server::HttpHandler
> binding_
;
63 MOJO_DISALLOW_COPY_AND_ASSIGN(GetHandler
);
66 typedef test::ApplicationTestBase ShellAppTest
;
68 class ShellHTTPAppTest
: public test::ApplicationTestBase
{
70 ShellHTTPAppTest() : ApplicationTestBase() {}
71 ~ShellHTTPAppTest() override
{}
74 // ApplicationTestBase:
75 void SetUp() override
{
76 ApplicationTestBase::SetUp();
78 application_impl()->ConnectToService("mojo:http_server",
79 &http_server_factory_
);
81 NetAddressPtr
local_address(NetAddress::New());
82 local_address
->family
= NET_ADDRESS_FAMILY_IPV4
;
83 local_address
->ipv4
= NetAddressIPv4::New();
84 local_address
->ipv4
->addr
.resize(4);
85 local_address
->ipv4
->addr
[0] = 127;
86 local_address
->ipv4
->addr
[1] = 0;
87 local_address
->ipv4
->addr
[2] = 0;
88 local_address
->ipv4
->addr
[3] = 1;
89 local_address
->ipv4
->port
= 0;
90 http_server_factory_
->CreateHttpServer(GetProxy(&http_server_
),
91 local_address
.Pass());
93 http_server_
->GetPort([this](uint16_t p
) { port_
= p
; });
94 EXPECT_TRUE(http_server_
.WaitForIncomingResponse());
96 InterfacePtr
<http_server::HttpHandler
> http_handler
;
97 handler_
.reset(new GetHandler(GetProxy(&http_handler
).Pass(), port_
));
98 http_server_
->SetHandler(".*", http_handler
.Pass(),
99 [](bool result
) { EXPECT_TRUE(result
); });
100 EXPECT_TRUE(http_server_
.WaitForIncomingResponse());
103 std::string
GetURL(const std::string
& path
) {
104 return ::mojo::GetURL(port_
, path
);
107 http_server::HttpServerFactoryPtr http_server_factory_
;
108 http_server::HttpServerPtr http_server_
;
109 scoped_ptr
<GetHandler
> handler_
;
113 MOJO_DISALLOW_COPY_AND_ASSIGN(ShellHTTPAppTest
);
116 // Test that we can load apps over http.
117 TEST_F(ShellHTTPAppTest
, Http
) {
118 InterfacePtr
<Pingable
> pingable
;
119 application_impl()->ConnectToService(GetURL("app"), &pingable
);
120 pingable
->Ping("hello",
121 [this](const String
& app_url
, const String
& connection_url
,
122 const String
& message
) {
123 EXPECT_EQ(GetURL("app"), app_url
);
124 EXPECT_EQ(GetURL("app"), connection_url
);
125 EXPECT_EQ("hello", message
);
126 base::MessageLoop::current()->Quit();
128 base::RunLoop().Run();
131 // Test that redirects work.
132 // TODO(aa): Test that apps receive the correct URL parameters.
133 TEST_F(ShellHTTPAppTest
, Redirect
) {
134 InterfacePtr
<Pingable
> pingable
;
135 application_impl()->ConnectToService(GetURL("redirect"), &pingable
);
136 pingable
->Ping("hello",
137 [this](const String
& app_url
, const String
& connection_url
,
138 const String
& message
) {
139 EXPECT_EQ(GetURL("app"), app_url
);
140 EXPECT_EQ(GetURL("app"), connection_url
);
141 EXPECT_EQ("hello", message
);
142 base::MessageLoop::current()->Quit();
144 base::RunLoop().Run();
147 // Test that querystring is not considered when resolving http applications.
148 // TODO(aa|qsr): Fix this test on Linux ASAN http://crbug.com/463662
149 #if defined(ADDRESS_SANITIZER)
150 #define MAYBE_QueryHandling DISABLED_QueryHandling
152 #define MAYBE_QueryHandling QueryHandling
153 #endif // ADDRESS_SANITIZER
154 TEST_F(ShellHTTPAppTest
, MAYBE_QueryHandling
) {
155 InterfacePtr
<Pingable
> pingable1
;
156 InterfacePtr
<Pingable
> pingable2
;
157 application_impl()->ConnectToService(GetURL("app?foo"), &pingable1
);
158 application_impl()->ConnectToService(GetURL("app?bar"), &pingable2
);
160 int num_responses
= 0;
161 auto callback
= [this, &num_responses
](const String
& app_url
,
162 const String
& connection_url
,
163 const String
& message
) {
164 EXPECT_EQ(GetURL("app"), app_url
);
165 EXPECT_EQ("hello", message
);
167 if (num_responses
== 1) {
168 EXPECT_EQ(GetURL("app?foo"), connection_url
);
169 } else if (num_responses
== 2) {
170 EXPECT_EQ(GetURL("app?bar"), connection_url
);
171 base::MessageLoop::current()->Quit();
176 pingable1
->Ping("hello", callback
);
177 pingable2
->Ping("hello", callback
);
178 base::RunLoop().Run();
181 // mojo: URLs can have querystrings too
182 TEST_F(ShellAppTest
, MojoURLQueryHandling
) {
183 InterfacePtr
<Pingable
> pingable
;
184 application_impl()->ConnectToService("mojo:pingable_app?foo", &pingable
);
185 auto callback
= [this](const String
& app_url
, const String
& connection_url
,
186 const String
& message
) {
187 EXPECT_TRUE(EndsWith(app_url
, "/pingable_app.mojo", true));
188 EXPECT_EQ(app_url
.To
<std::string
>() + "?foo", connection_url
);
189 EXPECT_EQ("hello", message
);
190 base::MessageLoop::current()->Quit();
192 pingable
->Ping("hello", callback
);
193 base::RunLoop().Run();