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
59ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/http/http_connection_curl.h>
6f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
7f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko#include <base/logging.h>
89ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/http/http_request.h>
99ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/http/http_transport_curl.h>
109ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/streams/memory_stream.h>
119ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/streams/stream_utils.h>
129ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/strings/string_utils.h>
13f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
149ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkonamespace brillo {
15f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenkonamespace http {
16f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenkonamespace curl {
17f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
182fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wileystatic int curl_trace(CURL* /* handle */,
1905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                      curl_infotype type,
2005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                      char* data,
2105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                      size_t size,
222fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley                      void* /* userp */) {
23f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::string msg(data, size);
24f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
25f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  switch (type) {
2605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    case CURLINFO_TEXT:
2705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      VLOG(3) << "== Info: " << msg;
2805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      break;
2905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    case CURLINFO_HEADER_OUT:
3005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      VLOG(3) << "=> Send headers:\n" << msg;
3105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      break;
3205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    case CURLINFO_DATA_OUT:
3305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      VLOG(3) << "=> Send data:\n" << msg;
3405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      break;
3505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    case CURLINFO_SSL_DATA_OUT:
3605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      VLOG(3) << "=> Send SSL data" << msg;
3705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      break;
3805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    case CURLINFO_HEADER_IN:
3905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      VLOG(3) << "<= Recv header: " << msg;
4005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      break;
4105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    case CURLINFO_DATA_IN:
4205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      VLOG(3) << "<= Recv data:\n" << msg;
4305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      break;
4405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    case CURLINFO_SSL_DATA_IN:
4505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      VLOG(3) << "<= Recv SSL data" << msg;
4605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      break;
4705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    default:
4805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      break;
49f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  }
50f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  return 0;
51f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
52f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
53f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex VakulenkoConnection::Connection(CURL* curl_handle,
54f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko                       const std::string& method,
55f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko                       const std::shared_ptr<CurlInterface>& curl_interface,
56f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko                       const std::shared_ptr<http::Transport>& transport)
57f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    : http::Connection(transport),
58f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      method_(method),
59f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      curl_handle_(curl_handle),
60f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      curl_interface_(curl_interface) {
61aa7d677661213b4116adc5fac88b8c37a1490010Alex Vakulenko  // Store the connection pointer inside the CURL handle so we can easily
62aa7d677661213b4116adc5fac88b8c37a1490010Alex Vakulenko  // retrieve it when doing asynchronous I/O.
63aa7d677661213b4116adc5fac88b8c37a1490010Alex Vakulenko  curl_interface_->EasySetOptPtr(curl_handle_, CURLOPT_PRIVATE, this);
64d4c955c70812b91796ace5cfecfa181f62f6a348Alex Vakulenko  VLOG(2) << "curl::Connection created: " << method_;
65f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
66f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
67f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex VakulenkoConnection::~Connection() {
68f95a2b9e277726d8793a5849ec6e81c038c22be3Alex Vakulenko  if (header_list_)
69f95a2b9e277726d8793a5849ec6e81c038c22be3Alex Vakulenko    curl_slist_free_all(header_list_);
70f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  curl_interface_->EasyCleanup(curl_handle_);
71d4c955c70812b91796ace5cfecfa181f62f6a348Alex Vakulenko  VLOG(2) << "curl::Connection destroyed";
72f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
73f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
74f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenkobool Connection::SendHeaders(const HeaderList& headers,
752fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley                             brillo::ErrorPtr* /* error */) {
76f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  headers_.insert(headers.begin(), headers.end());
77f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  return true;
78f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
79f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
802fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wileybool Connection::SetRequestData(StreamPtr stream,
812fd46ba1458275cd16b0949675bff70cc8abcdadChristopher Wiley                                brillo::ErrorPtr* /* error */) {
8280663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  request_data_stream_ = std::move(stream);
83f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  return true;
84f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
85f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
862eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullockvoid Connection::SetResponseData(StreamPtr stream) {
872eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock  response_data_stream_ = std::move(stream);
882eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock}
892eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock
90f95a2b9e277726d8793a5849ec6e81c038c22be3Alex Vakulenkovoid Connection::PrepareRequest() {
91f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  if (VLOG_IS_ON(3)) {
9205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    curl_interface_->EasySetOptCallback(
9305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko        curl_handle_, CURLOPT_DEBUGFUNCTION, &curl_trace);
94f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    curl_interface_->EasySetOptInt(curl_handle_, CURLOPT_VERBOSE, 1);
95f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  }
96f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
9706bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko  if (method_ != request_type::kGet) {
9806bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko    // Set up HTTP request data.
9906bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko    uint64_t data_size = 0;
10006bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko    if (request_data_stream_ && request_data_stream_->CanGetSize())
10106bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko        data_size = request_data_stream_->GetRemainingSize();
10206bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko
10306bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko    if (!request_data_stream_ || request_data_stream_->CanGetSize()) {
10406bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko      // Data size is known (either no data, or data size is available).
10506bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko      if (method_ == request_type::kPut) {
10606bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko        curl_interface_->EasySetOptOffT(
10706bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko            curl_handle_, CURLOPT_INFILESIZE_LARGE, data_size);
10806bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko      } else {
10906bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko        curl_interface_->EasySetOptOffT(
11006bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko            curl_handle_, CURLOPT_POSTFIELDSIZE_LARGE, data_size);
11106bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko      }
11206bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko    } else {
11306bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko      // Data size is unknown, so use chunked upload.
11406bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko      headers_.emplace(http::request_header::kTransferEncoding, "chunked");
11506bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko    }
11606bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko
11706bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko    if (request_data_stream_) {
11806bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko      curl_interface_->EasySetOptCallback(
11906bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko          curl_handle_, CURLOPT_READFUNCTION, &Connection::read_callback);
12006bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko      curl_interface_->EasySetOptPtr(curl_handle_, CURLOPT_READDATA, this);
12106bacd3c7b6c4c569a6e7a4c687e48c976f8ed0cAlex Vakulenko    }
122f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  }
123f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
124f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  if (!headers_.empty()) {
125f95a2b9e277726d8793a5849ec6e81c038c22be3Alex Vakulenko    CHECK(header_list_ == nullptr);
126f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    for (auto pair : headers_) {
127f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko      std::string header =
1289ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko          brillo::string_utils::Join(": ", pair.first, pair.second);
129f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko      VLOG(2) << "Request header: " << header;
130f95a2b9e277726d8793a5849ec6e81c038c22be3Alex Vakulenko      header_list_ = curl_slist_append(header_list_, header.c_str());
131f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    }
13205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    curl_interface_->EasySetOptPtr(
13305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko        curl_handle_, CURLOPT_HTTPHEADER, header_list_);
134f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  }
135f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
136f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  headers_.clear();
137f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
138f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  // Set up HTTP response data.
1392eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock  if (!response_data_stream_)
1402eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock    response_data_stream_ = MemoryStream::Create(nullptr);
141f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  if (method_ != request_type::kHead) {
14205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    curl_interface_->EasySetOptCallback(
14305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko        curl_handle_, CURLOPT_WRITEFUNCTION, &Connection::write_callback);
144f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko    curl_interface_->EasySetOptPtr(curl_handle_, CURLOPT_WRITEDATA, this);
145f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  }
146f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
147f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  // HTTP response headers
14805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  curl_interface_->EasySetOptCallback(
14905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      curl_handle_, CURLOPT_HEADERFUNCTION, &Connection::header_callback);
150f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  curl_interface_->EasySetOptPtr(curl_handle_, CURLOPT_HEADERDATA, this);
151f95a2b9e277726d8793a5849ec6e81c038c22be3Alex Vakulenko}
152f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
1539ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkobool Connection::FinishRequest(brillo::ErrorPtr* error) {
154f95a2b9e277726d8793a5849ec6e81c038c22be3Alex Vakulenko  PrepareRequest();
155f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  CURLcode ret = curl_interface_->EasyPerform(curl_handle_);
156f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  if (ret != CURLE_OK) {
157aa7d677661213b4116adc5fac88b8c37a1490010Alex Vakulenko    Transport::AddEasyCurlError(error, FROM_HERE, ret, curl_interface_.get());
158f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  } else {
15920d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko    // Rewind our data stream to the beginning so that it can be read back.
1602eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock    if (response_data_stream_->CanSeek() &&
1612eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock        !response_data_stream_->SetPosition(0, error))
16220d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko      return false;
163f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    LOG(INFO) << "Response: " << GetResponseStatusCode() << " ("
16405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko              << GetResponseStatusText() << ")";
165f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  }
166f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  return (ret == CURLE_OK);
167f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
168f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
1698757d061cd87578b5b158e8efcc8a6cf4715c7a1Alex VakulenkoRequestID Connection::FinishRequestAsync(
1708757d061cd87578b5b158e8efcc8a6cf4715c7a1Alex Vakulenko    const SuccessCallback& success_callback,
1718757d061cd87578b5b158e8efcc8a6cf4715c7a1Alex Vakulenko    const ErrorCallback& error_callback) {
172f95a2b9e277726d8793a5849ec6e81c038c22be3Alex Vakulenko  PrepareRequest();
173ac3059d5edad2af5a75184d1e31133e712c91f60Alex Vakulenko  return transport_->StartAsyncTransfer(this, success_callback, error_callback);
174f95a2b9e277726d8793a5849ec6e81c038c22be3Alex Vakulenko}
175f95a2b9e277726d8793a5849ec6e81c038c22be3Alex Vakulenko
176f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenkoint Connection::GetResponseStatusCode() const {
177f5effe9e46e479e6fdc4f6928da545d48dcd3997Alex Vakulenko  int status_code = 0;
17805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  curl_interface_->EasyGetInfoInt(
17905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      curl_handle_, CURLINFO_RESPONSE_CODE, &status_code);
180f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  return status_code;
181f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
182f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
183f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenkostd::string Connection::GetResponseStatusText() const {
184f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  return status_text_;
185f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
186f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
187f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenkostd::string Connection::GetProtocolVersion() const {
188f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  return protocol_version_;
189f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
190f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
191f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenkostd::string Connection::GetResponseHeader(
192f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    const std::string& header_name) const {
193f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  auto p = headers_.find(header_name);
194f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  return p != headers_.end() ? p->second : std::string();
195f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
196f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
1979ed0cab99f18acb3570a35e9408f24355f6b8324Alex VakulenkoStreamPtr Connection::ExtractDataStream(brillo::ErrorPtr* error) {
1982eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock  if (!response_data_stream_) {
19920d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko    stream_utils::ErrorStreamClosed(FROM_HERE, error);
20020d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko  }
2012eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock  return std::move(response_data_stream_);
202f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
203f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
20405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenkosize_t Connection::write_callback(char* ptr,
20505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                  size_t size,
20605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                  size_t num,
20705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                  void* data) {
208f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  Connection* me = reinterpret_cast<Connection*>(data);
209f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  size_t data_len = size * num;
210d4c955c70812b91796ace5cfecfa181f62f6a348Alex Vakulenko  VLOG(1) << "Response data (" << data_len << "): "
21120d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko          << std::string{ptr, data_len};
2122eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock  // TODO(nathanbullock): Currently we are relying on the stream not blocking,
2132eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock  // but if the stream is representing a pipe or some other construct that might
2142eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock  // block then this code will behave badly.
2152eed2f9a423b8e776b4d54530c567736c371ba48Nathan Bullock  if (!me->response_data_stream_->WriteAllBlocking(ptr, data_len, nullptr)) {
21620d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko    LOG(ERROR) << "Failed to write response data";
21720d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko    data_len = 0;
21820d497f58d7abdec1e011cb1efadb45e53e5af0bAlex Vakulenko  }
219f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  return data_len;
220f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
221f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
22205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenkosize_t Connection::read_callback(char* ptr,
22305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                 size_t size,
22405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                 size_t num,
22505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                 void* data) {
226f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  Connection* me = reinterpret_cast<Connection*>(data);
227f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  size_t data_len = size * num;
228f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
22947e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  size_t read_size = 0;
23080663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko  bool success = me->request_data_stream_->ReadBlocking(ptr, data_len,
23180663bf89f5ba2c0646f196371a1fa92123855c6Alex Vakulenko                                                        &read_size, nullptr);
23247e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  VLOG_IF(3, success) << "Sending data: " << std::string{ptr, read_size};
23347e9a9dd3dce9d197820ee4241135e6859f95360Alex Vakulenko  return success ? read_size : CURL_READFUNC_ABORT;
234f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
235f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
23605d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenkosize_t Connection::header_callback(char* ptr,
23705d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                   size_t size,
23805d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                   size_t num,
23905d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                                   void* data) {
2409ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  using brillo::string_utils::SplitAtFirst;
241f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  Connection* me = reinterpret_cast<Connection*>(data);
242f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  size_t hdr_len = size * num;
243f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  std::string header(ptr, hdr_len);
244f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  // Remove newlines at the end of header line.
245f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  while (!header.empty() && (header.back() == '\r' || header.back() == '\n')) {
246f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    header.pop_back();
247f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  }
248f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
249f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  VLOG(2) << "Response header: " << header;
250f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
251f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  if (!me->status_text_set_) {
252f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    // First header - response code as "HTTP/1.1 200 OK".
253f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    // Need to extract the OK part
254852ff001e232f6fcc2bddd10d97c609d7461cda2Vitaly Buka    auto pair = SplitAtFirst(header, " ");
255f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    me->protocol_version_ = pair.first;
256852ff001e232f6fcc2bddd10d97c609d7461cda2Vitaly Buka    me->status_text_ = SplitAtFirst(pair.second, " ").second;
257f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    me->status_text_set_ = true;
258f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  } else {
259852ff001e232f6fcc2bddd10d97c609d7461cda2Vitaly Buka    auto pair = SplitAtFirst(header, ":");
260f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko    if (!pair.second.empty())
261f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko      me->headers_.insert(pair);
262f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  }
263f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko  return hdr_len;
264f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}
265f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko
266f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}  // namespace curl
267f788c95c111d0dccff735b8e02939e4e95ee2f5dAlex Vakulenko}  // namespace http
2689ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko}  // namespace brillo
269