]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/lib/cpp/src/thrift/transport/THttpTransport.cpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / jaegertracing / thrift / lib / cpp / src / thrift / transport / THttpTransport.cpp
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 <sstream>
21
22 #include <thrift/transport/THttpTransport.h>
23
24 using std::string;
25
26 namespace apache {
27 namespace thrift {
28 namespace transport {
29
30 // Yeah, yeah, hacky to put these here, I know.
31 const char* THttpTransport::CRLF = "\r\n";
32 const int THttpTransport::CRLF_LEN = 2;
33
34 THttpTransport::THttpTransport(std::shared_ptr<TTransport> transport)
35 : transport_(transport),
36 origin_(""),
37 readHeaders_(true),
38 chunked_(false),
39 chunkedDone_(false),
40 chunkSize_(0),
41 contentLength_(0),
42 httpBuf_(nullptr),
43 httpPos_(0),
44 httpBufLen_(0),
45 httpBufSize_(1024) {
46 init();
47 }
48
49 void THttpTransport::init() {
50 httpBuf_ = (char*)std::malloc(httpBufSize_ + 1);
51 if (httpBuf_ == nullptr) {
52 throw std::bad_alloc();
53 }
54 httpBuf_[httpBufLen_] = '\0';
55 }
56
57 THttpTransport::~THttpTransport() {
58 if (httpBuf_ != nullptr) {
59 std::free(httpBuf_);
60 }
61 }
62
63 uint32_t THttpTransport::read(uint8_t* buf, uint32_t len) {
64 if (readBuffer_.available_read() == 0) {
65 readBuffer_.resetBuffer();
66 uint32_t got = readMoreData();
67 if (got == 0) {
68 return 0;
69 }
70 }
71 return readBuffer_.read(buf, len);
72 }
73
74 uint32_t THttpTransport::readEnd() {
75 // Read any pending chunked data (footers etc.)
76 if (chunked_) {
77 while (!chunkedDone_) {
78 readChunked();
79 }
80 }
81 return 0;
82 }
83
84 uint32_t THttpTransport::readMoreData() {
85 uint32_t size;
86
87 if (httpPos_ == httpBufLen_) {
88 // Get more data!
89 refill();
90 }
91
92 if (readHeaders_) {
93 readHeaders();
94 }
95
96 if (chunked_) {
97 size = readChunked();
98 } else {
99 size = readContent(contentLength_);
100 readHeaders_ = true;
101 }
102
103 return size;
104 }
105
106 uint32_t THttpTransport::readChunked() {
107 uint32_t length = 0;
108
109 char* line = readLine();
110 uint32_t chunkSize = parseChunkSize(line);
111 if (chunkSize == 0) {
112 readChunkedFooters();
113 } else {
114 // Read data content
115 length += readContent(chunkSize);
116 // Read trailing CRLF after content
117 readLine();
118 }
119 return length;
120 }
121
122 void THttpTransport::readChunkedFooters() {
123 // End of data, read footer lines until a blank one appears
124 while (true) {
125 char* line = readLine();
126 if (strlen(line) == 0) {
127 chunkedDone_ = true;
128 break;
129 }
130 }
131 }
132
133 uint32_t THttpTransport::parseChunkSize(char* line) {
134 char* semi = strchr(line, ';');
135 if (semi != nullptr) {
136 *semi = '\0';
137 }
138 uint32_t size = 0;
139 sscanf(line, "%x", &size);
140 return size;
141 }
142
143 uint32_t THttpTransport::readContent(uint32_t size) {
144 uint32_t need = size;
145 while (need > 0) {
146 uint32_t avail = httpBufLen_ - httpPos_;
147 if (avail == 0) {
148 // We have given all the data, reset position to head of the buffer
149 httpPos_ = 0;
150 httpBufLen_ = 0;
151 refill();
152
153 // Now have available however much we read
154 avail = httpBufLen_;
155 }
156 uint32_t give = avail;
157 if (need < give) {
158 give = need;
159 }
160 readBuffer_.write((uint8_t*)(httpBuf_ + httpPos_), give);
161 httpPos_ += give;
162 need -= give;
163 }
164 return size;
165 }
166
167 char* THttpTransport::readLine() {
168 while (true) {
169 char* eol = nullptr;
170
171 eol = strstr(httpBuf_ + httpPos_, CRLF);
172
173 // No CRLF yet?
174 if (eol == nullptr) {
175 // Shift whatever we have now to front and refill
176 shift();
177 refill();
178 } else {
179 // Return pointer to next line
180 *eol = '\0';
181 char* line = httpBuf_ + httpPos_;
182 httpPos_ = static_cast<uint32_t>((eol - httpBuf_) + CRLF_LEN);
183 return line;
184 }
185 }
186 }
187
188 void THttpTransport::shift() {
189 if (httpBufLen_ > httpPos_) {
190 // Shift down remaining data and read more
191 uint32_t length = httpBufLen_ - httpPos_;
192 memmove(httpBuf_, httpBuf_ + httpPos_, length);
193 httpBufLen_ = length;
194 } else {
195 httpBufLen_ = 0;
196 }
197 httpPos_ = 0;
198 httpBuf_[httpBufLen_] = '\0';
199 }
200
201 void THttpTransport::refill() {
202 uint32_t avail = httpBufSize_ - httpBufLen_;
203 if (avail <= (httpBufSize_ / 4)) {
204 httpBufSize_ *= 2;
205 char* tmpBuf = (char*)std::realloc(httpBuf_, httpBufSize_ + 1);
206 if (tmpBuf == nullptr) {
207 throw std::bad_alloc();
208 }
209 httpBuf_ = tmpBuf;
210 }
211
212 // Read more data
213 uint32_t got = transport_->read((uint8_t*)(httpBuf_ + httpBufLen_), httpBufSize_ - httpBufLen_);
214 httpBufLen_ += got;
215 httpBuf_[httpBufLen_] = '\0';
216
217 if (got == 0) {
218 throw TTransportException(TTransportException::END_OF_FILE, "Could not refill buffer");
219 }
220 }
221
222 void THttpTransport::readHeaders() {
223 // Initialize headers state variables
224 contentLength_ = 0;
225 chunked_ = false;
226 chunkedDone_ = false;
227 chunkSize_ = 0;
228
229 // Control state flow
230 bool statusLine = true;
231 bool finished = false;
232
233 // Loop until headers are finished
234 while (true) {
235 char* line = readLine();
236
237 if (strlen(line) == 0) {
238 if (finished) {
239 readHeaders_ = false;
240 return;
241 } else {
242 // Must have been an HTTP 100, keep going for another status line
243 statusLine = true;
244 }
245 } else {
246 if (statusLine) {
247 statusLine = false;
248 finished = parseStatusLine(line);
249 } else {
250 parseHeader(line);
251 }
252 }
253 }
254 }
255
256 void THttpTransport::write(const uint8_t* buf, uint32_t len) {
257 writeBuffer_.write(buf, len);
258 }
259
260 const std::string THttpTransport::getOrigin() const {
261 std::ostringstream oss;
262 if (!origin_.empty()) {
263 oss << origin_ << ", ";
264 }
265 oss << transport_->getOrigin();
266 return oss.str();
267 }
268 }
269 }
270 }