xref: /aosp_15_r20/external/libbrillo/brillo/http/http_utils_test.cc (revision 1a96fba65179ea7d3f56207137718607415c5953)
1*1a96fba6SXin Li // Copyright 2014 The Chromium OS Authors. All rights reserved.
2*1a96fba6SXin Li // Use of this source code is governed by a BSD-style license that can be
3*1a96fba6SXin Li // found in the LICENSE file.
4*1a96fba6SXin Li 
5*1a96fba6SXin Li #include <numeric>
6*1a96fba6SXin Li #include <string>
7*1a96fba6SXin Li #include <vector>
8*1a96fba6SXin Li 
9*1a96fba6SXin Li #include <base/bind.h>
10*1a96fba6SXin Li #include <base/values.h>
11*1a96fba6SXin Li #include <brillo/http/http_transport_fake.h>
12*1a96fba6SXin Li #include <brillo/http/http_utils.h>
13*1a96fba6SXin Li #include <brillo/mime_utils.h>
14*1a96fba6SXin Li #include <brillo/strings/string_utils.h>
15*1a96fba6SXin Li #include <brillo/url_utils.h>
16*1a96fba6SXin Li #include <gtest/gtest.h>
17*1a96fba6SXin Li 
18*1a96fba6SXin Li namespace brillo {
19*1a96fba6SXin Li namespace http {
20*1a96fba6SXin Li 
21*1a96fba6SXin Li static const char kFakeUrl[] = "http://localhost";
22*1a96fba6SXin Li static const char kEchoUrl[] = "http://localhost/echo";
23*1a96fba6SXin Li static const char kMethodEchoUrl[] = "http://localhost/echo/method";
24*1a96fba6SXin Li 
25*1a96fba6SXin Li ///////////////////// Generic helper request handlers /////////////////////////
26*1a96fba6SXin Li // Returns the request data back with the same content type.
EchoDataHandler(const fake::ServerRequest & request,fake::ServerResponse * response)27*1a96fba6SXin Li static void EchoDataHandler(const fake::ServerRequest& request,
28*1a96fba6SXin Li                             fake::ServerResponse* response) {
29*1a96fba6SXin Li   response->Reply(status_code::Ok,
30*1a96fba6SXin Li                   request.GetData(),
31*1a96fba6SXin Li                   request.GetHeader(request_header::kContentType));
32*1a96fba6SXin Li }
33*1a96fba6SXin Li 
34*1a96fba6SXin Li // Returns the request method as a plain text response.
EchoMethodHandler(const fake::ServerRequest & request,fake::ServerResponse * response)35*1a96fba6SXin Li static void EchoMethodHandler(const fake::ServerRequest& request,
36*1a96fba6SXin Li                               fake::ServerResponse* response) {
37*1a96fba6SXin Li   response->ReplyText(
38*1a96fba6SXin Li       status_code::Ok, request.GetMethod(), brillo::mime::text::kPlain);
39*1a96fba6SXin Li }
40*1a96fba6SXin Li 
41*1a96fba6SXin Li ///////////////////////////////////////////////////////////////////////////////
TEST(HttpUtils,SendRequest_BinaryData)42*1a96fba6SXin Li TEST(HttpUtils, SendRequest_BinaryData) {
43*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
44*1a96fba6SXin Li   transport->AddHandler(
45*1a96fba6SXin Li       kEchoUrl, request_type::kPost, base::Bind(EchoDataHandler));
46*1a96fba6SXin Li 
47*1a96fba6SXin Li   // Test binary data round-tripping.
48*1a96fba6SXin Li   std::vector<uint8_t> custom_data{0xFF, 0x00, 0x80, 0x40, 0xC0, 0x7F};
49*1a96fba6SXin Li   auto response =
50*1a96fba6SXin Li       http::SendRequestAndBlock(request_type::kPost,
51*1a96fba6SXin Li                                 kEchoUrl,
52*1a96fba6SXin Li                                 custom_data.data(),
53*1a96fba6SXin Li                                 custom_data.size(),
54*1a96fba6SXin Li                                 brillo::mime::application::kOctet_stream,
55*1a96fba6SXin Li                                 {},
56*1a96fba6SXin Li                                 transport,
57*1a96fba6SXin Li                                 nullptr);
58*1a96fba6SXin Li   EXPECT_TRUE(response->IsSuccessful());
59*1a96fba6SXin Li   EXPECT_EQ(brillo::mime::application::kOctet_stream,
60*1a96fba6SXin Li             response->GetContentType());
61*1a96fba6SXin Li   EXPECT_EQ(custom_data, response->ExtractData());
62*1a96fba6SXin Li }
63*1a96fba6SXin Li 
TEST(HttpUtils,SendRequestAsync_BinaryData)64*1a96fba6SXin Li TEST(HttpUtils, SendRequestAsync_BinaryData) {
65*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
66*1a96fba6SXin Li   transport->AddHandler(
67*1a96fba6SXin Li       kEchoUrl, request_type::kPost, base::Bind(EchoDataHandler));
68*1a96fba6SXin Li 
69*1a96fba6SXin Li   // Test binary data round-tripping.
70*1a96fba6SXin Li   std::vector<uint8_t> custom_data{0xFF, 0x00, 0x80, 0x40, 0xC0, 0x7F};
71*1a96fba6SXin Li   auto success_callback = [](const std::vector<uint8_t>& custom_data,
72*1a96fba6SXin Li                              RequestID /* id */,
73*1a96fba6SXin Li                              std::unique_ptr<http::Response> response) {
74*1a96fba6SXin Li     EXPECT_TRUE(response->IsSuccessful());
75*1a96fba6SXin Li     EXPECT_EQ(brillo::mime::application::kOctet_stream,
76*1a96fba6SXin Li               response->GetContentType());
77*1a96fba6SXin Li     EXPECT_EQ(custom_data, response->ExtractData());
78*1a96fba6SXin Li   };
79*1a96fba6SXin Li   auto error_callback = [](RequestID /* id */, const Error* /* error */) {
80*1a96fba6SXin Li     FAIL() << "This callback shouldn't have been called";
81*1a96fba6SXin Li   };
82*1a96fba6SXin Li   http::SendRequest(request_type::kPost,
83*1a96fba6SXin Li                     kEchoUrl,
84*1a96fba6SXin Li                     custom_data.data(),
85*1a96fba6SXin Li                     custom_data.size(),
86*1a96fba6SXin Li                     brillo::mime::application::kOctet_stream,
87*1a96fba6SXin Li                     {},
88*1a96fba6SXin Li                     transport,
89*1a96fba6SXin Li                     base::Bind(success_callback, custom_data),
90*1a96fba6SXin Li                     base::Bind(error_callback));
91*1a96fba6SXin Li }
92*1a96fba6SXin Li 
TEST(HttpUtils,SendRequest_Post)93*1a96fba6SXin Li TEST(HttpUtils, SendRequest_Post) {
94*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
95*1a96fba6SXin Li   transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
96*1a96fba6SXin Li 
97*1a96fba6SXin Li   // Test binary data round-tripping.
98*1a96fba6SXin Li   std::vector<uint8_t> custom_data{0xFF, 0x00, 0x80, 0x40, 0xC0, 0x7F};
99*1a96fba6SXin Li 
100*1a96fba6SXin Li   // Check the correct HTTP method used.
101*1a96fba6SXin Li   auto response =
102*1a96fba6SXin Li       http::SendRequestAndBlock(request_type::kPost,
103*1a96fba6SXin Li                                 kMethodEchoUrl,
104*1a96fba6SXin Li                                 custom_data.data(),
105*1a96fba6SXin Li                                 custom_data.size(),
106*1a96fba6SXin Li                                 brillo::mime::application::kOctet_stream,
107*1a96fba6SXin Li                                 {},
108*1a96fba6SXin Li                                 transport,
109*1a96fba6SXin Li                                 nullptr);
110*1a96fba6SXin Li   EXPECT_TRUE(response->IsSuccessful());
111*1a96fba6SXin Li   EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
112*1a96fba6SXin Li   EXPECT_EQ(request_type::kPost, response->ExtractDataAsString());
113*1a96fba6SXin Li }
114*1a96fba6SXin Li 
TEST(HttpUtils,SendRequest_Get)115*1a96fba6SXin Li TEST(HttpUtils, SendRequest_Get) {
116*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
117*1a96fba6SXin Li   transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
118*1a96fba6SXin Li 
119*1a96fba6SXin Li   auto response = http::SendRequestAndBlock(request_type::kGet,
120*1a96fba6SXin Li                                             kMethodEchoUrl,
121*1a96fba6SXin Li                                             nullptr,
122*1a96fba6SXin Li                                             0,
123*1a96fba6SXin Li                                             std::string{},
124*1a96fba6SXin Li                                             {},
125*1a96fba6SXin Li                                             transport,
126*1a96fba6SXin Li                                             nullptr);
127*1a96fba6SXin Li   EXPECT_TRUE(response->IsSuccessful());
128*1a96fba6SXin Li   EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
129*1a96fba6SXin Li   EXPECT_EQ(request_type::kGet, response->ExtractDataAsString());
130*1a96fba6SXin Li }
131*1a96fba6SXin Li 
TEST(HttpUtils,SendRequest_Put)132*1a96fba6SXin Li TEST(HttpUtils, SendRequest_Put) {
133*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
134*1a96fba6SXin Li   transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
135*1a96fba6SXin Li 
136*1a96fba6SXin Li   auto response = http::SendRequestAndBlock(request_type::kPut,
137*1a96fba6SXin Li                                             kMethodEchoUrl,
138*1a96fba6SXin Li                                             nullptr,
139*1a96fba6SXin Li                                             0,
140*1a96fba6SXin Li                                             std::string{},
141*1a96fba6SXin Li                                             {},
142*1a96fba6SXin Li                                             transport,
143*1a96fba6SXin Li                                             nullptr);
144*1a96fba6SXin Li   EXPECT_TRUE(response->IsSuccessful());
145*1a96fba6SXin Li   EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
146*1a96fba6SXin Li   EXPECT_EQ(request_type::kPut, response->ExtractDataAsString());
147*1a96fba6SXin Li }
148*1a96fba6SXin Li 
TEST(HttpUtils,SendRequest_NotFound)149*1a96fba6SXin Li TEST(HttpUtils, SendRequest_NotFound) {
150*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
151*1a96fba6SXin Li   // Test failed response (URL not found).
152*1a96fba6SXin Li   auto response = http::SendRequestWithNoDataAndBlock(
153*1a96fba6SXin Li       request_type::kGet, "http://blah.com", {}, transport, nullptr);
154*1a96fba6SXin Li   EXPECT_FALSE(response->IsSuccessful());
155*1a96fba6SXin Li   EXPECT_EQ(status_code::NotFound, response->GetStatusCode());
156*1a96fba6SXin Li }
157*1a96fba6SXin Li 
TEST(HttpUtils,SendRequestAsync_NotFound)158*1a96fba6SXin Li TEST(HttpUtils, SendRequestAsync_NotFound) {
159*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
160*1a96fba6SXin Li   // Test failed response (URL not found).
161*1a96fba6SXin Li   auto success_callback =
162*1a96fba6SXin Li       [](RequestID /* request_id */, std::unique_ptr<http::Response> response) {
163*1a96fba6SXin Li     EXPECT_FALSE(response->IsSuccessful());
164*1a96fba6SXin Li     EXPECT_EQ(status_code::NotFound, response->GetStatusCode());
165*1a96fba6SXin Li   };
166*1a96fba6SXin Li   auto error_callback = [](RequestID /* request_id */,
167*1a96fba6SXin Li                            const Error* /* error */) {
168*1a96fba6SXin Li     FAIL() << "This callback shouldn't have been called";
169*1a96fba6SXin Li   };
170*1a96fba6SXin Li   http::SendRequestWithNoData(request_type::kGet,
171*1a96fba6SXin Li                               "http://blah.com",
172*1a96fba6SXin Li                               {},
173*1a96fba6SXin Li                               transport,
174*1a96fba6SXin Li                               base::Bind(success_callback),
175*1a96fba6SXin Li                               base::Bind(error_callback));
176*1a96fba6SXin Li }
177*1a96fba6SXin Li 
TEST(HttpUtils,SendRequest_Headers)178*1a96fba6SXin Li TEST(HttpUtils, SendRequest_Headers) {
179*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
180*1a96fba6SXin Li 
181*1a96fba6SXin Li   static const char json_echo_url[] = "http://localhost/echo/json";
182*1a96fba6SXin Li   auto JsonEchoHandler =
183*1a96fba6SXin Li       [](const fake::ServerRequest& request, fake::ServerResponse* response) {
184*1a96fba6SXin Li     base::DictionaryValue json;
185*1a96fba6SXin Li     json.SetString("method", request.GetMethod());
186*1a96fba6SXin Li     json.SetString("data", request.GetDataAsString());
187*1a96fba6SXin Li     for (const auto& pair : request.GetHeaders()) {
188*1a96fba6SXin Li       json.SetString("header." + pair.first, pair.second);
189*1a96fba6SXin Li     }
190*1a96fba6SXin Li     response->ReplyJson(status_code::Ok, &json);
191*1a96fba6SXin Li   };
192*1a96fba6SXin Li   transport->AddHandler(json_echo_url, "*", base::Bind(JsonEchoHandler));
193*1a96fba6SXin Li   auto response = http::SendRequestAndBlock(
194*1a96fba6SXin Li       request_type::kPost, json_echo_url, "abcd", 4,
195*1a96fba6SXin Li       brillo::mime::application::kOctet_stream, {
196*1a96fba6SXin Li         {request_header::kCookie, "flavor=vanilla"},
197*1a96fba6SXin Li         {request_header::kIfMatch, "*"},
198*1a96fba6SXin Li       }, transport, nullptr);
199*1a96fba6SXin Li   EXPECT_TRUE(response->IsSuccessful());
200*1a96fba6SXin Li   EXPECT_EQ(brillo::mime::application::kJson,
201*1a96fba6SXin Li             brillo::mime::RemoveParameters(response->GetContentType()));
202*1a96fba6SXin Li   auto json = ParseJsonResponse(response.get(), nullptr, nullptr);
203*1a96fba6SXin Li   std::string value;
204*1a96fba6SXin Li   EXPECT_TRUE(json->GetString("method", &value));
205*1a96fba6SXin Li   EXPECT_EQ(request_type::kPost, value);
206*1a96fba6SXin Li   EXPECT_TRUE(json->GetString("data", &value));
207*1a96fba6SXin Li   EXPECT_EQ("abcd", value);
208*1a96fba6SXin Li   EXPECT_TRUE(json->GetString("header.Cookie", &value));
209*1a96fba6SXin Li   EXPECT_EQ("flavor=vanilla", value);
210*1a96fba6SXin Li   EXPECT_TRUE(json->GetString("header.Content-Type", &value));
211*1a96fba6SXin Li   EXPECT_EQ(brillo::mime::application::kOctet_stream, value);
212*1a96fba6SXin Li   EXPECT_TRUE(json->GetString("header.Content-Length", &value));
213*1a96fba6SXin Li   EXPECT_EQ("4", value);
214*1a96fba6SXin Li   EXPECT_TRUE(json->GetString("header.If-Match", &value));
215*1a96fba6SXin Li   EXPECT_EQ("*", value);
216*1a96fba6SXin Li }
217*1a96fba6SXin Li 
TEST(HttpUtils,Get)218*1a96fba6SXin Li TEST(HttpUtils, Get) {
219*1a96fba6SXin Li   // Sends back the "?test=..." portion of URL.
220*1a96fba6SXin Li   // So if we do GET "http://localhost?test=blah", this handler responds
221*1a96fba6SXin Li   // with "blah" as text/plain.
222*1a96fba6SXin Li   auto GetHandler =
223*1a96fba6SXin Li       [](const fake::ServerRequest& request, fake::ServerResponse* response) {
224*1a96fba6SXin Li     EXPECT_EQ(request_type::kGet, request.GetMethod());
225*1a96fba6SXin Li     EXPECT_EQ("0", request.GetHeader(request_header::kContentLength));
226*1a96fba6SXin Li     EXPECT_EQ("", request.GetHeader(request_header::kContentType));
227*1a96fba6SXin Li     response->ReplyText(status_code::Ok,
228*1a96fba6SXin Li                         request.GetFormField("test"),
229*1a96fba6SXin Li                         brillo::mime::text::kPlain);
230*1a96fba6SXin Li   };
231*1a96fba6SXin Li 
232*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
233*1a96fba6SXin Li   transport->AddHandler(kFakeUrl, request_type::kGet, base::Bind(GetHandler));
234*1a96fba6SXin Li   transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
235*1a96fba6SXin Li 
236*1a96fba6SXin Li   // Make sure Get() actually does the GET request
237*1a96fba6SXin Li   auto response = http::GetAndBlock(kMethodEchoUrl, {}, transport, nullptr);
238*1a96fba6SXin Li   EXPECT_TRUE(response->IsSuccessful());
239*1a96fba6SXin Li   EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
240*1a96fba6SXin Li   EXPECT_EQ(request_type::kGet, response->ExtractDataAsString());
241*1a96fba6SXin Li 
242*1a96fba6SXin Li   for (std::string data : {"blah", "some data", ""}) {
243*1a96fba6SXin Li     std::string url = brillo::url::AppendQueryParam(kFakeUrl, "test", data);
244*1a96fba6SXin Li     response = http::GetAndBlock(url, {}, transport, nullptr);
245*1a96fba6SXin Li     EXPECT_EQ(data, response->ExtractDataAsString());
246*1a96fba6SXin Li   }
247*1a96fba6SXin Li }
248*1a96fba6SXin Li 
TEST(HttpUtils,Head)249*1a96fba6SXin Li TEST(HttpUtils, Head) {
250*1a96fba6SXin Li   auto HeadHandler =
251*1a96fba6SXin Li       [](const fake::ServerRequest& request, fake::ServerResponse* response) {
252*1a96fba6SXin Li     EXPECT_EQ(request_type::kHead, request.GetMethod());
253*1a96fba6SXin Li     EXPECT_EQ("0", request.GetHeader(request_header::kContentLength));
254*1a96fba6SXin Li     EXPECT_EQ("", request.GetHeader(request_header::kContentType));
255*1a96fba6SXin Li     response->ReplyText(status_code::Ok, "blah", brillo::mime::text::kPlain);
256*1a96fba6SXin Li   };
257*1a96fba6SXin Li 
258*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
259*1a96fba6SXin Li   transport->AddHandler(kFakeUrl, request_type::kHead, base::Bind(HeadHandler));
260*1a96fba6SXin Li 
261*1a96fba6SXin Li   auto response = http::HeadAndBlock(kFakeUrl, transport, nullptr);
262*1a96fba6SXin Li   EXPECT_TRUE(response->IsSuccessful());
263*1a96fba6SXin Li   EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
264*1a96fba6SXin Li   EXPECT_EQ("", response->ExtractDataAsString());  // Must not have actual body.
265*1a96fba6SXin Li   EXPECT_EQ("4", response->GetHeader(request_header::kContentLength));
266*1a96fba6SXin Li }
267*1a96fba6SXin Li 
TEST(HttpUtils,PostBinary)268*1a96fba6SXin Li TEST(HttpUtils, PostBinary) {
269*1a96fba6SXin Li   auto Handler =
270*1a96fba6SXin Li       [](const fake::ServerRequest& request, fake::ServerResponse* response) {
271*1a96fba6SXin Li     EXPECT_EQ(request_type::kPost, request.GetMethod());
272*1a96fba6SXin Li     EXPECT_EQ("256", request.GetHeader(request_header::kContentLength));
273*1a96fba6SXin Li     EXPECT_EQ(brillo::mime::application::kOctet_stream,
274*1a96fba6SXin Li               request.GetHeader(request_header::kContentType));
275*1a96fba6SXin Li     const auto& data = request.GetData();
276*1a96fba6SXin Li     EXPECT_EQ(256, data.size());
277*1a96fba6SXin Li 
278*1a96fba6SXin Li     // Sum up all the bytes.
279*1a96fba6SXin Li     int sum = std::accumulate(data.begin(), data.end(), 0);
280*1a96fba6SXin Li     EXPECT_EQ(32640, sum);  // sum(i, i => [0, 255]) = 32640.
281*1a96fba6SXin Li     response->ReplyText(status_code::Ok, "", brillo::mime::text::kPlain);
282*1a96fba6SXin Li   };
283*1a96fba6SXin Li 
284*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
285*1a96fba6SXin Li   transport->AddHandler(kFakeUrl, request_type::kPost, base::Bind(Handler));
286*1a96fba6SXin Li 
287*1a96fba6SXin Li   /// Fill the data buffer with bytes from 0x00 to 0xFF.
288*1a96fba6SXin Li   std::vector<uint8_t> data(256);
289*1a96fba6SXin Li   std::iota(data.begin(), data.end(), 0);
290*1a96fba6SXin Li 
291*1a96fba6SXin Li   auto response = http::PostBinaryAndBlock(kFakeUrl,
292*1a96fba6SXin Li                                            data.data(),
293*1a96fba6SXin Li                                            data.size(),
294*1a96fba6SXin Li                                            mime::application::kOctet_stream,
295*1a96fba6SXin Li                                            {},
296*1a96fba6SXin Li                                            transport,
297*1a96fba6SXin Li                                            nullptr);
298*1a96fba6SXin Li   EXPECT_TRUE(response->IsSuccessful());
299*1a96fba6SXin Li }
300*1a96fba6SXin Li 
TEST(HttpUtils,PostText)301*1a96fba6SXin Li TEST(HttpUtils, PostText) {
302*1a96fba6SXin Li   std::string fake_data = "Some data";
303*1a96fba6SXin Li   auto PostHandler = [](const std::string& fake_data,
304*1a96fba6SXin Li                         const fake::ServerRequest& request,
305*1a96fba6SXin Li                         fake::ServerResponse* response) {
306*1a96fba6SXin Li     EXPECT_EQ(request_type::kPost, request.GetMethod());
307*1a96fba6SXin Li     EXPECT_EQ(fake_data.size(),
308*1a96fba6SXin Li               std::stoul(request.GetHeader(request_header::kContentLength)));
309*1a96fba6SXin Li     EXPECT_EQ(brillo::mime::text::kPlain,
310*1a96fba6SXin Li               request.GetHeader(request_header::kContentType));
311*1a96fba6SXin Li     response->ReplyText(status_code::Ok,
312*1a96fba6SXin Li                         request.GetDataAsString(),
313*1a96fba6SXin Li                         brillo::mime::text::kPlain);
314*1a96fba6SXin Li   };
315*1a96fba6SXin Li 
316*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
317*1a96fba6SXin Li   transport->AddHandler(
318*1a96fba6SXin Li       kFakeUrl, request_type::kPost, base::Bind(PostHandler, fake_data));
319*1a96fba6SXin Li 
320*1a96fba6SXin Li   auto response = http::PostTextAndBlock(kFakeUrl,
321*1a96fba6SXin Li                                          fake_data,
322*1a96fba6SXin Li                                          brillo::mime::text::kPlain,
323*1a96fba6SXin Li                                          {},
324*1a96fba6SXin Li                                          transport,
325*1a96fba6SXin Li                                          nullptr);
326*1a96fba6SXin Li   EXPECT_TRUE(response->IsSuccessful());
327*1a96fba6SXin Li   EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
328*1a96fba6SXin Li   EXPECT_EQ(fake_data, response->ExtractDataAsString());
329*1a96fba6SXin Li }
330*1a96fba6SXin Li 
TEST(HttpUtils,PostFormData)331*1a96fba6SXin Li TEST(HttpUtils, PostFormData) {
332*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
333*1a96fba6SXin Li   transport->AddHandler(
334*1a96fba6SXin Li       kFakeUrl, request_type::kPost, base::Bind(EchoDataHandler));
335*1a96fba6SXin Li 
336*1a96fba6SXin Li   auto response = http::PostFormDataAndBlock(
337*1a96fba6SXin Li       kFakeUrl, {
338*1a96fba6SXin Li           {"key", "value"},
339*1a96fba6SXin Li           {"field", "field value"},
340*1a96fba6SXin Li       }, {}, transport, nullptr);
341*1a96fba6SXin Li   EXPECT_TRUE(response->IsSuccessful());
342*1a96fba6SXin Li   EXPECT_EQ(brillo::mime::application::kWwwFormUrlEncoded,
343*1a96fba6SXin Li             response->GetContentType());
344*1a96fba6SXin Li   EXPECT_EQ("key=value&field=field+value", response->ExtractDataAsString());
345*1a96fba6SXin Li }
346*1a96fba6SXin Li 
TEST(HttpUtils,PostMultipartFormData)347*1a96fba6SXin Li TEST(HttpUtils, PostMultipartFormData) {
348*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
349*1a96fba6SXin Li   transport->AddHandler(
350*1a96fba6SXin Li       kFakeUrl, request_type::kPost, base::Bind(EchoDataHandler));
351*1a96fba6SXin Li 
352*1a96fba6SXin Li   std::unique_ptr<FormData> form_data{new FormData{"boundary123"}};
353*1a96fba6SXin Li   form_data->AddTextField("key1", "value1");
354*1a96fba6SXin Li   form_data->AddTextField("key2", "value2");
355*1a96fba6SXin Li   std::string expected_content_type = form_data->GetContentType();
356*1a96fba6SXin Li   auto response = http::PostFormDataAndBlock(
357*1a96fba6SXin Li       kFakeUrl, std::move(form_data), {}, transport, nullptr);
358*1a96fba6SXin Li   EXPECT_TRUE(response->IsSuccessful());
359*1a96fba6SXin Li   EXPECT_EQ(expected_content_type, response->GetContentType());
360*1a96fba6SXin Li   const char expected_value[] =
361*1a96fba6SXin Li       "--boundary123\r\n"
362*1a96fba6SXin Li       "Content-Disposition: form-data; name=\"key1\"\r\n"
363*1a96fba6SXin Li       "\r\n"
364*1a96fba6SXin Li       "value1\r\n"
365*1a96fba6SXin Li       "--boundary123\r\n"
366*1a96fba6SXin Li       "Content-Disposition: form-data; name=\"key2\"\r\n"
367*1a96fba6SXin Li       "\r\n"
368*1a96fba6SXin Li       "value2\r\n"
369*1a96fba6SXin Li       "--boundary123--\r\n";
370*1a96fba6SXin Li   EXPECT_EQ(expected_value, response->ExtractDataAsString());
371*1a96fba6SXin Li }
372*1a96fba6SXin Li 
TEST(HttpUtils,PostPatchJson)373*1a96fba6SXin Li TEST(HttpUtils, PostPatchJson) {
374*1a96fba6SXin Li   auto JsonHandler =
375*1a96fba6SXin Li       [](const fake::ServerRequest& request, fake::ServerResponse* response) {
376*1a96fba6SXin Li     auto mime_type = brillo::mime::RemoveParameters(
377*1a96fba6SXin Li         request.GetHeader(request_header::kContentType));
378*1a96fba6SXin Li     EXPECT_EQ(brillo::mime::application::kJson, mime_type);
379*1a96fba6SXin Li     response->ReplyJson(
380*1a96fba6SXin Li         status_code::Ok,
381*1a96fba6SXin Li         {
382*1a96fba6SXin Li           {"method", request.GetMethod()}, {"data", request.GetDataAsString()},
383*1a96fba6SXin Li         });
384*1a96fba6SXin Li   };
385*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
386*1a96fba6SXin Li   transport->AddHandler(kFakeUrl, "*", base::Bind(JsonHandler));
387*1a96fba6SXin Li 
388*1a96fba6SXin Li   base::DictionaryValue json;
389*1a96fba6SXin Li   json.SetString("key1", "val1");
390*1a96fba6SXin Li   json.SetString("key2", "val2");
391*1a96fba6SXin Li   std::string value;
392*1a96fba6SXin Li 
393*1a96fba6SXin Li   // Test POST
394*1a96fba6SXin Li   auto response =
395*1a96fba6SXin Li       http::PostJsonAndBlock(kFakeUrl, &json, {}, transport, nullptr);
396*1a96fba6SXin Li   auto resp_json = http::ParseJsonResponse(response.get(), nullptr, nullptr);
397*1a96fba6SXin Li   EXPECT_NE(nullptr, resp_json.get());
398*1a96fba6SXin Li   EXPECT_TRUE(resp_json->GetString("method", &value));
399*1a96fba6SXin Li   EXPECT_EQ(request_type::kPost, value);
400*1a96fba6SXin Li   EXPECT_TRUE(resp_json->GetString("data", &value));
401*1a96fba6SXin Li   EXPECT_EQ("{\"key1\":\"val1\",\"key2\":\"val2\"}", value);
402*1a96fba6SXin Li 
403*1a96fba6SXin Li   // Test PATCH
404*1a96fba6SXin Li   response = http::PatchJsonAndBlock(kFakeUrl, &json, {}, transport, nullptr);
405*1a96fba6SXin Li   resp_json = http::ParseJsonResponse(response.get(), nullptr, nullptr);
406*1a96fba6SXin Li   EXPECT_NE(nullptr, resp_json.get());
407*1a96fba6SXin Li   EXPECT_TRUE(resp_json->GetString("method", &value));
408*1a96fba6SXin Li   EXPECT_EQ(request_type::kPatch, value);
409*1a96fba6SXin Li   EXPECT_TRUE(resp_json->GetString("data", &value));
410*1a96fba6SXin Li   EXPECT_EQ("{\"key1\":\"val1\",\"key2\":\"val2\"}", value);
411*1a96fba6SXin Li }
412*1a96fba6SXin Li 
TEST(HttpUtils,ParseJsonResponse)413*1a96fba6SXin Li TEST(HttpUtils, ParseJsonResponse) {
414*1a96fba6SXin Li   auto JsonHandler =
415*1a96fba6SXin Li       [](const fake::ServerRequest& request, fake::ServerResponse* response) {
416*1a96fba6SXin Li     int status_code = std::stoi(request.GetFormField("code"));
417*1a96fba6SXin Li     response->ReplyJson(status_code, {{"data", request.GetFormField("value")}});
418*1a96fba6SXin Li   };
419*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
420*1a96fba6SXin Li   transport->AddHandler(kFakeUrl, request_type::kPost, base::Bind(JsonHandler));
421*1a96fba6SXin Li 
422*1a96fba6SXin Li   // Test valid JSON responses (with success or error codes).
423*1a96fba6SXin Li   for (auto item : {"200;data", "400;wrong", "500;Internal Server error"}) {
424*1a96fba6SXin Li     auto pair = brillo::string_utils::SplitAtFirst(item, ";");
425*1a96fba6SXin Li     auto response = http::PostFormDataAndBlock(
426*1a96fba6SXin Li         kFakeUrl, {
427*1a96fba6SXin Li           {"code", pair.first},
428*1a96fba6SXin Li           {"value", pair.second},
429*1a96fba6SXin Li         }, {}, transport, nullptr);
430*1a96fba6SXin Li     int code = 0;
431*1a96fba6SXin Li     auto json = http::ParseJsonResponse(response.get(), &code, nullptr);
432*1a96fba6SXin Li     EXPECT_NE(nullptr, json.get());
433*1a96fba6SXin Li     std::string value;
434*1a96fba6SXin Li     EXPECT_TRUE(json->GetString("data", &value));
435*1a96fba6SXin Li     EXPECT_EQ(pair.first, brillo::string_utils::ToString(code));
436*1a96fba6SXin Li     EXPECT_EQ(pair.second, value);
437*1a96fba6SXin Li   }
438*1a96fba6SXin Li 
439*1a96fba6SXin Li   // Test invalid (non-JSON) response.
440*1a96fba6SXin Li   auto response = http::GetAndBlock("http://bad.url", {}, transport, nullptr);
441*1a96fba6SXin Li   EXPECT_EQ(status_code::NotFound, response->GetStatusCode());
442*1a96fba6SXin Li   EXPECT_EQ(brillo::mime::text::kHtml, response->GetContentType());
443*1a96fba6SXin Li   int code = 0;
444*1a96fba6SXin Li   auto json = http::ParseJsonResponse(response.get(), &code, nullptr);
445*1a96fba6SXin Li   EXPECT_EQ(nullptr, json.get());
446*1a96fba6SXin Li   EXPECT_EQ(status_code::NotFound, code);
447*1a96fba6SXin Li }
448*1a96fba6SXin Li 
TEST(HttpUtils,SendRequest_Failure)449*1a96fba6SXin Li TEST(HttpUtils, SendRequest_Failure) {
450*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
451*1a96fba6SXin Li   transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
452*1a96fba6SXin Li   ErrorPtr error;
453*1a96fba6SXin Li   Error::AddTo(&error, FROM_HERE, "test_domain", "test_code", "Test message");
454*1a96fba6SXin Li   transport->SetCreateConnectionError(std::move(error));
455*1a96fba6SXin Li   error.reset();  // Just to make sure it is empty...
456*1a96fba6SXin Li   auto response = http::SendRequestWithNoDataAndBlock(
457*1a96fba6SXin Li       request_type::kGet, "http://blah.com", {}, transport, &error);
458*1a96fba6SXin Li   EXPECT_EQ(nullptr, response.get());
459*1a96fba6SXin Li   EXPECT_EQ("test_domain", error->GetDomain());
460*1a96fba6SXin Li   EXPECT_EQ("test_code", error->GetCode());
461*1a96fba6SXin Li   EXPECT_EQ("Test message", error->GetMessage());
462*1a96fba6SXin Li }
463*1a96fba6SXin Li 
TEST(HttpUtils,SendRequestAsync_Failure)464*1a96fba6SXin Li TEST(HttpUtils, SendRequestAsync_Failure) {
465*1a96fba6SXin Li   std::shared_ptr<fake::Transport> transport(new fake::Transport);
466*1a96fba6SXin Li   transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
467*1a96fba6SXin Li   ErrorPtr error;
468*1a96fba6SXin Li   Error::AddTo(&error, FROM_HERE, "test_domain", "test_code", "Test message");
469*1a96fba6SXin Li   transport->SetCreateConnectionError(std::move(error));
470*1a96fba6SXin Li   auto success_callback =
471*1a96fba6SXin Li       [](RequestID /* request_id */,
472*1a96fba6SXin Li          std::unique_ptr<http::Response> /* response */) {
473*1a96fba6SXin Li     FAIL() << "This callback shouldn't have been called";
474*1a96fba6SXin Li   };
475*1a96fba6SXin Li   auto error_callback = [](RequestID /* request_id */, const Error* error) {
476*1a96fba6SXin Li     EXPECT_EQ("test_domain", error->GetDomain());
477*1a96fba6SXin Li     EXPECT_EQ("test_code", error->GetCode());
478*1a96fba6SXin Li     EXPECT_EQ("Test message", error->GetMessage());
479*1a96fba6SXin Li   };
480*1a96fba6SXin Li   http::SendRequestWithNoData(request_type::kGet,
481*1a96fba6SXin Li                               "http://blah.com",
482*1a96fba6SXin Li                               {},
483*1a96fba6SXin Li                               transport,
484*1a96fba6SXin Li                               base::Bind(success_callback),
485*1a96fba6SXin Li                               base::Bind(error_callback));
486*1a96fba6SXin Li }
487*1a96fba6SXin Li 
TEST(HttpUtils,GetCanonicalHeaderName)488*1a96fba6SXin Li TEST(HttpUtils, GetCanonicalHeaderName) {
489*1a96fba6SXin Li   EXPECT_EQ("Foo", GetCanonicalHeaderName("foo"));
490*1a96fba6SXin Li   EXPECT_EQ("Bar", GetCanonicalHeaderName("BaR"));
491*1a96fba6SXin Li   EXPECT_EQ("Baz", GetCanonicalHeaderName("BAZ"));
492*1a96fba6SXin Li   EXPECT_EQ("Foo-Bar", GetCanonicalHeaderName("foo-bar"));
493*1a96fba6SXin Li   EXPECT_EQ("Foo-Bar-Baz", GetCanonicalHeaderName("foo-Bar-BAZ"));
494*1a96fba6SXin Li   EXPECT_EQ("Foo-Bar-Baz", GetCanonicalHeaderName("FOO-BAR-BAZ"));
495*1a96fba6SXin Li   EXPECT_EQ("Foo-Bar-", GetCanonicalHeaderName("fOO-bAR-"));
496*1a96fba6SXin Li   EXPECT_EQ("-Bar", GetCanonicalHeaderName("-bAR"));
497*1a96fba6SXin Li   EXPECT_EQ("", GetCanonicalHeaderName(""));
498*1a96fba6SXin Li   EXPECT_EQ("A-B-C", GetCanonicalHeaderName("a-B-c"));
499*1a96fba6SXin Li }
500*1a96fba6SXin Li 
501*1a96fba6SXin Li }  // namespace http
502*1a96fba6SXin Li }  // namespace brillo
503