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