Erebot  latest
A modular IRC bot for PHP 7.0+
HTTP.php
1 <?php
2 /*
3  This file is part of Erebot, a modular IRC bot written in PHP.
4 
5  Copyright © 2010 François Poirotte
6 
7  Erebot is free software: you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11 
12  Erebot is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with Erebot. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 namespace Erebot\Proxy;
22 
27 class HTTP extends \Erebot\Proxy\Base
28 {
29  public function proxify(\Erebot\URIInterface $proxyURI, \Erebot\URIInterface $nextURI)
30  {
31  $credentials = $proxyURI->getUserInfo();
32  $host = $nextURI->getHost();
33  $port = $nextURI->getPort();
34  $scheme = $nextURI->getScheme();
35 
36  if ($port === null) {
37  $port = getservbyname($scheme, 'tcp');
38  }
39  if (!is_int($port) || $port <= 0 || $port > 65535) {
40  throw new \Erebot\InvalidValueException('Invalid port');
41  }
42 
43  $request = "";
44  $request .= sprintf("CONNECT %s:%d HTTP/1.0\r\n", $host, $port);
45  $request .= sprintf("Host: %s:%d\r\n", $host, $port);
46  $request .= "User-Agent: Erebot/dev-master\r\n";
47 
48  if ($credentials !== null) {
49  $request .= sprintf(
50  "Proxy-Authorization: basic %s\r\n",
51  base64_encode($credentials)
52  );
53  }
54  $request .= "\r\n";
55 
56  for ($written = 0, $len = strlen($request); $written < $len; $written += $fwrite) {
57  $fwrite = fwrite($this->_socket, substr($request, $written));
58  if ($fwrite === false) {
59  throw new \Erebot\Exception('Connection closed by proxy');
60  }
61  }
62 
63  $line = stream_get_line($this->_socket, 4096, "\r\n");
64  if ($line === false) {
65  throw new \Erebot\InvalidValueException(
66  'Invalid response from proxy'
67  );
68  }
69 
70  $this->_logger->debug(
71  '%(line)s',
72  array('line' => addcslashes($line, "\000..\037"))
73  );
74  $contents = array_filter(explode(" ", $line));
75 
76  switch ((int) $contents[1]) {
77  case 200:
78  break;
79  case 407:
80  throw new \Erebot\Exception('Proxy authentication required');
81  default:
82  throw new \Erebot\Exception('Connection rejected by proxy');
83  }
84 
85  // Avoid an endless loop by limiting the number of headers.
86  // No HTTP server is likely to send more than 2^10 headers anyway.
87  $max = (1 << 10);
88  for ($i = 0; $i < $max; $i++) {
89  $line = stream_get_line($this->_socket, 4096, "\r\n");
90  if ($line === false) {
91  throw new \Erebot\InvalidValueException(
92  'Invalid response from proxy'
93  );
94  }
95  if ($line == "") {
96  break;
97  }
98  $this->_logger->debug(
99  '%(line)s',
100  array('line' => addcslashes($line, "\000..\037"))
101  );
102  }
103  if ($i === $max) {
104  throw new \Erebot\InvalidValueException(
105  'Endless loop detected in proxy response'
106  );
107  }
108  }
109 }
Proxies data through an HTTP proxy.
Definition: HTTP.php:27