blob: 4d6be32fed23cef496fc6c59bd7b606e54a70237 [file] [log] [blame]
Roger Meier21c0a852012-09-05 19:47:14 +00001<?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
23namespace Thrift\Transport;
24
Roger Meier21c0a852012-09-05 19:47:14 +000025use Thrift\Exception\TTransportException;
26use Thrift\Factory\TStringFuncFactory;
27
28/**
29 * HTTP client for Thrift
30 *
31 * @package thrift.transport
32 */
Roger Thomas6fb59232014-11-04 10:09:23 +000033class THttpClient extends TTransport
34{
Robert Lub03ca012018-01-18 19:06:39 +080035 /**
36 * The host to connect to
37 *
38 * @var string
39 */
40 protected $host_;
Roger Meier21c0a852012-09-05 19:47:14 +000041
Robert Lub03ca012018-01-18 19:06:39 +080042 /**
43 * The port to connect on
44 *
45 * @var int
46 */
47 protected $port_;
Roger Meier21c0a852012-09-05 19:47:14 +000048
Robert Lub03ca012018-01-18 19:06:39 +080049 /**
50 * The URI to request
51 *
52 * @var string
53 */
54 protected $uri_;
Roger Meier21c0a852012-09-05 19:47:14 +000055
Robert Lub03ca012018-01-18 19:06:39 +080056 /**
57 * The scheme to use for the request, i.e. http, https
58 *
59 * @var string
60 */
61 protected $scheme_;
Roger Meier21c0a852012-09-05 19:47:14 +000062
Robert Lub03ca012018-01-18 19:06:39 +080063 /**
64 * Buffer for the HTTP request data
65 *
66 * @var string
67 */
68 protected $buf_;
Roger Meier21c0a852012-09-05 19:47:14 +000069
Robert Lub03ca012018-01-18 19:06:39 +080070 /**
71 * Input socket stream.
72 *
73 * @var resource
74 */
75 protected $handle_;
Roger Meier21c0a852012-09-05 19:47:14 +000076
Robert Lub03ca012018-01-18 19:06:39 +080077 /**
78 * Read timeout
79 *
80 * @var float
81 */
82 protected $timeout_;
Roger Meier21c0a852012-09-05 19:47:14 +000083
Robert Lub03ca012018-01-18 19:06:39 +080084 /**
85 * http headers
86 *
87 * @var array
88 */
89 protected $headers_;
Roger Meier1f9717d2013-03-23 16:03:38 +010090
Robert Lub03ca012018-01-18 19:06:39 +080091 /**
Efimov Evgenij7f0fa6c2018-11-23 10:57:42 +030092 * Context additional options
93 *
94 * @var array
95 */
96 protected $context_;
97
98 /**
Robert Lub03ca012018-01-18 19:06:39 +080099 * Make a new HTTP client.
100 *
101 * @param string $host
Efimov Evgenij7f0fa6c2018-11-23 10:57:42 +0300102 * @param int $port
Robert Lub03ca012018-01-18 19:06:39 +0800103 * @param string $uri
Efimov Evgenij7f0fa6c2018-11-23 10:57:42 +0300104 * @param string $scheme
105 * @param array $context
Robert Lub03ca012018-01-18 19:06:39 +0800106 */
Efimov Evgenij7f0fa6c2018-11-23 10:57:42 +0300107 public function __construct($host, $port = 80, $uri = '', $scheme = 'http', array $context = array())
Robert Lub03ca012018-01-18 19:06:39 +0800108 {
Stoyan Markov44b0b5d2020-09-04 12:49:38 +0200109 if ((TStringFuncFactory::create()->strlen($uri) > 0) && ($uri[0] != '/')) {
Robert Lub03ca012018-01-18 19:06:39 +0800110 $uri = '/' . $uri;
111 }
112 $this->scheme_ = $scheme;
113 $this->host_ = $host;
114 $this->port_ = $port;
115 $this->uri_ = $uri;
116 $this->buf_ = '';
117 $this->handle_ = null;
118 $this->timeout_ = null;
119 $this->headers_ = array();
Efimov Evgenij7f0fa6c2018-11-23 10:57:42 +0300120 $this->context_ = $context;
Roger Meier21c0a852012-09-05 19:47:14 +0000121 }
Roger Thomas6fb59232014-11-04 10:09:23 +0000122
Robert Lub03ca012018-01-18 19:06:39 +0800123 /**
124 * Set read timeout
125 *
126 * @param float $timeout
127 */
128 public function setTimeoutSecs($timeout)
129 {
130 $this->timeout_ = $timeout;
Roger Meier1f9717d2013-03-23 16:03:38 +0100131 }
Roger Meier21c0a852012-09-05 19:47:14 +0000132
Robert Lub03ca012018-01-18 19:06:39 +0800133 /**
134 * Whether this transport is open.
135 *
136 * @return boolean true if open
137 */
138 public function isOpen()
139 {
140 return true;
Roger Meier21c0a852012-09-05 19:47:14 +0000141 }
Roger Meier21c0a852012-09-05 19:47:14 +0000142
Robert Lub03ca012018-01-18 19:06:39 +0800143 /**
144 * Open the transport for reading/writing
145 *
146 * @throws TTransportException if cannot open
147 */
148 public function open()
149 {
Roger Meier21c0a852012-09-05 19:47:14 +0000150 }
Roger Meier21c0a852012-09-05 19:47:14 +0000151
Robert Lub03ca012018-01-18 19:06:39 +0800152 /**
153 * Close the transport.
154 */
155 public function close()
156 {
157 if ($this->handle_) {
158 @fclose($this->handle_);
159 $this->handle_ = null;
160 }
161 }
Roger Meier1f9717d2013-03-23 16:03:38 +0100162
Robert Lub03ca012018-01-18 19:06:39 +0800163 /**
164 * Read some data into the array.
165 *
166 * @param int $len How much to read
167 * @return string The data that has been read
168 * @throws TTransportException if cannot read any more data
169 */
170 public function read($len)
171 {
172 $data = @fread($this->handle_, $len);
173 if ($data === false || $data === '') {
174 $md = stream_get_meta_data($this->handle_);
175 if ($md['timed_out']) {
176 throw new TTransportException(
177 'THttpClient: timed out reading ' . $len . ' bytes from ' .
178 $this->host_ . ':' . $this->port_ . $this->uri_,
179 TTransportException::TIMED_OUT
180 );
181 } else {
182 throw new TTransportException(
183 'THttpClient: Could not read ' . $len . ' bytes from ' .
184 $this->host_ . ':' . $this->port_ . $this->uri_,
185 TTransportException::UNKNOWN
186 );
187 }
188 }
189
190 return $data;
191 }
192
193 /**
194 * Writes some data into the pending buffer
195 *
196 * @param string $buf The data to write
197 * @throws TTransportException if writing fails
198 */
199 public function write($buf)
200 {
201 $this->buf_ .= $buf;
202 }
203
204 /**
205 * Opens and sends the actual request over the HTTP connection
206 *
207 * @throws TTransportException if a writing error occurs
208 */
209 public function flush()
210 {
211 // God, PHP really has some esoteric ways of doing simple things.
212 $host = $this->host_ . ($this->port_ != 80 ? ':' . $this->port_ : '');
213
214 $headers = array();
215 $defaultHeaders = array('Host' => $host,
216 'Accept' => 'application/x-thrift',
217 'User-Agent' => 'PHP/THttpClient',
218 'Content-Type' => 'application/x-thrift',
219 'Content-Length' => TStringFuncFactory::create()->strlen($this->buf_));
220 foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) {
221 $headers[] = "$key: $value";
222 }
223
Efimov Evgenij7f0fa6c2018-11-23 10:57:42 +0300224 $options = $this->context_;
225
226 $baseHttpOptions = isset($options["http"]) ? $options["http"] : array();
227
228 $httpOptions = $baseHttpOptions + array('method' => 'POST',
Robert Lub03ca012018-01-18 19:06:39 +0800229 'header' => implode("\r\n", $headers),
230 'max_redirects' => 1,
231 'content' => $this->buf_);
232 if ($this->timeout_ > 0) {
Efimov Evgenij7f0fa6c2018-11-23 10:57:42 +0300233 $httpOptions['timeout'] = $this->timeout_;
Robert Lub03ca012018-01-18 19:06:39 +0800234 }
235 $this->buf_ = '';
236
Efimov Evgenij7f0fa6c2018-11-23 10:57:42 +0300237 $options["http"] = $httpOptions;
238 $contextid = stream_context_create($options);
Robert Lub03ca012018-01-18 19:06:39 +0800239 $this->handle_ = @fopen(
240 $this->scheme_ . '://' . $host . $this->uri_,
241 'r',
242 false,
243 $contextid
244 );
245
246 // Connect failed?
247 if ($this->handle_ === false) {
248 $this->handle_ = null;
249 $error = 'THttpClient: Could not connect to ' . $host . $this->uri_;
250 throw new TTransportException($error, TTransportException::NOT_OPEN);
251 }
252 }
253
254 public function addHeaders($headers)
255 {
256 $this->headers_ = array_merge($this->headers_, $headers);
257 }
Roger Meier21c0a852012-09-05 19:47:14 +0000258}