function stream_read($count) { switch ($this->cur_state) { case static::BUFFERING: $buffer =& $this->buffer; // sadly this blocks on Windows. // non-blocking pipes don't work in PHP on Windows, and stream_select doesn't know when the pipe has data $data = fread($this->stream, $count); if ($data !== false) { $buffer .= $data; // need to wait until CGI is finished to determine Content-Length if (!feof($this->stream)) { return ''; } } // now the CGI process has finished sending data. // CGI process sends HTTP status as regular header, // which we need to convert to HTTP status line. // also, need to add Content-Length header for HTTP keep-alive $end_response_headers = strpos($buffer, "\r\n\r\n"); if ($end_response_headers === false) { $response = $this->server->text_response(502, "Invalid Response from CGI process"); } else { $headers_str = substr($buffer, 0, $end_response_headers); $headers = HTTPServer::parse_headers($headers_str); if (isset($headers['Status'])) { $status_arr = explode(' ', $headers['Status'], 2); $status = (int) $status_arr[0]; $status_msg = trim($status_arr[1]); unset($headers['Status']); } else { $status = 200; $status_msg = null; } $content = substr($buffer, $end_response_headers + 4); $response = $this->server->response($status, $content, $headers, $status_msg); } // set status and headers on the server's HTTPResponse object. // these aren't actually sent to the client, // but they could be referenced by HTTPServer::get_log_line $this->response->status = $response->status; $this->response->status_msg = $response->status_msg; $this->response->headers = $response->headers; $this->cur_state = static::BUFFERED; $this->buffer_stream = fopen('data://text/plain,', 'r+b'); fwrite($this->buffer_stream, $response->render()); fseek($this->buffer_stream, 0); // intentional fallthrough // intentional fallthrough case static::BUFFERED: $res = fread($this->buffer_stream, $count); if (feof($this->buffer_stream)) { $this->cur_state = static::EOF; } return $res; case static::EOF: return false; } }
function __construct() { parent::__construct(array('port' => 8002)); }
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ require dirname(__FILE__) . '/_bootstrap.php'; // configure logger JAXLLogger::$level = JAXLLogger::INFO; // print usage notice and parse addr/port parameters if passed JAXLLogger::cliLog("Usage: {$argv['0']} port (default: 9699)", JAXLLogger::NOTICE); $port = $argc == 2 ? $argv[1] : 9699; // initialize http server $http = new HTTPServer($port); // callback method for dispatch rule (see below) function index($request) { $request->send_response(200, array('Content-Type' => 'text/html'), '<html><head/><body><h1>Jaxl Http Server</h1><a href="/upload">upload a file</a></body></html>'); $request->close(); } // callback method for dispatch rule (see below) function upload($request) { if ($request->method == 'GET') { $request->ok(array('Content-Type' => 'text/html'), '<html><head/><body><h1>Jaxl Http Server</h1><form enctype="multipart/form-data" method="POST" ' . 'action="http://127.0.0.1:9699/upload/"><input type="file" name="file"/><input type="submit" ' . 'value="upload"/></form></body></html>'); } elseif ($request->method == 'POST') { if ($request->body === null && $request->expect) { $request->recv_body(); } else {
function add_data($data) { switch ($this->cur_state) { case static::READ_HEADERS: if (!$this->start_time) { $this->start_time = microtime(true); } $header_buf =& $this->header_buf; $header_buf .= $data; if (strlen($header_buf) < 4) { break; } $end_headers = strpos($header_buf, "\r\n\r\n", 4); if ($end_headers === false) { break; } // parse HTTP request line $end_req = strpos($header_buf, "\r\n"); $this->request_line = substr($header_buf, 0, $end_req); $req_arr = explode(' ', $this->request_line, 3); $this->method = $req_arr[0]; $this->request_uri = $req_arr[1]; $this->http_version = $req_arr[2]; $parsed_uri = parse_url($this->request_uri); $this->uri = urldecode($parsed_uri['path']); $this->query_string = @$parsed_uri['query']; // parse HTTP headers $start_headers = $end_req + 2; $headers_str = substr($header_buf, $start_headers, $end_headers - $start_headers); $this->headers = HTTPServer::parse_headers($headers_str); $this->lc_headers = array(); foreach ($this->headers as $k => $v) { $this->lc_headers[strtolower($k)] = $v; } if (isset($this->lc_headers['transfer-encoding'])) { $this->is_chunked = $this->lc_headers['transfer-encoding'][0] == 'chunked'; unset($this->lc_headers['transfer-encoding']); unset($this->headers['Transfer-Encoding']); $this->content_len = 0; } else { $this->content_len = (int) @$this->lc_headers['content-length'][0]; } $start_content = $end_headers + 4; // $end_headers is before last \r\n\r\n $data = substr($header_buf, $start_content); $header_buf = ''; $this->cur_state = static::READ_CONTENT; // fallthrough to READ_CONTENT with leftover data // fallthrough to READ_CONTENT with leftover data case static::READ_CONTENT: if ($this->is_chunked) { $this->read_chunked_data($data); } else { fwrite($this->content_stream, $data); $this->content_len_read += strlen($data); if ($this->content_len - $this->content_len_read <= 0) { $this->cur_state = static::READ_COMPLETE; } } break; case static::READ_COMPLETE: break; } if ($this->cur_state == static::READ_COMPLETE) { fseek($this->content_stream, 0); } }
function __construct($init) { parent::__construct(array('port' => $init['port'])); }
function add_data($data) { switch ($this->cur_state) { case static::READ_HEADERS: if (!$this->start_time) { $this->start_time = microtime(true); } $header_buf =& $this->header_buf; $header_buf .= $data; $end_headers = strpos($header_buf, "\r\n\r\n", 4); if ($end_headers === false) { break; } // parse HTTP request line $end_req = strpos($header_buf, "\r\n"); $this->request_line = substr($header_buf, 0, $end_req); $req_arr = explode(' ', $this->request_line, 3); $this->method = $req_arr[0]; $this->request_uri = $req_arr[1]; $this->http_version = $req_arr[2]; $parsed_uri = parse_url($this->request_uri); $this->uri = urldecode($parsed_uri['path']); $this->query_string = @$parsed_uri['query']; // parse HTTP headers $start_headers = $end_req + 2; $headers_str = substr($header_buf, $start_headers, $end_headers - $start_headers); $this->headers = HTTPServer::parse_headers($headers_str); $this->lc_headers = array(); foreach ($this->headers as $k => $v) { $this->lc_headers[strtolower($k)] = $v; } $this->content_len = (int) @$this->lc_headers['content-length']; $start_content = $end_headers + 4; // $end_headers is before last \r\n\r\n // add leftover to content $content = substr($header_buf, $start_content); fwrite($this->content_stream, $content); $this->content_len_read = strlen($content); $header_buf = ''; break; case static::READ_CONTENT: fwrite($this->content_stream, $data); $this->content_len_read += strlen($data); break; case static::READ_COMPLETE: break; } if (!$this->headers) { $this->cur_state = static::READ_HEADERS; } else { if ($this->needs_content()) { $this->cur_state = static::READ_CONTENT; } else { fseek($this->content_stream, 0); $this->cur_state = static::READ_COMPLETE; } } }
/** * Returns a server config value. * * @access public * @return mixed */ public function config($key) { return $this->_server->config($key); }
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ // include and configure logger require_once 'jaxl.php'; JAXLLogger::$level = JAXL_INFO; // print usage notice and parse addr/port parameters if passed _colorize("Usage: {$argv['0']} port (default: 9699)", JAXL_NOTICE); $port = $argc == 2 ? $argv[1] : 9699; // initialize http server require_once JAXL_CWD . '/http/http_server.php'; $http = new HTTPServer($port); // catch all incoming requests here function on_request($request) { $body = json_encode($request); $request->ok($body, array('Content-Type' => 'application/json')); } // start http server $http->start('on_request');