proxygen
CurlClient.cpp
Go to the documentation of this file.
1 #include "CurlClient.h"
2 
3 #include <iostream>
4 #include <fstream>
5 
6 #include <folly/FileUtil.h>
7 #include <folly/String.h>
14 
15 using namespace folly;
16 using namespace proxygen;
17 using namespace std;
18 
19 DECLARE_int32(recv_window);
20 
21 namespace CurlService {
22 
23 CurlClient::CurlClient(EventBase* evb,
24  HTTPMethod httpMethod,
25  const URL& url,
26  const proxygen::URL* proxy,
27  const HTTPHeaders& headers,
28  const string& inputFilename,
29  bool h2c,
30  unsigned short httpMajor,
31  unsigned short httpMinor)
32  : evb_(evb),
33  httpMethod_(httpMethod),
34  url_(url),
35  inputFilename_(inputFilename),
36  h2c_(h2c),
37  httpMajor_(httpMajor),
38  httpMinor_(httpMinor) {
39  if (proxy != nullptr) {
40  proxy_ = std::make_unique<URL>(proxy->getUrl());
41  }
42 
43  headers.forEach([this] (const string& header, const string& val) {
44  request_.getHeaders().add(header, val);
45  });
46 }
47 
49  vector<StringPiece> headersList;
50  HTTPHeaders headers;
51  folly::split(",", headersString, headersList);
52  for (const auto& headerPair: headersList) {
53  vector<StringPiece> nv;
54  folly::split('=', headerPair, nv);
55  if (nv.size() > 0) {
56  if (nv[0].empty()) {
57  continue;
58  }
59  StringPiece value("");
60  if (nv.size() > 1) {
61  value = nv[1];
62  } // trim anything else
63  headers.add(nv[0], value);
64  }
65  }
66  return headers;
67 }
68 
69 void CurlClient::initializeSsl(const string& caPath,
70  const string& nextProtos,
71  const string& certPath,
72  const string& keyPath) {
73  sslContext_ = std::make_shared<folly::SSLContext>();
74  sslContext_->setOptions(SSL_OP_NO_COMPRESSION);
76  if (!caPath.empty()) {
77  sslContext_->loadTrustedCertificates(caPath.c_str());
78  }
79  if (!certPath.empty() && !keyPath.empty()) {
80  sslContext_->loadCertKeyPairFromFiles(certPath.c_str(), keyPath.c_str());
81  }
82  list<string> nextProtoList;
83  folly::splitTo<string>(',', nextProtos, std::inserter(nextProtoList,
84  nextProtoList.begin()));
85  sslContext_->setAdvertisedNextProtocols(nextProtoList);
86  h2c_ = false;
87 }
88 
90  AsyncSSLSocket* sslSocket = dynamic_cast<AsyncSSLSocket*>(
91  session->getTransport());
92 
93  const unsigned char* nextProto = nullptr;
94  unsigned nextProtoLength = 0;
95  sslSocket->getSelectedNextProtocol(&nextProto, &nextProtoLength);
96  if (nextProto) {
97  VLOG(1) << "Client selected next protocol " <<
98  string((const char*)nextProto, nextProtoLength);
99  } else {
100  VLOG(1) << "Client did not select a next protocol";
101  }
102 
103  // Note: This ssl session can be used by defining a member and setting
104  // something like sslSession_ = sslSocket->getSSLSession() and then
105  // passing it to the connector::connectSSL() method
106 }
107 
109  recvWindow_ = recvWindow;
110 }
111 
113 
114  if (url_.isSecure()) {
115  sslHandshakeFollowup(session);
116  }
117 
119  sendRequest(session->newTransaction(this));
120  session->closeWhenIdle();
121 }
122 
124  txn_ = txn;
127  if (proxy_) {
129  } else {
131  }
133  if (h2c_) {
134  HTTP2Codec::requestUpgrade(request_);
135  }
136 
138  request_.getHeaders().add(HTTP_HEADER_USER_AGENT, "proxygen_curl");
139  }
142  }
144  request_.getHeaders().add("Accept", "*/*");
145  }
146  if (loggingEnabled_) {
148  }
149 
151 
152  unique_ptr<IOBuf> buf;
153  if (httpMethod_ == HTTPMethod::POST) {
154 
155  const uint16_t kReadSize = 4096;
156  ifstream inputFile(inputFilename_, ios::in | ios::binary);
157 
158  // Reading from the file by chunks
159  // Important note: It's pretty bad to call a blocking i/o function like
160  // ifstream::read() in an eventloop - but for the sake of this simple
161  // example, we'll do it.
162  // An alternative would be to put this into some folly::AsyncReader
163  // object.
164  while (inputFile.good()) {
165  buf = IOBuf::createCombined(kReadSize);
166  inputFile.read((char*)buf->writableData(), kReadSize);
167  buf->append(inputFile.gcount());
168  txn_->sendBody(move(buf));
169  }
170  }
171 
172  // note that sendBody() is called only for POST. It's fine not to call it
173  // at all.
174 
175  txn_->sendEOM();
176 }
177 
179  LOG_IF(ERROR, loggingEnabled_) << "Coudln't connect to "
180  << url_.getHostAndPort() << ":" << ex.what();
181 }
182 
184 }
185 
187 }
188 
189 void CurlClient::onHeadersComplete(unique_ptr<HTTPMessage> msg) noexcept {
190  response_ = std::move(msg);
191  if (!loggingEnabled_) {
192  return;
193  }
194  cout << response_->getStatusCode() << " "
195  << response_->getStatusMessage() << endl;
196  response_->getHeaders().forEach([&](const string& header, const string& val) {
197  cout << header << ": " << val << endl;
198  });
199 }
200 
201 void CurlClient::onBody(std::unique_ptr<folly::IOBuf> chain) noexcept {
202  if (!loggingEnabled_) {
203  return;
204  }
205  if (chain) {
206  const IOBuf* p = chain.get();
207  do {
208  cout.write((const char*)p->data(), p->length());
209  cout.flush();
210  p = p->next();
211  } while (p != chain.get());
212  }
213 }
214 
215 void CurlClient::onTrailers(std::unique_ptr<HTTPHeaders>) noexcept {
216  LOG_IF(INFO, loggingEnabled_) << "Discarding trailers";
217 }
218 
220  LOG_IF(INFO, loggingEnabled_) << "Got EOM";
221 }
222 
224  LOG_IF(INFO, loggingEnabled_) << "Discarding upgrade protocol";
225 }
226 
228  LOG_IF(ERROR, loggingEnabled_) << "An error occurred: " << error.what();
229 }
230 
232  LOG_IF(INFO, loggingEnabled_) << "Egress paused";
233 }
234 
236  LOG_IF(INFO, loggingEnabled_) << "Egress resumed";
237 }
238 
239 const string& CurlClient::getServerName() const {
240  const string& res = request_.getHeaders().getSingleOrEmpty(HTTP_HEADER_HOST);
241  if (res.empty()) {
242  return url_.getHost();
243  }
244  return res;
245 }
246 
247 } // namespace CurlService
static proxygen::HTTPHeaders parseHeaders(const std::string &headersString)
Definition: CurlClient.cpp:48
folly::SSLContextPtr sslContext_
Definition: CurlClient.h:88
void onEgressResumed() noexceptoverride
Definition: CurlClient.cpp:235
proxygen::URL url_
Definition: CurlClient.h:84
const std::string & getHost() const noexcept
Definition: URL.h:118
HTTPTransaction * newTransaction(HTTPTransaction::Handler *handler) override
std::string makeRelativeURL() const noexcept
Definition: URL.h:138
const std::string inputFilename_
Definition: CurlClient.h:87
void onError(const proxygen::HTTPException &error) noexceptoverride
Definition: CurlClient.cpp:227
void detachTransaction() noexceptoverride
Definition: CurlClient.cpp:186
void setFlowControlSettings(int32_t recvWindow)
Definition: CurlClient.cpp:108
unsigned short httpMajor_
Definition: CurlClient.h:92
std::unique_ptr< proxygen::HTTPMessage > response_
Definition: CurlClient.h:95
void onEgressPaused() noexceptoverride
Definition: CurlClient.cpp:231
proxygen::HTTPMethod httpMethod_
Definition: CurlClient.h:83
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
STL namespace.
double val
Definition: String.cpp:273
const uint8_t * data() const
Definition: IOBuf.h:499
const std::string & getUrl() const noexcept
Definition: URL.h:98
size_t getNumberOfValues(HTTPHeaderCode code) const
void connectSuccess(proxygen::HTTPUpstreamSession *session) override
Definition: CurlClient.cpp:112
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
void onUpgrade(proxygen::UpgradeProtocol protocol) noexceptoverride
Definition: CurlClient.cpp:223
void onTrailers(std::unique_ptr< proxygen::HTTPHeaders > trailers) noexceptoverride
Definition: CurlClient.cpp:215
requires E e noexcept(noexcept(s.error(std::move(e))))
requires And< SemiMovable< VN >... > &&SemiMovable< E > auto error(E e)
Definition: error.h:48
void split(const Delim &delimiter, const String &input, std::vector< OutputType > &out, bool ignoreEmpty)
Definition: String-inl.h:382
std::string getHostAndPort() const noexcept
Definition: URL.h:122
void sslHandshakeFollowup(proxygen::HTTPUpstreamSession *session) noexcept
Definition: CurlClient.cpp:89
void connectError(const folly::AsyncSocketException &ex) override
Definition: CurlClient.cpp:178
void setSecure(bool secure)
Definition: HTTPMessage.h:534
constexpr auto empty(C const &c) -> decltype(c.empty())
Definition: Access.h:55
ParseURL setURL(T &&url)
Definition: HTTPMessage.h:183
EventBase * evb_
void setTransaction(proxygen::HTTPTransaction *txn) noexceptoverride
Definition: CurlClient.cpp:183
uint8_t * writableData()
Definition: IOBuf.h:509
void setFlowControl(size_t initialReceiveWindow, size_t receiveStreamWindowSize, size_t receiveSessionWindowSize) override
void onBody(std::unique_ptr< folly::IOBuf > chain) noexceptoverride
Definition: CurlClient.cpp:201
std::size_t length() const
Definition: IOBuf.h:533
static constexpr auto kCipherList
Definition: SSLOptions.h:33
proxygen::HTTPTransaction * txn_
Definition: CurlClient.h:81
void forEach(LAMBDA func) const
Definition: HTTPHeaders.h:337
virtual void sendBody(std::unique_ptr< folly::IOBuf > body)
virtual void sendHeaders(const HTTPMessage &headers)
static const char *const value
Definition: Conv.cpp:50
IOBuf * next()
Definition: IOBuf.h:600
HTTPHeaders & getHeaders()
Definition: HTTPMessage.h:273
DECLARE_int32(recv_window)
const std::string & getSingleOrEmpty(const T &nameOrCode) const
Definition: HTTPHeaders.h:420
void setMethod(HTTPMethod method)
void onEOM() noexceptoverride
Definition: CurlClient.cpp:219
bool isSecure() const noexcept
Definition: URL.h:110
const std::string & getServerName() const
Definition: CurlClient.cpp:239
const char * string
Definition: Conv.cpp:212
void setHTTPVersion(uint8_t major, uint8_t minor)
void initializeSsl(const std::string &caPath, const std::string &nextProtos, const std::string &certPath="", const std::string &keyPath="")
Definition: CurlClient.cpp:69
void add(folly::StringPiece name, folly::StringPiece value)
Definition: HTTPHeaders.cpp:52
void closeWhenIdle() override
std::unique_ptr< proxygen::URL > proxy_
Definition: CurlClient.h:85
void onHeadersComplete(std::unique_ptr< proxygen::HTTPMessage > msg) noexceptoverride
Definition: CurlClient.cpp:189
void sendRequest(proxygen::HTTPTransaction *txn)
Definition: CurlClient.cpp:123
void dumpMessage(int verbosity) const
proxygen::HTTPMessage request_
Definition: CurlClient.h:86
void append(std::size_t amount)
Definition: IOBuf.h:689
unsigned short httpMinor_
Definition: CurlClient.h:93
virtual void getSelectedNextProtocol(const unsigned char **protoName, unsigned *protoLen) const