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