[ Index ]

PHP Cross Reference of Moodle 1.9.3 [Build 15-Oct-2008]

title

Body

[close]

/lib/simpletestlib/ -> http.php (source)

   1  <?php
   2      /**
   3       *    base include file for SimpleTest
   4       *    @package    SimpleTest
   5       *    @subpackage    WebTester
   6       *    @version    $Id$
   7       */
   8  
   9      /**#@+
  10       *    include other SimpleTest class files
  11       */
  12      require_once(dirname(__FILE__) . '/socket.php');
  13      require_once(dirname(__FILE__) . '/cookies.php');
  14      require_once(dirname(__FILE__) . '/url.php');
  15      /**#@-*/
  16      
  17      /**
  18       *    Creates HTTP headers for the end point of
  19       *    a HTTP request.
  20       *    @package SimpleTest
  21       *    @subpackage WebTester
  22       */
  23      class SimpleRoute {
  24          var $_url;
  25          
  26          /**
  27           *    Sets the target URL.
  28           *    @param SimpleUrl $url   URL as object.
  29           *    @access public
  30           */
  31          function SimpleRoute($url) {
  32              $this->_url = $url;
  33          }
  34          
  35          /**
  36           *    Resource name.
  37           *    @return SimpleUrl        Current url.
  38           *    @access protected
  39           */
  40          function getUrl() {
  41              return $this->_url;
  42          }
  43          
  44          /**
  45           *    Creates the first line which is the actual request.
  46           *    @param string $method   HTTP request method, usually GET.
  47           *    @return string          Request line content.
  48           *    @access protected
  49           */
  50          function _getRequestLine($method) {
  51              return $method . ' ' . $this->_url->getPath() .
  52                      $this->_url->getEncodedRequest() . ' HTTP/1.0';
  53          }
  54          
  55          /**
  56           *    Creates the host part of the request.
  57           *    @return string          Host line content.
  58           *    @access protected
  59           */
  60          function _getHostLine() {
  61              $line = 'Host: ' . $this->_url->getHost();
  62              if ($this->_url->getPort()) {
  63                  $line .= ':' . $this->_url->getPort();
  64              }
  65              return $line;
  66          }
  67          
  68          /**
  69           *    Opens a socket to the route.
  70           *    @param string $method      HTTP request method, usually GET.
  71           *    @param integer $timeout    Connection timeout.
  72           *    @return SimpleSocket       New socket.
  73           *    @access public
  74           */
  75          function &createConnection($method, $timeout) {
  76              $default_port = ('https' == $this->_url->getScheme()) ? 443 : 80;
  77              $socket = &$this->_createSocket(
  78                      $this->_url->getScheme() ? $this->_url->getScheme() : 'http',
  79                      $this->_url->getHost(),
  80                      $this->_url->getPort() ? $this->_url->getPort() : $default_port,
  81                      $timeout);
  82              if (! $socket->isError()) {
  83                  $socket->write($this->_getRequestLine($method) . "\r\n");
  84                  $socket->write($this->_getHostLine() . "\r\n");
  85                  $socket->write("Connection: close\r\n");
  86              }
  87              return $socket;
  88          }
  89          
  90          /**
  91           *    Factory for socket.
  92           *    @param string $scheme                   Protocol to use.
  93           *    @param string $host                     Hostname to connect to.
  94           *    @param integer $port                    Remote port.
  95           *    @param integer $timeout                 Connection timeout.
  96           *    @return SimpleSocket/SimpleSecureSocket New socket.
  97           *    @access protected
  98           */
  99          function &_createSocket($scheme, $host, $port, $timeout) {
 100              if (in_array($scheme, array('https'))) {
 101                  $socket = &new SimpleSecureSocket($host, $port, $timeout);
 102              } else {
 103                  $socket = &new SimpleSocket($host, $port, $timeout);
 104              }
 105              return $socket;
 106          }
 107      }
 108      
 109      /**
 110       *    Creates HTTP headers for the end point of
 111       *    a HTTP request via a proxy server.
 112       *    @package SimpleTest
 113       *    @subpackage WebTester
 114       */
 115      class SimpleProxyRoute extends SimpleRoute {
 116          var $_proxy;
 117          var $_username;
 118          var $_password;
 119          
 120          /**
 121           *    Stashes the proxy address.
 122           *    @param SimpleUrl $url     URL as object.
 123           *    @param string $proxy      Proxy URL.
 124           *    @param string $username   Username for autentication.
 125           *    @param string $password   Password for autentication.
 126           *    @access public
 127           */
 128          function SimpleProxyRoute($url, $proxy, $username = false, $password = false) {
 129              $this->SimpleRoute($url);
 130              $this->_proxy = $proxy;
 131              $this->_username = $username;
 132              $this->_password = $password;
 133          }
 134          
 135          /**
 136           *    Creates the first line which is the actual request.
 137           *    @param string $method   HTTP request method, usually GET.
 138           *    @param SimpleUrl $url   URL as object.
 139           *    @return string          Request line content.
 140           *    @access protected
 141           */
 142          function _getRequestLine($method) {
 143              $url = $this->getUrl();
 144              $scheme = $url->getScheme() ? $url->getScheme() : 'http';
 145              $port = $url->getPort() ? ':' . $url->getPort() : '';
 146              return $method . ' ' . $scheme . '://' . $url->getHost() . $port .
 147                      $url->getPath() . $url->getEncodedRequest() . ' HTTP/1.0';
 148          }
 149          
 150          /**
 151           *    Creates the host part of the request.
 152           *    @param SimpleUrl $url   URL as object.
 153           *    @return string          Host line content.
 154           *    @access protected
 155           */
 156          function _getHostLine() {
 157              $host = 'Host: ' . $this->_proxy->getHost();
 158              $port = $this->_proxy->getPort() ? $this->_proxy->getPort() : 8080;
 159              return "$host:$port";
 160          }
 161          
 162          /**
 163           *    Opens a socket to the route.
 164           *    @param string $method       HTTP request method, usually GET.
 165           *    @param integer $timeout     Connection timeout.
 166           *    @return SimpleSocket        New socket.
 167           *    @access public
 168           */
 169          function &createConnection($method, $timeout) {
 170              $socket = &$this->_createSocket(
 171                      $this->_proxy->getScheme() ? $this->_proxy->getScheme() : 'http',
 172                      $this->_proxy->getHost(),
 173                      $this->_proxy->getPort() ? $this->_proxy->getPort() : 8080,
 174                      $timeout);
 175              if ($socket->isError()) {
 176                  return $socket;
 177              }
 178              $socket->write($this->_getRequestLine($method) . "\r\n");
 179              $socket->write($this->_getHostLine() . "\r\n");
 180              if ($this->_username && $this->_password) {
 181                  $socket->write('Proxy-Authorization: Basic ' .
 182                          base64_encode($this->_username . ':' . $this->_password) .
 183                          "\r\n");
 184              }
 185              $socket->write("Connection: close\r\n");
 186              return $socket;
 187          }
 188      }
 189  
 190      /**
 191       *    HTTP request for a web page. Factory for
 192       *    HttpResponse object.
 193       *    @package SimpleTest
 194       *    @subpackage WebTester
 195       */
 196      class SimpleHttpRequest {
 197          var $_route;
 198          var $_encoding;
 199          var $_headers;
 200          var $_cookies;
 201          
 202          /**
 203           *    Builds the socket request from the different pieces.
 204           *    These include proxy information, URL, cookies, headers,
 205           *    request method and choice of encoding.
 206           *    @param SimpleRoute $route              Request route.
 207           *    @param SimpleFormEncoding $encoding    Content to send with
 208           *                                           request.
 209           *    @access public
 210           */
 211          function SimpleHttpRequest(&$route, $encoding) {
 212              $this->_route = &$route;
 213              $this->_encoding = $encoding;
 214              $this->_headers = array();
 215              $this->_cookies = array();
 216          }
 217          
 218          /**
 219           *    Dispatches the content to the route's socket.
 220           *    @param integer $timeout      Connection timeout.
 221           *    @return SimpleHttpResponse   A response which may only have
 222           *                                 an error, but hopefully has a
 223           *                                 complete web page.
 224           *    @access public
 225           */
 226          function &fetch($timeout) {
 227              $socket = &$this->_route->createConnection($this->_encoding->getMethod(), $timeout);
 228              if (! $socket->isError()) {
 229                  $this->_dispatchRequest($socket, $this->_encoding);
 230              }
 231              $response = &$this->_createResponse($socket);
 232              return $response;
 233          }
 234          
 235          /**
 236           *    Sends the headers.
 237           *    @param SimpleSocket $socket           Open socket.
 238           *    @param string $method                 HTTP request method,
 239           *                                          usually GET.
 240           *    @param SimpleFormEncoding $encoding   Content to send with request.
 241           *    @access private
 242           */
 243          function _dispatchRequest(&$socket, $encoding) {
 244              foreach ($this->_headers as $header_line) {
 245                  $socket->write($header_line . "\r\n");
 246              }
 247              if (count($this->_cookies) > 0) {
 248                  $socket->write("Cookie: " . implode(";", $this->_cookies) . "\r\n");
 249              }
 250              $encoding->writeHeadersTo($socket);
 251              $socket->write("\r\n");
 252              $encoding->writeTo($socket);
 253          }
 254          
 255          /**
 256           *    Adds a header line to the request.
 257           *    @param string $header_line    Text of full header line.
 258           *    @access public
 259           */
 260          function addHeaderLine($header_line) {
 261              $this->_headers[] = $header_line;
 262          }
 263          
 264          /**
 265           *    Reads all the relevant cookies from the
 266           *    cookie jar.
 267           *    @param SimpleCookieJar $jar     Jar to read
 268           *    @param SimpleUrl $url           Url to use for scope.
 269           *    @access public
 270           */
 271          function readCookiesFromJar($jar, $url) {
 272              $this->_cookies = $jar->selectAsPairs($url);
 273          }
 274          
 275          /**
 276           *    Wraps the socket in a response parser.
 277           *    @param SimpleSocket $socket   Responding socket.
 278           *    @return SimpleHttpResponse    Parsed response object.
 279           *    @access protected
 280           */
 281          function &_createResponse(&$socket) {
 282              $response = &new SimpleHttpResponse(
 283                      $socket,
 284                      $this->_route->getUrl(),
 285                      $this->_encoding);
 286              return $response;
 287          }
 288      }
 289      
 290      /**
 291       *    Collection of header lines in the response.
 292       *    @package SimpleTest
 293       *    @subpackage WebTester
 294       */
 295      class SimpleHttpHeaders {
 296          var $_raw_headers;
 297          var $_response_code;
 298          var $_http_version;
 299          var $_mime_type;
 300          var $_location;
 301          var $_cookies;
 302          var $_authentication;
 303          var $_realm;
 304          
 305          /**
 306           *    Parses the incoming header block.
 307           *    @param string $headers     Header block.
 308           *    @access public
 309           */
 310          function SimpleHttpHeaders($headers) {
 311              $this->_raw_headers = $headers;
 312              $this->_response_code = false;
 313              $this->_http_version = false;
 314              $this->_mime_type = '';
 315              $this->_location = false;
 316              $this->_cookies = array();
 317              $this->_authentication = false;
 318              $this->_realm = false;
 319              foreach (split("\r\n", $headers) as $header_line) {
 320                  $this->_parseHeaderLine($header_line);
 321              }
 322          }
 323          
 324          /**
 325           *    Accessor for parsed HTTP protocol version.
 326           *    @return integer           HTTP error code.
 327           *    @access public
 328           */
 329          function getHttpVersion() {
 330              return $this->_http_version;
 331          }
 332          
 333          /**
 334           *    Accessor for raw header block.
 335           *    @return string        All headers as raw string.
 336           *    @access public
 337           */
 338          function getRaw() {
 339              return $this->_raw_headers;
 340          }
 341          
 342          /**
 343           *    Accessor for parsed HTTP error code.
 344           *    @return integer           HTTP error code.
 345           *    @access public
 346           */
 347          function getResponseCode() {
 348              return (integer)$this->_response_code;
 349          }
 350          
 351          /**
 352           *    Returns the redirected URL or false if
 353           *    no redirection.
 354           *    @return string      URL or false for none.
 355           *    @access public
 356           */
 357          function getLocation() {
 358              return $this->_location;
 359          }
 360          
 361          /**
 362           *    Test to see if the response is a valid redirect.
 363           *    @return boolean       True if valid redirect.
 364           *    @access public
 365           */
 366          function isRedirect() {
 367              return in_array($this->_response_code, array(301, 302, 303, 307)) &&
 368                      (boolean)$this->getLocation();
 369          }
 370          
 371          /**
 372           *    Test to see if the response is an authentication
 373           *    challenge.
 374           *    @return boolean       True if challenge.
 375           *    @access public
 376           */
 377          function isChallenge() {
 378              return ($this->_response_code == 401) &&
 379                      (boolean)$this->_authentication &&
 380                      (boolean)$this->_realm;
 381          }
 382          
 383          /**
 384           *    Accessor for MIME type header information.
 385           *    @return string           MIME type.
 386           *    @access public
 387           */
 388          function getMimeType() {
 389              return $this->_mime_type;
 390          }
 391          
 392          /**
 393           *    Accessor for authentication type.
 394           *    @return string        Type.
 395           *    @access public
 396           */
 397          function getAuthentication() {
 398              return $this->_authentication;
 399          }
 400          
 401          /**
 402           *    Accessor for security realm.
 403           *    @return string        Realm.
 404           *    @access public
 405           */
 406          function getRealm() {
 407              return $this->_realm;
 408          }
 409          
 410          /**
 411           *    Writes new cookies to the cookie jar.
 412           *    @param SimpleCookieJar $jar   Jar to write to.
 413           *    @param SimpleUrl $url         Host and path to write under.
 414           *    @access public
 415           */
 416          function writeCookiesToJar(&$jar, $url) {
 417              foreach ($this->_cookies as $cookie) {
 418                  $jar->setCookie(
 419                          $cookie->getName(),
 420                          $cookie->getValue(),
 421                          $url->getHost(),
 422                          $cookie->getPath(),
 423                          $cookie->getExpiry());
 424              }
 425          }
 426  
 427          /**
 428           *    Called on each header line to accumulate the held
 429           *    data within the class.
 430           *    @param string $header_line        One line of header.
 431           *    @access protected
 432           */
 433          function _parseHeaderLine($header_line) {
 434              if (preg_match('/HTTP\/(\d+\.\d+)\s+(\d+)/i', $header_line, $matches)) {
 435                  $this->_http_version = $matches[1];
 436                  $this->_response_code = $matches[2];
 437              }
 438              if (preg_match('/Content-type:\s*(.*)/i', $header_line, $matches)) {
 439                  $this->_mime_type = trim($matches[1]);
 440              }
 441              if (preg_match('/Location:\s*(.*)/i', $header_line, $matches)) {
 442                  $this->_location = trim($matches[1]);
 443              }
 444              if (preg_match('/Set-cookie:(.*)/i', $header_line, $matches)) {
 445                  $this->_cookies[] = $this->_parseCookie($matches[1]);
 446              }
 447              if (preg_match('/WWW-Authenticate:\s+(\S+)\s+realm=\"(.*?)\"/i', $header_line, $matches)) {
 448                  $this->_authentication = $matches[1];
 449                  $this->_realm = trim($matches[2]);
 450              }
 451          }
 452          
 453          /**
 454           *    Parse the Set-cookie content.
 455           *    @param string $cookie_line    Text after "Set-cookie:"
 456           *    @return SimpleCookie          New cookie object.
 457           *    @access private
 458           */
 459          function _parseCookie($cookie_line) {
 460              $parts = split(";", $cookie_line);
 461              $cookie = array();
 462              preg_match('/\s*(.*?)\s*=(.*)/', array_shift($parts), $cookie);
 463              foreach ($parts as $part) {
 464                  if (preg_match('/\s*(.*?)\s*=(.*)/', $part, $matches)) {
 465                      $cookie[$matches[1]] = trim($matches[2]);
 466                  }
 467              }
 468              return new SimpleCookie(
 469                      $cookie[1],
 470                      trim($cookie[2]),
 471                      isset($cookie["path"]) ? $cookie["path"] : "",
 472                      isset($cookie["expires"]) ? $cookie["expires"] : false);
 473          }
 474      }
 475      
 476      /**
 477       *    Basic HTTP response.
 478       *    @package SimpleTest
 479       *    @subpackage WebTester
 480       */
 481      class SimpleHttpResponse extends SimpleStickyError {
 482          var $_url;
 483          var $_encoding;
 484          var $_sent;
 485          var $_content;
 486          var $_headers;
 487          
 488          /**
 489           *    Constructor. Reads and parses the incoming
 490           *    content and headers.
 491           *    @param SimpleSocket $socket   Network connection to fetch
 492           *                                  response text from.
 493           *    @param SimpleUrl $url         Resource name.
 494           *    @param mixed $encoding        Record of content sent.
 495           *    @access public
 496           */
 497          function SimpleHttpResponse(&$socket, $url, $encoding) {
 498              $this->SimpleStickyError();
 499              $this->_url = $url;
 500              $this->_encoding = $encoding;
 501              $this->_sent = $socket->getSent();
 502              $this->_content = false;
 503              $raw = $this->_readAll($socket);
 504              if ($socket->isError()) {
 505                  $this->_setError('Error reading socket [' . $socket->getError() . ']');
 506                  return;
 507              }
 508              $this->_parse($raw);
 509          }
 510          
 511          /**
 512           *    Splits up the headers and the rest of the content.
 513           *    @param string $raw    Content to parse.
 514           *    @access private
 515           */
 516          function _parse($raw) {
 517              if (! $raw) {
 518                  $this->_setError('Nothing fetched');
 519                  $this->_headers = &new SimpleHttpHeaders('');
 520              } elseif (! strstr($raw, "\r\n\r\n")) {
 521                  $this->_setError('Could not split headers from content');
 522                  $this->_headers = &new SimpleHttpHeaders($raw);
 523              } else {
 524                  list($headers, $this->_content) = split("\r\n\r\n", $raw, 2);
 525                  $this->_headers = &new SimpleHttpHeaders($headers);
 526              }
 527          }
 528          
 529          /**
 530           *    Original request method.
 531           *    @return string        GET, POST or HEAD.
 532           *    @access public
 533           */
 534          function getMethod() {
 535              return $this->_encoding->getMethod();
 536          }
 537          
 538          /**
 539           *    Resource name.
 540           *    @return SimpleUrl        Current url.
 541           *    @access public
 542           */
 543          function getUrl() {
 544              return $this->_url;
 545          }
 546          
 547          /**
 548           *    Original request data.
 549           *    @return mixed              Sent content.
 550           *    @access public
 551           */
 552          function getRequestData() {
 553              return $this->_encoding;
 554          }
 555          
 556          /**
 557           *    Raw request that was sent down the wire.
 558           *    @return string        Bytes actually sent.
 559           *    @access public
 560           */
 561          function getSent() {
 562              return $this->_sent;
 563          }
 564          
 565          /**
 566           *    Accessor for the content after the last
 567           *    header line.
 568           *    @return string           All content.
 569           *    @access public
 570           */
 571          function getContent() {
 572              return $this->_content;
 573          }
 574          
 575          /**
 576           *    Accessor for header block. The response is the
 577           *    combination of this and the content.
 578           *    @return SimpleHeaders        Wrapped header block.
 579           *    @access public
 580           */
 581          function getHeaders() {
 582              return $this->_headers;
 583          }
 584          
 585          /**
 586           *    Accessor for any new cookies.
 587           *    @return array       List of new cookies.
 588           *    @access public
 589           */
 590          function getNewCookies() {
 591              return $this->_headers->getNewCookies();
 592          }
 593          
 594          /**
 595           *    Reads the whole of the socket output into a
 596           *    single string.
 597           *    @param SimpleSocket $socket  Unread socket.
 598           *    @return string               Raw output if successful
 599           *                                 else false.
 600           *    @access private
 601           */
 602          function _readAll(&$socket) {
 603              $all = '';
 604              while (! $this->_isLastPacket($next = $socket->read())) {
 605                  $all .= $next;
 606              }
 607              return $all;
 608          }
 609          
 610          /**
 611           *    Test to see if the packet from the socket is the
 612           *    last one.
 613           *    @param string $packet    Chunk to interpret.
 614           *    @return boolean          True if empty or EOF.
 615           *    @access private
 616           */
 617          function _isLastPacket($packet) {
 618              if (is_string($packet)) {
 619                  return $packet === '';
 620              }
 621              return ! $packet;
 622          }
 623      }
 624  ?>


Generated: Wed Jan 14 11:33:29 2009 Cross-referenced by PHPXref 0.7