Source for file http.php

Documentation is available at http.php

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

Documentation generated on Sun, 04 May 2008 09:21:41 -0500 by phpDocumentor 1.3.0