THttpClient.php 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. namespace Thrift\Transport;
  23. use Thrift\Exception\TTransportException;
  24. use Thrift\Factory\TStringFuncFactory;
  25. /**
  26. * HTTP client for Thrift
  27. *
  28. * @package thrift.transport
  29. */
  30. class THttpClient extends TTransport
  31. {
  32. /**
  33. * The host to connect to
  34. *
  35. * @var string
  36. */
  37. protected $host_;
  38. /**
  39. * The port to connect on
  40. *
  41. * @var int
  42. */
  43. protected $port_;
  44. /**
  45. * The URI to request
  46. *
  47. * @var string
  48. */
  49. protected $uri_;
  50. /**
  51. * The scheme to use for the request, i.e. http, https
  52. *
  53. * @var string
  54. */
  55. protected $scheme_;
  56. /**
  57. * Buffer for the HTTP request data
  58. *
  59. * @var string
  60. */
  61. protected $buf_;
  62. /**
  63. * Input socket stream.
  64. *
  65. * @var resource
  66. */
  67. protected $handle_;
  68. /**
  69. * Read timeout
  70. *
  71. * @var float
  72. */
  73. protected $timeout_;
  74. /**
  75. * http headers
  76. *
  77. * @var array
  78. */
  79. protected $headers_;
  80. /**
  81. * Make a new HTTP client.
  82. *
  83. * @param string $host
  84. * @param int $port
  85. * @param string $uri
  86. */
  87. public function __construct($host, $port=80, $uri='', $scheme = 'http')
  88. {
  89. if ((TStringFuncFactory::create()->strlen($uri) > 0) && ($uri{0} != '/')) {
  90. $uri = '/'.$uri;
  91. }
  92. $this->scheme_ = $scheme;
  93. $this->host_ = $host;
  94. $this->port_ = $port;
  95. $this->uri_ = $uri;
  96. $this->buf_ = '';
  97. $this->handle_ = null;
  98. $this->timeout_ = null;
  99. $this->headers_ = array();
  100. }
  101. /**
  102. * Set read timeout
  103. *
  104. * @param float $timeout
  105. */
  106. public function setTimeoutSecs($timeout)
  107. {
  108. $this->timeout_ = $timeout;
  109. }
  110. /**
  111. * Whether this transport is open.
  112. *
  113. * @return boolean true if open
  114. */
  115. public function isOpen()
  116. {
  117. return true;
  118. }
  119. /**
  120. * Open the transport for reading/writing
  121. *
  122. * @throws TTransportException if cannot open
  123. */
  124. public function open() {}
  125. /**
  126. * Close the transport.
  127. */
  128. public function close()
  129. {
  130. if ($this->handle_) {
  131. @fclose($this->handle_);
  132. $this->handle_ = null;
  133. }
  134. }
  135. /**
  136. * Read some data into the array.
  137. *
  138. * @param int $len How much to read
  139. * @return string The data that has been read
  140. * @throws TTransportException if cannot read any more data
  141. */
  142. public function read($len)
  143. {
  144. $data = @fread($this->handle_, $len);
  145. if ($data === FALSE || $data === '') {
  146. $md = stream_get_meta_data($this->handle_);
  147. if ($md['timed_out']) {
  148. throw new TTransportException('THttpClient: timed out reading '.$len.' bytes from '.$this->host_.':'.$this->port_.$this->uri_, TTransportException::TIMED_OUT);
  149. } else {
  150. throw new TTransportException('THttpClient: Could not read '.$len.' bytes from '.$this->host_.':'.$this->port_.$this->uri_, TTransportException::UNKNOWN);
  151. }
  152. }
  153. return $data;
  154. }
  155. /**
  156. * Writes some data into the pending buffer
  157. *
  158. * @param string $buf The data to write
  159. * @throws TTransportException if writing fails
  160. */
  161. public function write($buf)
  162. {
  163. $this->buf_ .= $buf;
  164. }
  165. /**
  166. * Opens and sends the actual request over the HTTP connection
  167. *
  168. * @throws TTransportException if a writing error occurs
  169. */
  170. public function flush()
  171. {
  172. // God, PHP really has some esoteric ways of doing simple things.
  173. $host = $this->host_.($this->port_ != 80 ? ':'.$this->port_ : '');
  174. $headers = array();
  175. $defaultHeaders = array('Host' => $host,
  176. 'Accept' => 'application/x-thrift',
  177. 'User-Agent' => 'PHP/THttpClient',
  178. 'Content-Type' => 'application/x-thrift',
  179. 'Content-Length' => TStringFuncFactory::create()->strlen($this->buf_));
  180. foreach (array_merge($defaultHeaders, $this->headers_) as $key => $value) {
  181. $headers[] = "$key: $value";
  182. }
  183. $options = array('method' => 'POST',
  184. 'header' => implode("\r\n", $headers),
  185. 'max_redirects' => 1,
  186. 'content' => $this->buf_);
  187. if ($this->timeout_ > 0) {
  188. $options['timeout'] = $this->timeout_;
  189. }
  190. $this->buf_ = '';
  191. $contextid = stream_context_create(array('http' => $options));
  192. $this->handle_ = @fopen($this->scheme_.'://'.$host.$this->uri_, 'r', false, $contextid);
  193. // Connect failed?
  194. if ($this->handle_ === FALSE) {
  195. $this->handle_ = null;
  196. $error = 'THttpClient: Could not connect to '.$host.$this->uri_;
  197. throw new TTransportException($error, TTransportException::NOT_OPEN);
  198. }
  199. }
  200. public function addHeaders($headers)
  201. {
  202. $this->headers_ = array_merge($this->headers_, $headers);
  203. }
  204. }