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