1f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko// Copyright 2014 The Chromium OS Authors. All rights reserved.
2f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko// Use of this source code is governed by a BSD-style license that can be
3f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko// found in the LICENSE file.
4f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
5b57c2eebc4050087576f55e02deb47b0839fb467Bertrand SIMONNET#include <numeric>
6f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko#include <string>
7f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko#include <vector>
8f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
9f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko#include <base/values.h>
109ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/bind_lambda.h>
119ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/http/http_transport_fake.h>
129ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/http/http_utils.h>
139ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/mime_utils.h>
149ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/strings/string_utils.h>
159ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/url_utils.h>
16f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko#include <gtest/gtest.h>
17f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
189ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkonamespace brillo {
19f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenkonamespace http {
20f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
21f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenkostatic const char kFakeUrl[] = "http://localhost";
22f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenkostatic const char kEchoUrl[] = "http://localhost/echo";
23f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenkostatic const char kMethodEchoUrl[] = "http://localhost/echo/method";
24f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
25f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko///////////////////// Generic helper request handlers /////////////////////////
26f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko// Returns the request data back with the same content type.
27f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenkostatic void EchoDataHandler(const fake::ServerRequest& request,
28f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko                            fake::ServerResponse* response) {
2905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  response->Reply(status_code::Ok,
3005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                  request.GetData(),
312e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko                  request.GetHeader(request_header::kContentType));
32f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
33f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
34f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko// Returns the request method as a plain text response.
35f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenkostatic void EchoMethodHandler(const fake::ServerRequest& request,
36f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko                              fake::ServerResponse* response) {
3705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  response->ReplyText(
389ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko      status_code::Ok, request.GetMethod(), brillo::mime::text::kPlain);
39f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
40f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
41f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko///////////////////////////////////////////////////////////////////////////////
42f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex VakulenkoTEST(HttpUtils, SendRequest_BinaryData) {
43f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
4405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  transport->AddHandler(
4505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      kEchoUrl, request_type::kPost, base::Bind(EchoDataHandler));
46f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
47f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  // Test binary data round-tripping.
48f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::vector<uint8_t> custom_data{0xFF, 0x00, 0x80, 0x40, 0xC0, 0x7F};
4905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  auto response =
5005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      http::SendRequestAndBlock(request_type::kPost,
5105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                kEchoUrl,
5205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                custom_data.data(),
5305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                custom_data.size(),
549ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko                                brillo::mime::application::kOctet_stream,
5505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                {},
5605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                transport,
5705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                nullptr);
58f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(response->IsSuccessful());
599ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  EXPECT_EQ(brillo::mime::application::kOctet_stream,
60f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko            response->GetContentType());
6120d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko  EXPECT_EQ(custom_data, response->ExtractData());
62f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
63f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
64f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex VakulenkoTEST(HttpUtils, SendRequestAsync_BinaryData) {
65f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
6605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  transport->AddHandler(
6705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      kEchoUrl, request_type::kPost, base::Bind(EchoDataHandler));
68f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
69f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // Test binary data round-tripping.
70f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::vector<uint8_t> custom_data{0xFF, 0x00, 0x80, 0x40, 0xC0, 0x7F};
71ac3059d5edad2af5a75184d1e31133e712c91f60Alex Vakulenko  auto success_callback =
722fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley      [&custom_data](RequestID /* id */,
732fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley                     std::unique_ptr<http::Response> response) {
74f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    EXPECT_TRUE(response->IsSuccessful());
759ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    EXPECT_EQ(brillo::mime::application::kOctet_stream,
76f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko              response->GetContentType());
7720d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko    EXPECT_EQ(custom_data, response->ExtractData());
78f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  };
792fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley  auto error_callback = [](RequestID /* id */, const Error* /* error */) {
80f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    FAIL() << "This callback shouldn't have been called";
81f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  };
8205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  http::SendRequest(request_type::kPost,
8305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                    kEchoUrl,
8405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                    custom_data.data(),
8505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                    custom_data.size(),
869ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko                    brillo::mime::application::kOctet_stream,
8705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                    {},
8805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                    transport,
8905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                    base::Bind(success_callback),
9005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                    base::Bind(error_callback));
91f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko}
92f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
93f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex VakulenkoTEST(HttpUtils, SendRequest_Post) {
94f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
95f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
96f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
97f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  // Test binary data round-tripping.
98f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::vector<uint8_t> custom_data{0xFF, 0x00, 0x80, 0x40, 0xC0, 0x7F};
99f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
100f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  // Check the correct HTTP method used.
10105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  auto response =
10205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      http::SendRequestAndBlock(request_type::kPost,
10305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                kMethodEchoUrl,
10405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                custom_data.data(),
10505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                custom_data.size(),
1069ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko                                brillo::mime::application::kOctet_stream,
10705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                {},
10805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                transport,
10905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                nullptr);
110f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(response->IsSuccessful());
1119ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
11220d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko  EXPECT_EQ(request_type::kPost, response->ExtractDataAsString());
113f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
114f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
115f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex VakulenkoTEST(HttpUtils, SendRequest_Get) {
116f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
117f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
118f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
11905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  auto response = http::SendRequestAndBlock(request_type::kGet,
12005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                            kMethodEchoUrl,
12105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                            nullptr,
12205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                            0,
12305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                            std::string{},
12405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                            {},
12505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                            transport,
12605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                            nullptr);
127f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(response->IsSuccessful());
1289ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
12920d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko  EXPECT_EQ(request_type::kGet, response->ExtractDataAsString());
130f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
131f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
132f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex VakulenkoTEST(HttpUtils, SendRequest_Put) {
133f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
134f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
135f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
13605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  auto response = http::SendRequestAndBlock(request_type::kPut,
13705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                            kMethodEchoUrl,
13805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                            nullptr,
13905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                            0,
14005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                            std::string{},
14105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                            {},
14205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                            transport,
14305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                            nullptr);
144f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(response->IsSuccessful());
1459ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
14620d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko  EXPECT_EQ(request_type::kPut, response->ExtractDataAsString());
147f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
148f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
149f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex VakulenkoTEST(HttpUtils, SendRequest_NotFound) {
150f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
151f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  // Test failed response (URL not found).
152f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  auto response = http::SendRequestWithNoDataAndBlock(
153f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      request_type::kGet, "http://blah.com", {}, transport, nullptr);
154f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_FALSE(response->IsSuccessful());
155f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_EQ(status_code::NotFound, response->GetStatusCode());
156f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
157f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
158f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex VakulenkoTEST(HttpUtils, SendRequestAsync_NotFound) {
159f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
160f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // Test failed response (URL not found).
161ac3059d5edad2af5a75184d1e31133e712c91f60Alex Vakulenko  auto success_callback =
1622fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley      [](RequestID /* request_id */, std::unique_ptr<http::Response> response) {
163f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    EXPECT_FALSE(response->IsSuccessful());
164f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    EXPECT_EQ(status_code::NotFound, response->GetStatusCode());
165f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  };
1662fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley  auto error_callback = [](RequestID /* request_id */,
1672fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley                           const Error* /* error */) {
168f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    FAIL() << "This callback shouldn't have been called";
169f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  };
17005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  http::SendRequestWithNoData(request_type::kGet,
17105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                              "http://blah.com",
17205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                              {},
17305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                              transport,
17405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                              base::Bind(success_callback),
17505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                              base::Bind(error_callback));
176f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko}
177f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
178f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex VakulenkoTEST(HttpUtils, SendRequest_Headers) {
179f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
180f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
181f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  static const char json_echo_url[] = "http://localhost/echo/json";
18205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  auto JsonEchoHandler =
18305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      [](const fake::ServerRequest& request, fake::ServerResponse* response) {
184f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    base::DictionaryValue json;
185f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    json.SetString("method", request.GetMethod());
186f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    json.SetString("data", request.GetDataAsString());
187f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    for (const auto& pair : request.GetHeaders()) {
188f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko      json.SetString("header." + pair.first, pair.second);
189f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    }
190f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    response->ReplyJson(status_code::Ok, &json);
191f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  };
19205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  transport->AddHandler(json_echo_url, "*", base::Bind(JsonEchoHandler));
1932e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko  auto response = http::SendRequestAndBlock(
194f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko      request_type::kPost, json_echo_url, "abcd", 4,
1959ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko      brillo::mime::application::kOctet_stream, {
196f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko        {request_header::kCookie, "flavor=vanilla"},
197f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko        {request_header::kIfMatch, "*"},
198f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko      }, transport, nullptr);
199f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(response->IsSuccessful());
2009ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  EXPECT_EQ(brillo::mime::application::kJson,
2019ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko            brillo::mime::RemoveParameters(response->GetContentType()));
202f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  auto json = ParseJsonResponse(response.get(), nullptr, nullptr);
203f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::string value;
204f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(json->GetString("method", &value));
205f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_EQ(request_type::kPost, value);
206f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(json->GetString("data", &value));
207f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_EQ("abcd", value);
208f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(json->GetString("header.Cookie", &value));
209f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_EQ("flavor=vanilla", value);
210f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(json->GetString("header.Content-Type", &value));
2119ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  EXPECT_EQ(brillo::mime::application::kOctet_stream, value);
212f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(json->GetString("header.Content-Length", &value));
213f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_EQ("4", value);
214f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(json->GetString("header.If-Match", &value));
215f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_EQ("*", value);
216f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
217f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
218f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex VakulenkoTEST(HttpUtils, Get) {
219f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  // Sends back the "?test=..." portion of URL.
220f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  // So if we do GET "http://localhost?test=blah", this handler responds
221f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  // with "blah" as text/plain.
22205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  auto GetHandler =
22305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      [](const fake::ServerRequest& request, fake::ServerResponse* response) {
224f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_EQ(request_type::kGet, request.GetMethod());
225f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_EQ("0", request.GetHeader(request_header::kContentLength));
226f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_EQ("", request.GetHeader(request_header::kContentType));
22705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    response->ReplyText(status_code::Ok,
22805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                        request.GetFormField("test"),
2299ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko                        brillo::mime::text::kPlain);
230f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  };
231f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
232f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
233f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  transport->AddHandler(kFakeUrl, request_type::kGet, base::Bind(GetHandler));
234f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
235f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
236d360e9b5f7549eecf5651ab58a5d766a095caf2eAlex Vakulenko  // Make sure Get() actually does the GET request
2372e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko  auto response = http::GetAndBlock(kMethodEchoUrl, {}, transport, nullptr);
238f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(response->IsSuccessful());
2399ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
24020d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko  EXPECT_EQ(request_type::kGet, response->ExtractDataAsString());
241f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
242f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  for (std::string data : {"blah", "some data", ""}) {
2439ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    std::string url = brillo::url::AppendQueryParam(kFakeUrl, "test", data);
244d360e9b5f7549eecf5651ab58a5d766a095caf2eAlex Vakulenko    response = http::GetAndBlock(url, {}, transport, nullptr);
24520d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko    EXPECT_EQ(data, response->ExtractDataAsString());
246f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  }
247f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
248f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
249f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex VakulenkoTEST(HttpUtils, Head) {
25005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  auto HeadHandler =
25105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      [](const fake::ServerRequest& request, fake::ServerResponse* response) {
252f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_EQ(request_type::kHead, request.GetMethod());
253f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_EQ("0", request.GetHeader(request_header::kContentLength));
254f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_EQ("", request.GetHeader(request_header::kContentType));
2559ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    response->ReplyText(status_code::Ok, "blah", brillo::mime::text::kPlain);
256f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  };
257f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
258f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
259f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  transport->AddHandler(kFakeUrl, request_type::kHead, base::Bind(HeadHandler));
260f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
2612e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko  auto response = http::HeadAndBlock(kFakeUrl, transport, nullptr);
262f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(response->IsSuccessful());
2639ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
26420d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko  EXPECT_EQ("", response->ExtractDataAsString());  // Must not have actual body.
265f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_EQ("4", response->GetHeader(request_header::kContentLength));
266f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
267f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
268f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex VakulenkoTEST(HttpUtils, PostBinary) {
26905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  auto Handler =
27005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      [](const fake::ServerRequest& request, fake::ServerResponse* response) {
271f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_EQ(request_type::kPost, request.GetMethod());
272f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_EQ("256", request.GetHeader(request_header::kContentLength));
2739ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    EXPECT_EQ(brillo::mime::application::kOctet_stream,
274f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko              request.GetHeader(request_header::kContentType));
275f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    const auto& data = request.GetData();
276f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_EQ(256, data.size());
277f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
278f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    // Sum up all the bytes.
279f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    int sum = std::accumulate(data.begin(), data.end(), 0);
280f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_EQ(32640, sum);  // sum(i, i => [0, 255]) = 32640.
2819ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    response->ReplyText(status_code::Ok, "", brillo::mime::text::kPlain);
282f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  };
283f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
284f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
285f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  transport->AddHandler(kFakeUrl, request_type::kPost, base::Bind(Handler));
286f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
287f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  /// Fill the data buffer with bytes from 0x00 to 0xFF.
288f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::vector<uint8_t> data(256);
289f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::iota(data.begin(), data.end(), 0);
290f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
29105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  auto response = http::PostBinaryAndBlock(kFakeUrl,
29205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                           data.data(),
29305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                           data.size(),
29405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                           mime::application::kOctet_stream,
29505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                           {},
29605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                           transport,
29705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                           nullptr);
298f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(response->IsSuccessful());
299f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
300f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
301f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex VakulenkoTEST(HttpUtils, PostText) {
302f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::string fake_data = "Some data";
303f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  auto PostHandler = [fake_data](const fake::ServerRequest& request,
304f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko                                 fake::ServerResponse* response) {
305f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_EQ(request_type::kPost, request.GetMethod());
306f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_EQ(fake_data.size(),
307f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko              std::stoul(request.GetHeader(request_header::kContentLength)));
3089ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    EXPECT_EQ(brillo::mime::text::kPlain,
309f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko              request.GetHeader(request_header::kContentType));
31005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    response->ReplyText(status_code::Ok,
31105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                        request.GetDataAsString(),
3129ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko                        brillo::mime::text::kPlain);
313f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  };
314f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
315f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
316f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  transport->AddHandler(kFakeUrl, request_type::kPost, base::Bind(PostHandler));
317f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
31805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  auto response = http::PostTextAndBlock(kFakeUrl,
31905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                         fake_data,
3209ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko                                         brillo::mime::text::kPlain,
32105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                         {},
32205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                         transport,
32305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                         nullptr);
324f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(response->IsSuccessful());
3259ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  EXPECT_EQ(brillo::mime::text::kPlain, response->GetContentType());
32620d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko  EXPECT_EQ(fake_data, response->ExtractDataAsString());
327f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
328f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
329f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex VakulenkoTEST(HttpUtils, PostFormData) {
330f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
33105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  transport->AddHandler(
33205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      kFakeUrl, request_type::kPost, base::Bind(EchoDataHandler));
333f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
3342e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko  auto response = http::PostFormDataAndBlock(
3352e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko      kFakeUrl, {
3362e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko          {"key", "value"},
3372e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko          {"field", "field value"},
3382e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko      }, {}, transport, nullptr);
339f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(response->IsSuccessful());
3409ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  EXPECT_EQ(brillo::mime::application::kWwwFormUrlEncoded,
341f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko            response->GetContentType());
34220d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko  EXPECT_EQ("key=value&field=field+value", response->ExtractDataAsString());
343f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
344f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
34547e9a9dd3dce9d197820ee4241135e6859f95360Alex VakulenkoTEST(HttpUtils, PostMultipartFormData) {
34647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
34705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  transport->AddHandler(
34805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      kFakeUrl, request_type::kPost, base::Bind(EchoDataHandler));
34947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko
35047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  std::unique_ptr<FormData> form_data{new FormData{"boundary123"}};
35147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  form_data->AddTextField("key1", "value1");
35247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  form_data->AddTextField("key2", "value2");
35347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  std::string expected_content_type = form_data->GetContentType();
35405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  auto response = http::PostFormDataAndBlock(
35505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      kFakeUrl, std::move(form_data), {}, transport, nullptr);
35647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  EXPECT_TRUE(response->IsSuccessful());
35747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  EXPECT_EQ(expected_content_type, response->GetContentType());
35847e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  const char expected_value[] =
35947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "--boundary123\r\n"
36047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Disposition: form-data; name=\"key1\"\r\n"
36147e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "\r\n"
36247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "value1\r\n"
36347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "--boundary123\r\n"
36447e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "Content-Disposition: form-data; name=\"key2\"\r\n"
36547e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "\r\n"
36647e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "value2\r\n"
36747e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko      "--boundary123--";
36820d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko  EXPECT_EQ(expected_value, response->ExtractDataAsString());
36947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko}
37047e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko
371f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex VakulenkoTEST(HttpUtils, PostPatchJson) {
37205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  auto JsonHandler =
37305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      [](const fake::ServerRequest& request, fake::ServerResponse* response) {
3749ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    auto mime_type = brillo::mime::RemoveParameters(
375f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko        request.GetHeader(request_header::kContentType));
3769ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    EXPECT_EQ(brillo::mime::application::kJson, mime_type);
37705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    response->ReplyJson(
37805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko        status_code::Ok,
37905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko        {
38020d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko          {"method", request.GetMethod()}, {"data", request.GetDataAsString()},
38105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko        });
382f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  };
383f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
384f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  transport->AddHandler(kFakeUrl, "*", base::Bind(JsonHandler));
385f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
386f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  base::DictionaryValue json;
387f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  json.SetString("key1", "val1");
388f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  json.SetString("key2", "val2");
389f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::string value;
390f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
391f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  // Test POST
3922e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko  auto response =
3932e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko      http::PostJsonAndBlock(kFakeUrl, &json, {}, transport, nullptr);
394f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  auto resp_json = http::ParseJsonResponse(response.get(), nullptr, nullptr);
395f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_NE(nullptr, resp_json.get());
396f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(resp_json->GetString("method", &value));
397f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_EQ(request_type::kPost, value);
398f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(resp_json->GetString("data", &value));
399f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_EQ("{\"key1\":\"val1\",\"key2\":\"val2\"}", value);
400f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
401f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  // Test PATCH
4022e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko  response = http::PatchJsonAndBlock(kFakeUrl, &json, {}, transport, nullptr);
403f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  resp_json = http::ParseJsonResponse(response.get(), nullptr, nullptr);
404f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_NE(nullptr, resp_json.get());
405f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(resp_json->GetString("method", &value));
406f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_EQ(request_type::kPatch, value);
407f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_TRUE(resp_json->GetString("data", &value));
408f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_EQ("{\"key1\":\"val1\",\"key2\":\"val2\"}", value);
409f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
410f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
411f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex VakulenkoTEST(HttpUtils, ParseJsonResponse) {
41205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  auto JsonHandler =
41305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      [](const fake::ServerRequest& request, fake::ServerResponse* response) {
414f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    int status_code = std::stoi(request.GetFormField("code"));
415f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    response->ReplyJson(status_code, {{"data", request.GetFormField("value")}});
416f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  };
417f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
418f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  transport->AddHandler(kFakeUrl, request_type::kPost, base::Bind(JsonHandler));
419f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
420f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  // Test valid JSON responses (with success or error codes).
421f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  for (auto item : {"200;data", "400;wrong", "500;Internal Server error"}) {
4229ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    auto pair = brillo::string_utils::SplitAtFirst(item, ";");
4232e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko    auto response = http::PostFormDataAndBlock(
4242e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko        kFakeUrl, {
4252e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko          {"code", pair.first},
4262e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko          {"value", pair.second},
4272e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko        }, {}, transport, nullptr);
428f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    int code = 0;
429f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    auto json = http::ParseJsonResponse(response.get(), &code, nullptr);
430f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_NE(nullptr, json.get());
431f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    std::string value;
432f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_TRUE(json->GetString("data", &value));
4339ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko    EXPECT_EQ(pair.first, brillo::string_utils::ToString(code));
434f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    EXPECT_EQ(pair.second, value);
435f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  }
436f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
437f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  // Test invalid (non-JSON) response.
4382e1579107504b584d59e4ab036544369321f2a58Alex Vakulenko  auto response = http::GetAndBlock("http://bad.url", {}, transport, nullptr);
439f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_EQ(status_code::NotFound, response->GetStatusCode());
4409ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  EXPECT_EQ(brillo::mime::text::kHtml, response->GetContentType());
441f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  int code = 0;
442f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  auto json = http::ParseJsonResponse(response.get(), &code, nullptr);
443f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_EQ(nullptr, json.get());
444f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  EXPECT_EQ(status_code::NotFound, code);
445f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
446f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
447f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex VakulenkoTEST(HttpUtils, SendRequest_Failure) {
448f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
449f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
450f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  ErrorPtr error;
451f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  Error::AddTo(&error, FROM_HERE, "test_domain", "test_code", "Test message");
452f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  transport->SetCreateConnectionError(std::move(error));
453f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  error.reset();  // Just to make sure it is empty...
454f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  auto response = http::SendRequestWithNoDataAndBlock(
455f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      request_type::kGet, "http://blah.com", {}, transport, &error);
456f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_EQ(nullptr, response.get());
457f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_EQ("test_domain", error->GetDomain());
458f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_EQ("test_code", error->GetCode());
459f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_EQ("Test message", error->GetMessage());
460f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko}
461f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
462f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex VakulenkoTEST(HttpUtils, SendRequestAsync_Failure) {
463f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::shared_ptr<fake::Transport> transport(new fake::Transport);
464f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  transport->AddHandler(kMethodEchoUrl, "*", base::Bind(EchoMethodHandler));
465f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  ErrorPtr error;
466f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  Error::AddTo(&error, FROM_HERE, "test_domain", "test_code", "Test message");
467f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  transport->SetCreateConnectionError(std::move(error));
468ac3059d5edad2af5a75184d1e31133e712c91f60Alex Vakulenko  auto success_callback =
4692fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley      [](RequestID /* request_id */,
4702fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley         std::unique_ptr<http::Response> /* response */) {
471f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    FAIL() << "This callback shouldn't have been called";
472f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  };
4732fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley  auto error_callback = [](RequestID /* request_id */, const Error* error) {
474f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    EXPECT_EQ("test_domain", error->GetDomain());
475f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    EXPECT_EQ("test_code", error->GetCode());
476f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    EXPECT_EQ("Test message", error->GetMessage());
477f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  };
47805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  http::SendRequestWithNoData(request_type::kGet,
47905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                              "http://blah.com",
48005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                              {},
48105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                              transport,
48205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                              base::Bind(success_callback),
48305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                              base::Bind(error_callback));
484f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko}
485f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
486eff2061417e01d42b150d508d364733519a55653Alex VakulenkoTEST(HttpUtils, GetCanonicalHeaderName) {
487eff2061417e01d42b150d508d364733519a55653Alex Vakulenko  EXPECT_EQ("Foo", GetCanonicalHeaderName("foo"));
488eff2061417e01d42b150d508d364733519a55653Alex Vakulenko  EXPECT_EQ("Bar", GetCanonicalHeaderName("BaR"));
489eff2061417e01d42b150d508d364733519a55653Alex Vakulenko  EXPECT_EQ("Baz", GetCanonicalHeaderName("BAZ"));
490eff2061417e01d42b150d508d364733519a55653Alex Vakulenko  EXPECT_EQ("Foo-Bar", GetCanonicalHeaderName("foo-bar"));
491eff2061417e01d42b150d508d364733519a55653Alex Vakulenko  EXPECT_EQ("Foo-Bar-Baz", GetCanonicalHeaderName("foo-Bar-BAZ"));
492eff2061417e01d42b150d508d364733519a55653Alex Vakulenko  EXPECT_EQ("Foo-Bar-Baz", GetCanonicalHeaderName("FOO-BAR-BAZ"));
493eff2061417e01d42b150d508d364733519a55653Alex Vakulenko  EXPECT_EQ("Foo-Bar-", GetCanonicalHeaderName("fOO-bAR-"));
494eff2061417e01d42b150d508d364733519a55653Alex Vakulenko  EXPECT_EQ("-Bar", GetCanonicalHeaderName("-bAR"));
495eff2061417e01d42b150d508d364733519a55653Alex Vakulenko  EXPECT_EQ("", GetCanonicalHeaderName(""));
496eff2061417e01d42b150d508d364733519a55653Alex Vakulenko  EXPECT_EQ("A-B-C", GetCanonicalHeaderName("a-B-c"));
497eff2061417e01d42b150d508d364733519a55653Alex Vakulenko}
498eff2061417e01d42b150d508d364733519a55653Alex Vakulenko
499f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}  // namespace http
5009ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko}  // namespace brillo
501