RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
soa/service/http_rest_proxy.cc
00001 /* http_rest_proxy.cc
00002    Jeremy Barnes, 10 April 2013
00003    Copyright (c) 2013 Datacratic Inc.  All rights reserved.
00004 
00005    REST proxy class for http.
00006 */
00007 
00008 #include "http_rest_proxy.h"
00009 
00010 #include <curlpp/cURLpp.hpp>
00011 #include <curlpp/Easy.hpp>
00012 #include <curlpp/Options.hpp>
00013 #include <curlpp/Info.hpp>
00014 #include <curlpp/Infos.hpp>
00015 
00016 
00017 using namespace std;
00018 using namespace ML;
00019 
00020 
00021 namespace Datacratic {
00022 
00023 
00024 /*****************************************************************************/
00025 /* HTTP REST PROXY                                                           */
00026 /*****************************************************************************/
00027 
00028 HttpRestProxy::Response
00029 HttpRestProxy::
00030 perform(const std::string & verb,
00031         const std::string & resource,
00032         const Content & content,
00033         const RestParams & queryParams,
00034         const RestParams & headers,
00035         int timeout) const
00036 {
00037     string responseHeaders;
00038     string body;
00039 
00040     try {
00041         responseHeaders.clear();
00042         body.clear();
00043 
00044         curlpp::Easy myRequest;
00045 
00046         using namespace curlpp::options;
00047         using namespace curlpp::infos;
00048             
00049         list<string> curlHeaders;
00050         for (unsigned i = 0;  i < headers.size();  ++i) {
00051             curlHeaders.push_back(headers[i].first + ": "
00052                                   + headers[i].second);
00053         }
00054 
00055         std::string uri = serviceUri + resource + queryParams.uriEscaped();
00056 
00057         //cerr << "uri = " << uri << endl;
00058 
00059         myRequest.setOpt<CustomRequest>(verb);
00060 
00061         myRequest.setOpt<curlpp::options::Url>(uri);
00062         //myRequest.setOpt<Verbose>(true);
00063         myRequest.setOpt<ErrorBuffer>((char *)0);
00064         if (timeout != -1)
00065             myRequest.setOpt<Timeout>(timeout);
00066         myRequest.setOpt<NoSignal>(1);
00067 
00068         auto onData = [&] (char * data, size_t ofs1, size_t ofs2) -> size_t
00069             {
00070                 //cerr << "called onData for " << ofs1 << " " << ofs2 << endl;
00071                 return 0;
00072             };
00073 
00074         auto onWriteData = [&] (char * data, size_t ofs1, size_t ofs2) -> size_t
00075             {
00076                 body.append(data, ofs1 * ofs2);
00077                 return ofs1 * ofs2;
00078                 //cerr << "called onWrite for " << ofs1 << " " << ofs2 << endl;
00079                 return 0;
00080             };
00081 
00082         auto onProgress = [&] (double p1, double p2, double p3, double p4) -> int
00083             {
00084                 cerr << "progress " << p1 << " " << p2 << " " << p3 << " "
00085                 << p4 << endl;
00086                 return 0;
00087             };
00088 
00089         bool afterContinue = false;
00090 
00091         auto onHeader = [&] (char * data, size_t ofs1, size_t ofs2) -> size_t
00092             {
00093                 string headerLine(data, ofs1 * ofs2);
00094                 if (headerLine.find("HTTP/1.1 100 Continue") == 0) {
00095                     afterContinue = true;
00096                 }
00097                 else if (afterContinue) {
00098                     if (headerLine == "\r\n")
00099                         afterContinue = false;
00100                 }
00101                 else {
00102                     responseHeaders.append(headerLine);
00103                     //cerr << "got header data " << headerLine << endl;
00104                 }
00105                 return ofs1 * ofs2;
00106             };
00107 
00108         myRequest.setOpt<BoostHeaderFunction>(onHeader);
00109         myRequest.setOpt<BoostWriteFunction>(onWriteData);
00110         myRequest.setOpt<BoostProgressFunction>(onProgress);
00111         //myRequest.setOpt<Header>(true);
00112 
00113         if (content.data) {
00114             string s(content.data, content.size);
00115             myRequest.setOpt<PostFields>(s);
00116             myRequest.setOpt<PostFieldSize>(content.size);
00117             curlHeaders.push_back(ML::format("Content-Length: %lld",
00118                                              content.size));
00119             //curlHeaders.push_back("Transfer-Encoding:");
00120             curlHeaders.push_back("Content-Type: " + content.contentType);
00121         }
00122 
00123         myRequest.setOpt<curlpp::options::HttpHeader>(curlHeaders);
00124 
00125         myRequest.perform();
00126 
00127         Response response;
00128         response.body_ = body;
00129 
00130         curlpp::InfoGetter::get(myRequest, CURLINFO_RESPONSE_CODE,
00131                                 response.code_);
00132 
00133         double bytesUploaded;
00134     
00135         curlpp::InfoGetter::get(myRequest, CURLINFO_SIZE_UPLOAD,
00136                                 bytesUploaded);
00137 
00138         //cerr << "uploaded " << bytesUploaded << " bytes" << endl;
00139 
00140         response.header_.parse(responseHeaders);
00141 
00142         return response;
00143     } catch (const curlpp::LibcurlRuntimeError & exc) {
00144         cerr << "libCurl returned an error with code " << exc.whatCode()
00145              << endl;
00146         cerr << "error is " << curl_easy_strerror(exc.whatCode())
00147              << endl;
00148         //cerr << "uri is " << uri << endl;
00149         cerr << "headers are " << responseHeaders << endl;
00150         cerr << "body contains " << body.size() << " bytes" << endl;
00151         throw;
00152     }
00153 }
00154 
00155 } // namespace Datacratic
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator