]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/lib/php/lib/Transport/TCurlClient.php
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / thrift / lib / php / lib / Transport / TCurlClient.php
1 <?php
2 /*
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 * @package thrift.transport
21 */
22
23 namespace Thrift\Transport;
24
25 use Thrift\Exception\TTransportException;
26 use Thrift\Factory\TStringFuncFactory;
27
28 /**
29 * HTTP client for Thrift
30 *
31 * @package thrift.transport
32 */
33 class TCurlClient extends TTransport
34 {
35 private static $curlHandle;
36
37 /**
38 * The host to connect to
39 *
40 * @var string
41 */
42 protected $host_;
43
44 /**
45 * The port to connect on
46 *
47 * @var int
48 */
49 protected $port_;
50
51 /**
52 * The URI to request
53 *
54 * @var string
55 */
56 protected $uri_;
57
58 /**
59 * The scheme to use for the request, i.e. http, https
60 *
61 * @var string
62 */
63 protected $scheme_;
64
65 /**
66 * Buffer for the HTTP request data
67 *
68 * @var string
69 */
70 protected $request_;
71
72 /**
73 * Buffer for the HTTP response data.
74 *
75 * @var binary string
76 */
77 protected $response_;
78
79 /**
80 * Read timeout
81 *
82 * @var float
83 */
84 protected $timeout_;
85
86 /**
87 * http headers
88 *
89 * @var array
90 */
91 protected $headers_;
92
93 /**
94 * Make a new HTTP client.
95 *
96 * @param string $host
97 * @param int $port
98 * @param string $uri
99 */
100 public function __construct($host, $port = 80, $uri = '', $scheme = 'http')
101 {
102 if ((TStringFuncFactory::create()->strlen($uri) > 0) && ($uri{0} != '/')) {
103 $uri = '/' . $uri;
104 }
105 $this->scheme_ = $scheme;
106 $this->host_ = $host;
107 $this->port_ = $port;
108 $this->uri_ = $uri;
109 $this->request_ = '';
110 $this->response_ = null;
111 $this->timeout_ = null;
112 $this->headers_ = array();
113 }
114
115 /**
116 * Set read timeout
117 *
118 * @param float $timeout
119 */
120 public function setTimeoutSecs($timeout)
121 {
122 $this->timeout_ = $timeout;
123 }
124
125 /**
126 * Whether this transport is open.
127 *
128 * @return boolean true if open
129 */
130 public function isOpen()
131 {
132 return true;
133 }
134
135 /**
136 * Open the transport for reading/writing
137 *
138 * @throws TTransportException if cannot open
139 */
140 public function open()
141 {
142 }
143
144 /**
145 * Close the transport.
146 */
147 public function close()
148 {
149 $this->request_ = '';
150 $this->response_ = null;
151 }
152
153 /**
154 * Read some data into the array.
155 *
156 * @param int $len How much to read
157 * @return string The data that has been read
158 * @throws TTransportException if cannot read any more data
159 */
160 public function read($len)
161 {
162 if ($len >= strlen($this->response_)) {
163 return $this->response_;
164 } else {
165 $ret = substr($this->response_, 0, $len);
166 $this->response_ = substr($this->response_, $len);
167
168 return $ret;
169 }
170 }
171
172 /**
173 * Guarantees that the full amount of data is read. Since TCurlClient gets entire payload at
174 * once, parent readAll cannot be used.
175 *
176 * @return string The data, of exact length
177 * @throws TTransportException if cannot read data
178 */
179 public function readAll($len)
180 {
181 $data = $this->read($len);
182
183 if (TStringFuncFactory::create()->strlen($data) !== $len) {
184 throw new TTransportException('TCurlClient could not read '.$len.' bytes');
185 }
186
187 return $data;
188 }
189
190 /**
191 * Writes some data into the pending buffer
192 *
193 * @param string $buf The data to write
194 * @throws TTransportException if writing fails
195 */
196 public function write($buf)
197 {
198 $this->request_ .= $buf;
199 }
200
201 /**
202 * Opens and sends the actual request over the HTTP connection
203 *
204 * @throws TTransportException if a writing error occurs
205 */
206 public function flush()
207 {
208 if (!self::$curlHandle) {
209 register_shutdown_function(array('Thrift\\Transport\\TCurlClient', 'closeCurlHandle'));
210 self::$curlHandle = curl_init();
211 curl_setopt(self::$curlHandle, CURLOPT_RETURNTRANSFER, true);
212 curl_setopt(self::$curlHandle, CURLOPT_BINARYTRANSFER, true);
213 curl_setopt(self::$curlHandle, CURLOPT_USERAGENT, 'PHP/TCurlClient');
214 curl_setopt(self::$curlHandle, CURLOPT_CUSTOMREQUEST, 'POST');
215 curl_setopt(self::$curlHandle, CURLOPT_FOLLOWLOCATION, true);
216 curl_setopt(self::$curlHandle, CURLOPT_MAXREDIRS, 1);
217 }
218 // God, PHP really has some esoteric ways of doing simple things.
219 $host = $this->host_ . ($this->port_ != 80 ? ':' . $this->port_ : '');
220 $fullUrl = $this->scheme_ . "://" . $host . $this->uri_;
221
222 $headers = array();
223 $defaultHeaders = array('Accept' => 'application/x-thrift',
224 'Content-Type' => 'application/x-thrift',
225 'Content-Length' => TStringFuncFactory::create()->strlen($this->request_));
226 foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) {
227 $headers[] = "$key: $value";
228 }
229
230 curl_setopt(self::$curlHandle, CURLOPT_HTTPHEADER, $headers);
231
232 if ($this->timeout_ > 0) {
233 if ($this->timeout_ < 1.0) {
234 // Timestamps smaller than 1 second are ignored when CURLOPT_TIMEOUT is used
235 curl_setopt(self::$curlHandle, CURLOPT_TIMEOUT_MS, 1000 * $this->timeout_);
236 } else {
237 curl_setopt(self::$curlHandle, CURLOPT_TIMEOUT, $this->timeout_);
238 }
239 }
240 curl_setopt(self::$curlHandle, CURLOPT_POSTFIELDS, $this->request_);
241 $this->request_ = '';
242
243 curl_setopt(self::$curlHandle, CURLOPT_URL, $fullUrl);
244 $this->response_ = curl_exec(self::$curlHandle);
245 $responseError = curl_error(self::$curlHandle);
246
247 $code = curl_getinfo(self::$curlHandle, CURLINFO_HTTP_CODE);
248
249 // Handle non 200 status code / connect failure
250 if ($this->response_ === false || $code !== 200) {
251 curl_close(self::$curlHandle);
252 self::$curlHandle = null;
253 $this->response_ = null;
254 $error = 'TCurlClient: Could not connect to ' . $fullUrl;
255 if ($responseError) {
256 $error .= ', ' . $responseError;
257 }
258 if ($code) {
259 $error .= ', HTTP status code: ' . $code;
260 }
261 throw new TTransportException($error, TTransportException::UNKNOWN);
262 }
263 }
264
265 public static function closeCurlHandle()
266 {
267 try {
268 if (self::$curlHandle) {
269 curl_close(self::$curlHandle);
270 self::$curlHandle = null;
271 }
272 } catch (\Exception $x) {
273 error_log('There was an error closing the curl handle: ' . $x->getMessage());
274 }
275 }
276
277 public function addHeaders($headers)
278 {
279 $this->headers_ = array_merge($this->headers_, $headers);
280 }
281 }