1f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko// Copyright 2014 The Chromium OS Authors. All rights reserved.
2f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko// Use of this source code is governed by a BSD-style license that can be
3f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko// found in the LICENSE file.
4f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
59ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/http/http_connection_curl.h>
6f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
7f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko#include <algorithm>
8f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko#include <set>
9f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
10f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko#include <base/callback.h>
119ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/http/http_request.h>
129ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/http/http_transport.h>
139ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/http/mock_curl_api.h>
149ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/http/mock_transport.h>
159ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/streams/memory_stream.h>
169ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/streams/mock_stream.h>
179ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/strings/string_utils.h>
189ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/mime_utils.h>
19f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko#include <gmock/gmock.h>
20f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko#include <gtest/gtest.h>
21f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
22f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenkousing testing::DoAll;
23f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenkousing testing::Invoke;
24f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenkousing testing::Return;
25f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenkousing testing::SetArgPointee;
26f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenkousing testing::_;
27f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
289ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkonamespace brillo {
29f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenkonamespace http {
30f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenkonamespace curl {
31f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
32f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenkonamespace {
33f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
34f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenkousing ReadWriteCallback =
35f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    size_t(char* ptr, size_t size, size_t num, void* data);
36f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
37f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko// A helper class to simulate curl_easy_perform action. It invokes the
38f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko// read callbacks to obtain the request data from the Connection and then
39f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko// calls the header and write callbacks to "send" the response header and body.
40f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenkoclass CurlPerformer {
41f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko public:
42f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // During the tests, use the address of |this| as the CURL* handle.
43f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // This allows the static Perform() method to obtain the instance pointer
44f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // having only CURL*.
45f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  CURL* GetCurlHandle() { return reinterpret_cast<CURL*>(this); }
46f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
47f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // Callback to be invoked when mocking out curl_easy_perform() method.
48f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  static CURLcode Perform(CURL* curl) {
49f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    CurlPerformer* me = reinterpret_cast<CurlPerformer*>(curl);
50f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    return me->DoPerform();
51f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  }
52f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
53f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // CURL callback functions and |connection| pointer needed to invoke the
54f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // callbacks from the Connection class.
55f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  Connection* connection{nullptr};
56f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  ReadWriteCallback* write_callback{nullptr};
57f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  ReadWriteCallback* read_callback{nullptr};
58f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  ReadWriteCallback* header_callback{nullptr};
59f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
60f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // Request body read from the connection.
61f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::string request_body;
62f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
63f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // Response data to be sent back to connection.
64f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::string status_line;
65f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  HeaderList response_headers;
66f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::string response_body;
67f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
68f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko private:
69f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // The actual implementation of curl_easy_perform() fake.
70f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  CURLcode DoPerform() {
71f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    // Read request body.
72f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    char buffer[1024];
73f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    for (;;) {
74f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      size_t size_read = read_callback(buffer, sizeof(buffer), 1, connection);
75f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      if (size_read == CURL_READFUNC_ABORT)
76f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko        return CURLE_ABORTED_BY_CALLBACK;
77f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      if (size_read == CURL_READFUNC_PAUSE)
78f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko        return CURLE_READ_ERROR;  // Shouldn't happen.
79f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      if (size_read == 0)
80f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko        break;
81f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      request_body.append(buffer, size_read);
82f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    }
83f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
84f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    // Send the response headers.
85f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    std::vector<std::string> header_lines;
86f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    header_lines.push_back(status_line + "\r\n");
87f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    for (const auto& pair : response_headers) {
8805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      header_lines.push_back(string_utils::Join(": ", pair.first, pair.second) +
8905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                             "\r\n");
90f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    }
91f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
92f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    for (const std::string& line : header_lines) {
93f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      CURLcode code = WriteString(header_callback, line);
94f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      if (code != CURLE_OK)
95f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko        return code;
96f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    }
97f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
98f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    // Send response body.
99f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    return WriteString(write_callback, response_body);
100f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  }
101f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
102f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // Helper method to send a string to a write callback. Keeps calling
103f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // the callback until all the data is written.
104f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  CURLcode WriteString(ReadWriteCallback* callback, const std::string& str) {
105f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    size_t pos = 0;
106f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    size_t size_remaining = str.size();
107f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    while (size_remaining) {
10805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      size_t size_written = callback(
10905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko          const_cast<char*>(str.data() + pos), size_remaining, 1, connection);
110f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      if (size_written == CURL_WRITEFUNC_PAUSE)
111f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko        return CURLE_WRITE_ERROR;  // Shouldn't happen.
112f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      CHECK(size_written <= size_remaining) << "Unexpected size returned";
113f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      size_remaining -= size_written;
114f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      pos += size_written;
115f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    }
116f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    return CURLE_OK;
117f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  }
118f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko};
119f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
120f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko// Custom matcher to validate the parameter of CURLOPT_HTTPHEADER CURL option
121f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko// which contains the request headers as curl_slist* chain.
122f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex VakulenkoMATCHER_P(HeadersMatch, headers, "") {
123f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::multiset<std::string> test_headers;
124f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  for (const auto& pair : headers)
125f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    test_headers.insert(string_utils::Join(": ", pair.first, pair.second));
126f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
127f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::multiset<std::string> src_headers;
128f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  const curl_slist* head = static_cast<const curl_slist*>(arg);
129f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  while (head) {
130f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    src_headers.insert(head->data);
131f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    head = head->next;
132f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  }
133f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
134f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::vector<std::string> difference;
135f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::set_symmetric_difference(src_headers.begin(), src_headers.end(),
136f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko                                test_headers.begin(), test_headers.end(),
137f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko                                std::back_inserter(difference));
138f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  return difference.empty();
139f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko}
140f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
141f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko// Custom action to save a CURL callback pointer into a member of CurlPerformer.
142f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex VakulenkoACTION_TEMPLATE(SaveCallback,
143f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko                HAS_1_TEMPLATE_PARAMS(int, k),
144f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko                AND_2_VALUE_PARAMS(performer, mem_ptr)) {
145f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  performer->*mem_ptr = reinterpret_cast<ReadWriteCallback*>(std::get<k>(args));
146f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko}
147f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
148f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko}  // anonymous namespace
149f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
150f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenkoclass HttpCurlConnectionTest : public testing::Test {
151f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko public:
152f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  void SetUp() override {
153f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    curl_api_ = std::make_shared<MockCurlInterface>();
154f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    transport_ = std::make_shared<MockTransport>();
155aa7d677661213b4116adc5fac88b8c37a1490010Alex Vakulenko    EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_PRIVATE, _))
156aa7d677661213b4116adc5fac88b8c37a1490010Alex Vakulenko        .WillOnce(Return(CURLE_OK));
15705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    connection_ = std::make_shared<Connection>(
15805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko        handle_, request_type::kPost, curl_api_, transport_);
159f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    performer_.connection = connection_.get();
160f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  }
161f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
162f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  void TearDown() override {
163f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    EXPECT_CALL(*curl_api_, EasyCleanup(handle_)).Times(1);
164f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    connection_.reset();
165f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    transport_.reset();
166f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    curl_api_.reset();
167f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  }
168f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
169f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko protected:
170f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::shared_ptr<MockCurlInterface> curl_api_;
171f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::shared_ptr<MockTransport> transport_;
172f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  CurlPerformer performer_;
173f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  CURL* handle_{performer_.GetCurlHandle()};
174f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::shared_ptr<Connection> connection_;
175f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko};
176f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
177f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex VakulenkoTEST_F(HttpCurlConnectionTest, FinishRequestAsync) {
178f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::string request_data{"Foo Bar Baz"};
17980663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  StreamPtr stream = MemoryStream::OpenRef(request_data, nullptr);
18080663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  EXPECT_TRUE(connection_->SetRequestData(std::move(stream), nullptr));
181f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_TRUE(connection_->SendHeaders({{"X-Foo", "bar"}}, nullptr));
182f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
183f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  if (VLOG_IS_ON(3)) {
184f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    EXPECT_CALL(*curl_api_,
185f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko                EasySetOptCallback(handle_, CURLOPT_DEBUGFUNCTION, _))
186f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko        .WillOnce(Return(CURLE_OK));
187f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_VERBOSE, 1))
188f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko        .WillOnce(Return(CURLE_OK));
189f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  }
190f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
19105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  EXPECT_CALL(
19205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      *curl_api_,
19305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      EasySetOptOffT(handle_, CURLOPT_POSTFIELDSIZE_LARGE, request_data.size()))
194f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(Return(CURLE_OK));
195f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
196f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_, EasySetOptCallback(handle_, CURLOPT_READFUNCTION, _))
197f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(Return(CURLE_OK));
198f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_READDATA, _))
199f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(Return(CURLE_OK));
200f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
201f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_HTTPHEADER, _))
202f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(Return(CURLE_OK));
203f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
204f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_, EasySetOptCallback(handle_, CURLOPT_WRITEFUNCTION, _))
205f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(Return(CURLE_OK));
206f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_WRITEDATA, _))
207f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(Return(CURLE_OK));
208f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
209f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_,
210f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko              EasySetOptCallback(handle_, CURLOPT_HEADERFUNCTION, _))
211f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(Return(CURLE_OK));
212f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_HEADERDATA, _))
213f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(Return(CURLE_OK));
214f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
215f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*transport_, StartAsyncTransfer(connection_.get(), _, _))
216f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .Times(1);
217f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  connection_->FinishRequestAsync({}, {});
218f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko}
219f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
220c5a9d47576cf0e2f80bd7714d0edd7eeb5ce4677Bertrand SIMONNETMATCHER_P(MatchStringBuffer, data, "") {
221c5a9d47576cf0e2f80bd7714d0edd7eeb5ce4677Bertrand SIMONNET  return data.compare(static_cast<const char*>(arg)) == 0;
222c5a9d47576cf0e2f80bd7714d0edd7eeb5ce4677Bertrand SIMONNET}
223c5a9d47576cf0e2f80bd7714d0edd7eeb5ce4677Bertrand SIMONNET
224f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex VakulenkoTEST_F(HttpCurlConnectionTest, FinishRequest) {
225f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  std::string request_data{"Foo Bar Baz"};
2262eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock  std::string response_data{"<html><body>OK</body></html>"};
22780663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  StreamPtr stream = MemoryStream::OpenRef(request_data, nullptr);
228f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  HeaderList headers{
22905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      {request_header::kAccept, "*/*"},
23005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      {request_header::kContentType, mime::text::kPlain},
23105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      {request_header::kContentLength, std::to_string(request_data.size())},
23205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      {"X-Foo", "bar"},
233f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  };
2342eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock  std::unique_ptr<MockStream> response_stream(new MockStream);
235c5a9d47576cf0e2f80bd7714d0edd7eeb5ce4677Bertrand SIMONNET  EXPECT_CALL(*response_stream,
236c5a9d47576cf0e2f80bd7714d0edd7eeb5ce4677Bertrand SIMONNET              WriteAllBlocking(MatchStringBuffer(response_data),
237c5a9d47576cf0e2f80bd7714d0edd7eeb5ce4677Bertrand SIMONNET                               response_data.size(), _))
2382eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock      .WillOnce(Return(true));
2392eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock  EXPECT_CALL(*response_stream, CanSeek())
2402eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock      .WillOnce(Return(false));
2412eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock  connection_->SetResponseData(std::move(response_stream));
24280663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  EXPECT_TRUE(connection_->SetRequestData(std::move(stream), nullptr));
243f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_TRUE(connection_->SendHeaders(headers, nullptr));
244f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
245f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // Expectations for Connection::FinishRequest() call.
246f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  if (VLOG_IS_ON(3)) {
247f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    EXPECT_CALL(*curl_api_,
248f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko                EasySetOptCallback(handle_, CURLOPT_DEBUGFUNCTION, _))
249f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko        .WillOnce(Return(CURLE_OK));
250f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    EXPECT_CALL(*curl_api_, EasySetOptInt(handle_, CURLOPT_VERBOSE, 1))
251f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko        .WillOnce(Return(CURLE_OK));
252f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  }
253f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
25405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  EXPECT_CALL(
25505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      *curl_api_,
25605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      EasySetOptOffT(handle_, CURLOPT_POSTFIELDSIZE_LARGE, request_data.size()))
257f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(Return(CURLE_OK));
258f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
259f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_, EasySetOptCallback(handle_, CURLOPT_READFUNCTION, _))
26005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      .WillOnce(
26105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko          DoAll(SaveCallback<2>(&performer_, &CurlPerformer::read_callback),
26205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                Return(CURLE_OK)));
263f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_READDATA, _))
264f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(Return(CURLE_OK));
265f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
266f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_,
267f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko              EasySetOptPtr(handle_, CURLOPT_HTTPHEADER, HeadersMatch(headers)))
268f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(Return(CURLE_OK));
269f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
270f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_, EasySetOptCallback(handle_, CURLOPT_WRITEFUNCTION, _))
27105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      .WillOnce(
27205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko          DoAll(SaveCallback<2>(&performer_, &CurlPerformer::write_callback),
27305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                Return(CURLE_OK)));
274f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_WRITEDATA, _))
275f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(Return(CURLE_OK));
276f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
277f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_,
278f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko              EasySetOptCallback(handle_, CURLOPT_HEADERFUNCTION, _))
27905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      .WillOnce(
28005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko          DoAll(SaveCallback<2>(&performer_, &CurlPerformer::header_callback),
28105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                Return(CURLE_OK)));
282f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_, EasySetOptPtr(handle_, CURLOPT_HEADERDATA, _))
283f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(Return(CURLE_OK));
284f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
285f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_, EasyPerform(handle_))
286f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(Invoke(&CurlPerformer::Perform));
287f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
288f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_, EasyGetInfoInt(handle_, CURLINFO_RESPONSE_CODE, _))
289f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(DoAll(SetArgPointee<2>(status_code::Ok), Return(CURLE_OK)));
290f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
291f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // Set up the CurlPerformer with the response data expected to be received.
292f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  HeaderList response_headers{
29305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      {response_header::kContentLength, std::to_string(response_data.size())},
29405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      {response_header::kContentType, mime::text::kHtml},
29505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      {"X-Foo", "baz"},
296f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  };
297f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  performer_.status_line = "HTTP/1.1 200 OK";
298f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  performer_.response_body = response_data;
299f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  performer_.response_headers = response_headers;
300f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
301f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // Perform the request.
302f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_TRUE(connection_->FinishRequest(nullptr));
303f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
304f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // Make sure we sent out the request body correctly.
305f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_EQ(request_data, performer_.request_body);
306f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
307f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  // Validate the parsed response data.
308f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_CALL(*curl_api_, EasyGetInfoInt(handle_, CURLINFO_RESPONSE_CODE, _))
309f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      .WillOnce(DoAll(SetArgPointee<2>(status_code::Ok), Return(CURLE_OK)));
310f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_EQ(status_code::Ok, connection_->GetResponseStatusCode());
311f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_EQ("HTTP/1.1", connection_->GetProtocolVersion());
312f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_EQ("OK", connection_->GetResponseStatusText());
313f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_EQ(std::to_string(response_data.size()),
314f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko            connection_->GetResponseHeader(response_header::kContentLength));
315f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_EQ(mime::text::kHtml,
316f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko            connection_->GetResponseHeader(response_header::kContentType));
317f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  EXPECT_EQ("baz", connection_->GetResponseHeader("X-Foo"));
31820d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko  auto data_stream = connection_->ExtractDataStream(nullptr);
31920d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko  ASSERT_NE(nullptr, data_stream.get());
320f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko}
321f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko
322f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko}  // namespace curl
323f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko}  // namespace http
3249ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko}  // namespace brillo
325