Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial implementation of the CGI handler

  • Loading branch information...
commit a0834096938a060554baf581e278d5f0a1400af5 1 parent cf953f7
@shevron authored
View
51 examples/cgi/info-xml.php
@@ -0,0 +1,51 @@
+<?php
+
+$superGlobs = array(
+ 'GET' => $_GET,
+ 'POST' => $_POST,
+ 'COOKIE' => $_COOKIE,
+ 'SERVER' => $_SERVER,
+ 'ENV' => $_ENV
+);
+
+header("Content-type: text/xml");
+
+$xml = new xmlWriter();
+$xml->openURI('php://output');
+$xml->setIndent(true);
+$xml->setIndentString(" ");
+
+$xml->startDocument();
+$xml->startElement('superglobals');
+
+foreach ($superGlobs as $globname => $glob) {
+ $xml->startElement('superglobal');
+ $xml->writeAttribute('name', $globname);
+
+ foreach($glob as $k => $v) {
+ print_glob_val($xml, $k, $v);
+ }
+
+ $xml->endElement();
+}
+
+$xml->endElement();
+$xml->endDocument();
+$xml->flush();
+
+function print_glob_val(XMLWriter $xml, $key, $value)
+{
+ $xml->startElement('value');
+ $xml->writeAttribute('name', $key);
+
+ if (is_array($value)) {
+ foreach($value as $subkey => $subval) {
+ print_glob_val($xml, $subkey, $subval);
+ }
+ } else {
+ $xml->text($value);
+ }
+
+ $xml->endElement();
+}
+
View
3  examples/cgi/info.php
@@ -0,0 +1,3 @@
+<?php
+
+phpinfo();
View
27 examples/server-cgi.php
@@ -0,0 +1,27 @@
+<?php
+
+// Add the incubator to the include path
+set_include_path(
+ dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'library'
+);
+
+require_once 'Aspamia/Http/Server.php';
+require_once 'Aspamia/Http/Server/Plugin/Logger.php';
+require_once 'Aspamia/Http/Server/Handler/Cgi.php';
+
+// Create the server object
+$server = new Aspamia_Http_Server();
+
+// Create the handler object - a single static handler for now
+$handler = new Aspamia_Http_Server_Handler_Cgi(array(
+ 'handler' => '/usr/bin/php-cgi',
+ 'document_root' => dirname(__FILE__) . DIRECTORY_SEPARATOR . 'cgi'
+));
+$server->setHandler($handler);
+
+// Register the logger plugin
+$server->registerPlugin(new Aspamia_Http_Server_Plugin_Logger());
+
+// Run the server!
+echo "Running Aspamia, use Ctrl+C to abort...\n";
+$server->run();
View
0  examples/server.php → examples/server-static.php
File renamed without changes
View
40 library/Aspamia/Http/Request.php
@@ -38,6 +38,20 @@ class Aspamia_Http_Request extends Aspamia_Http_Message
protected $_socket;
/**
+ * The remote address who made the request
+ *
+ * @var string
+ */
+ protected $_remoteAddress = null;
+
+ /**
+ * The local IP address that recieved the request
+ *
+ * @var string
+ */
+ protected $_localAddress = null;
+
+ /**
* Create a new request object
*
* @param string $method
@@ -74,6 +88,26 @@ public function getUri()
}
/**
+ * Get the remote address from which the request came, if known
+ *
+ * @return string
+ */
+ public function getRemoteAddress()
+ {
+ return $this->_remoteAddress;
+ }
+
+ /**
+ * Get the local address to which the response was sent, if known
+ *
+ * @return string
+ */
+ public function getLocalAddress()
+ {
+ return $this->_localAddress;
+ }
+
+ /**
* Set the request method
*
* @param string $method
@@ -157,6 +191,10 @@ protected function _getStartLine()
*/
static public function read($connection, $read_body = false)
{
+ // Get the local and remote address of the connection
+ $localAddress = stream_socket_get_name($connection, false);
+ $remoteAddress = stream_socket_get_name($connection, true);
+
$headerlines = self::_readHeaders($connection);
if (empty($headerlines)) {
require_once 'Aspamia/Http/Exception.php';
@@ -192,6 +230,8 @@ static public function read($connection, $read_body = false)
$request = new Aspamia_Http_Request($method, $uri, $headers);
$request->_httpVersion = $protocol[1];
$request->_socket = $connection;
+ $request->_localAddress = $localAddress;
+ $request->_remoteAddress = $remoteAddress;
if ($read_body) {
$request->_readBody();
View
7 library/Aspamia/Http/Response.php
@@ -204,7 +204,7 @@ static public function fromString($message)
require_once 'Aspamia/Http/Exception.php';
throw new Aspamia_Http_Exception("Invalid HTTP response status line: $statusLine");
}
-
+
$response = new Aspamia_Http_Response(
(int) $parts[2],
$headers,
@@ -213,6 +213,11 @@ static public function fromString($message)
$parts[3]
);
+ // Add the content-length header if not set
+ if ($response->getHeader('content-length') === null) {
+ $response->setHeader('content-length', strlen($body));
+ }
+
return $response;
}
View
32 library/Aspamia/Http/Server.php
@@ -7,9 +7,8 @@
class Aspamia_Http_Server
{
const ASPAMIA_VERSION = '0.0.1';
-
- const DEFAULT_ADDR = '127.0.0.1';
- const DEFAULT_PORT = 8000;
+ const DEFAULT_ADDR = '127.0.0.1';
+ const DEFAULT_PORT = 8000;
protected $_config = array(
'bind_addr' => self::DEFAULT_ADDR,
@@ -52,7 +51,7 @@ public function __construct($config = array())
// Initialize handler
if ($this->_config['handler'] instanceof Aspamia_Http_Server_Handler_Abstract) {
- $this->_handler = $this->_config['handler'];
+ $this->setHandler($handler);
} elseif (is_string($this->_config['handler'])) {
require_once 'Zend/Loader.php';
@@ -64,7 +63,7 @@ public function __construct($config = array())
throw new Aspamia_Http_Server_Exception("Provded handler is not a Aspamia_Http_Server_Handler_Abstract object");
}
- $this->_handler = $handler;
+ $this->setHandler($handler);
}
}
@@ -88,6 +87,23 @@ public function setConfig($config)
$this->_config[$k] = $v;
}
}
+
+ /**
+ * Get a configuration option value or the entire configuration array
+ *
+ * @param null|string $key
+ * @return mixed
+ */
+ public function getConfig($key = null)
+ {
+ if ($key === null) {
+ return $this->_config;
+ } elseif (isset($this->_config[$key])) {
+ return $this->_config[$key];
+ } else {
+ return null;
+ }
+ }
/**
* Register a plug-in
@@ -153,9 +169,15 @@ public function run()
$this->_callServerShutdownPlugins();
}
+ /**
+ * Set the handler object
+ *
+ * @param Aspamia_Http_Server_Handler_Abstract $handler
+ */
public function setHandler(Aspamia_Http_Server_Handler_Abstract $handler)
{
$this->_handler = $handler;
+ $handler->setServer($this);
}
protected function _handle($connection)
View
17 library/Aspamia/Http/Server/Handler/Abstract.php
@@ -9,6 +9,13 @@
*/
protected $_config = array();
+ /**
+ * The parent server object
+ *
+ * @var Aspamia_Http_Server
+ */
+ protected $_server = null;
+
public function __construct($config = array())
{
$this->setConfig($config);
@@ -36,6 +43,16 @@ public function setConfig($config)
}
/**
+ * Set the related server object. Called when registering the handler.
+ *
+ * @param Aspamia_Http_Server $server
+ */
+ public function setServer(Aspamia_Http_Server $server)
+ {
+ $this->_server = $server;
+ }
+
+ /**
* Create an error HTTP response message based on code and message
*
* @param integer $code
View
130 library/Aspamia/Http/Server/Handler/Cgi.php
@@ -1,3 +1,131 @@
<?php
-?>
+/**
+ * Aspamia HTTP Server Library for PHP
+ *
+ * @author Shahar Evron
+ * @license New BSD License, <url>
+ */
+
+require_once 'Aspamia/Http/Server/Handler/Abstract.php';
+
+/**
+ * CGI handler
+ *
+ * This handler implements the CGI/1.1 protocol, allowing the web server to
+ * execute programs in order to generate dynamic pages. Through CGI, you can
+ * enable PHP as well as other dynamic languages (Python, Perl) to generate web
+ * pages.
+ *
+ */
+class Aspamia_Http_Server_Handler_Cgi extends Aspamia_Http_Server_Handler_Abstract
+{
+ protected $_config = array(
+ 'handler' => null,
+ 'handler_script' => null,
+ 'document_root' => null,
+ );
+
+ /**
+ * Handle the request
+ *
+ * @param Aspamia_Http_Request $request
+ * @return Aspamia_Http_Response
+ */
+ public function handle(Aspamia_Http_Request $request)
+ {
+ if (! $this->_config['handler']) {
+ require_once 'Aspamia/Http/Server/Handler/Exception.php';
+ throw new Aspamia_Http_Server_Handler_Exception("No CGI handler was set");
+ }
+
+ if (isset($this->_config['document_root'])) {
+ $document_root = $this->_config['document_root'];
+ } else {
+ $document_root = getcwd();
+ }
+
+ // Parse the URI
+ $urlInfo = parse_url($request->getUri());
+
+ // Build the translated path
+ $script_path = rtrim($document_root, '/') .
+ (isset($this->_config['handler_script']) ?
+ '/' . ltrim($this->_config['handler_script']) :
+ $urlInfo['path']
+ );
+
+ // Set up the environment
+ $environment = array(
+ 'SERVER_SOFTWARE ' => 'Aspamia/' .
+ Aspamia_Http_Server::ASPAMIA_VERSION,
+ 'SERVER_NAME' => $request->getLocalAddress(),
+ 'SERVER_PROTOCOL' => 'HTTP/' . $request->getHttpVersion(),
+ 'SERVER_PORT' => $this->_server->getConfig('bind_port'),
+ 'DOCUMENT_ROOT' => $document_root,
+ 'GATEWAY_INTERFACE' => 'CGI/1.1',
+ 'REQUEST_METHOD' => $request->getMethod(),
+ 'REQUEST_URI' => $request->getUri(),
+ 'PATH_INFO' => $request->getUri(),
+ 'PATH_TRANSLATED' => $script_path,
+ 'SCRIPT_NAME' => $urlInfo['path'],
+ 'REMOTE_ADDR' => $request->getRemoteAddress(),
+ 'CONTENT_TYPE' => $request->getHeader('content-type'),
+ 'CONTENT_LENGTH' => $request->getHeader('content-length'),
+ 'PATH' => getenv('PATH')
+ );
+
+ if (isset($urlInfo['query'])) {
+ $environment['QUERY_STRING'] = $urlInfo['query'];
+ }
+
+ // Add the HTTP headers to the environment
+ $headers = $request->getAllHeaders();
+ unset(
+ $headers['content-type'],
+ $headers['content-length']
+ );
+ foreach($headers as $header => $value) {
+ $key = 'HTTP_' . strtoupper(strtr($header, '-', '_'));
+ $environment[$key] = $value;
+ }
+
+ // Open the CGI handler process
+ $cgi_proc = proc_open(
+ $this->_config['handler'],
+ array(
+ array('pipe', 'r'),
+ array('pipe', 'w'),
+ array('file', '/tmp/cgi-error.log', 'a')
+ ),
+ $pipes,
+ null,
+ $environment
+ );
+ if (! $cgi_proc) {
+ require_once 'Aspamia/Http/Server/Handler/Exception.php';
+ throw new Aspamia_Http_Server_Handler_Exception("Unable to run CGI handler");
+ }
+
+ // Write body, if any, to the CGI STDIN
+ fwrite($pipes[0], $request->getBody());
+ fclose($pipes[0]);
+
+ // Read the response
+ $response = stream_get_contents($pipes[1]);
+ fclose($pipes[1]);
+
+ // Close CGI process
+ proc_close($cgi_proc);
+
+ // Create the status line
+ $statusLine = "HTTP/{$request->getHttpVersion()}";
+ if (preg_match('/\Astatus:\s*(\d+ .+)$/', $response, $m)) {
+ $statusLine .= " {$m[1]}\r\n";
+ } else {
+ $statusLine .= " 200 OK\r\n"; // Default, send 200 Ok
+ }
+
+ return Aspamia_Http_Response::fromString($statusLine . $response);
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.