1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include <limits>
21 #include <cstdlib>
22 #include <sstream>
23 #include <boost/algorithm/string.hpp>
24 
25 #include <thrift/config.h>
26 #include <thrift/transport/THttpClient.h>
27 #include <thrift/transport/TSocket.h>
28 
29 using std::string;
30 
31 namespace apache {
32 namespace thrift {
33 namespace transport {
34 
THttpClient(stdcxx::shared_ptr<TTransport> transport,std::string host,std::string path)35 THttpClient::THttpClient(stdcxx::shared_ptr<TTransport> transport,
36                          std::string host,
37                          std::string path)
38   : THttpTransport(transport), host_(host), path_(path) {
39 }
40 
THttpClient(string host,int port,string path)41 THttpClient::THttpClient(string host, int port, string path)
42   : THttpTransport(stdcxx::shared_ptr<TTransport>(new TSocket(host, port))),
43     host_(host),
44     path_(path) {
45 }
46 
~THttpClient()47 THttpClient::~THttpClient() {
48 }
49 
parseHeader(char * header)50 void THttpClient::parseHeader(char* header) {
51   char* colon = strchr(header, ':');
52   if (colon == NULL) {
53     return;
54   }
55   char* value = colon + 1;
56 
57   if (boost::istarts_with(header, "Transfer-Encoding")) {
58     if (boost::iends_with(value, "chunked")) {
59       chunked_ = true;
60     }
61   } else if (boost::istarts_with(header, "Content-Length")) {
62     chunked_ = false;
63     contentLength_ = atoi(value);
64   }
65 }
66 
parseStatusLine(char * status)67 bool THttpClient::parseStatusLine(char* status) {
68   char* http = status;
69 
70   char* code = strchr(http, ' ');
71   if (code == NULL) {
72     throw TTransportException(string("Bad Status: ") + status);
73   }
74 
75   *code = '\0';
76   while (*(code++) == ' ') {
77   };
78 
79   char* msg = strchr(code, ' ');
80   if (msg == NULL) {
81     throw TTransportException(string("Bad Status: ") + status);
82   }
83   *msg = '\0';
84 
85   if (strcmp(code, "200") == 0) {
86     // HTTP 200 = OK, we got the response
87     return true;
88   } else if (strcmp(code, "100") == 0) {
89     // HTTP 100 = continue, just keep reading
90     return false;
91   } else {
92     throw TTransportException(string("Bad Status: ") + status);
93   }
94 }
95 
flush()96 void THttpClient::flush() {
97   // Fetch the contents of the write buffer
98   uint8_t* buf;
99   uint32_t len;
100   writeBuffer_.getBuffer(&buf, &len);
101 
102   // Construct the HTTP header
103   std::ostringstream h;
104   h << "POST " << path_ << " HTTP/1.1" << CRLF << "Host: " << host_ << CRLF
105     << "Content-Type: application/x-thrift" << CRLF << "Content-Length: " << len << CRLF
106     << "Accept: application/x-thrift" << CRLF << "User-Agent: Thrift/" << PACKAGE_VERSION
107     << " (C++/THttpClient)" << CRLF << CRLF;
108   string header = h.str();
109 
110   if (header.size() > (std::numeric_limits<uint32_t>::max)())
111     throw TTransportException("Header too big");
112   // Write the header, then the data, then flush
113   transport_->write((const uint8_t*)header.c_str(), static_cast<uint32_t>(header.size()));
114   transport_->write(buf, len);
115   transport_->flush();
116 
117   // Reset the buffer and header variables
118   writeBuffer_.resetBuffer();
119   readHeaders_ = true;
120 }
121 }
122 }
123 } // apache::thrift::transport
124