Merge lp:~fourkitchens/pressflow/6-evented into lp:pressflow

Proposed by David Strauss
Status: Work in progress
Proposed branch: lp:~fourkitchens/pressflow/6-evented
Merge into: lp:pressflow
Diff against target: 485 lines (+340/-18)
6 files modified
DaemonRequest.php (+58/-0)
DaemonResponse.php (+139/-0)
evented-daemon.php (+120/-0)
includes/bootstrap.inc (+12/-10)
includes/common.inc (+10/-8)
themes/garland/page.tpl.php (+1/-0)
To merge this branch: bzr merge lp:~fourkitchens/pressflow/6-evented
Reviewer Review Type Date Requested Status
Pressflow Administrators Pending
Review via email: mp+29770@code.launchpad.net
To post a comment you must log in.
lp:~fourkitchens/pressflow/6-evented updated
88. By Aaron Forsander

Added very basic support for static files.

89. By Aaron Forsander

Drupal's .htaccess doesn't set q with the leading / and it trims trailing slashes anyways.

90. By Aaron Forsander

Created DaemonRequest and DaemonResponse classes to make working with requests and responses a little easier. Trying to figure out the appropriate session setup/teardown per request.

91. By Aaron Forsander

Cleaning up log output.

92. By David Strauss

Merge from 6.x trunk.

Unmerged revisions

92. By David Strauss

Merge from 6.x trunk.

91. By Aaron Forsander

Cleaning up log output.

90. By Aaron Forsander

Created DaemonRequest and DaemonResponse classes to make working with requests and responses a little easier. Trying to figure out the appropriate session setup/teardown per request.

89. By Aaron Forsander

Drupal's .htaccess doesn't set q with the leading / and it trims trailing slashes anyways.

88. By Aaron Forsander

Added very basic support for static files.

87. By David Strauss

Make the port number for the daemon a shell argument.

86. By David Strauss

Initial event-driven system.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'DaemonRequest.php'
--- DaemonRequest.php 1970-01-01 00:00:00 +0000
+++ DaemonRequest.php 2010-08-22 07:23:38 +0000
@@ -0,0 +1,58 @@
1<?php
2
3class DaemonRequest {
4 public $request;
5 public $method = '';
6 public $uri = '';
7 public $query_string = '';
8 public $path = '';
9 public $headers = array();
10 public $body = '';
11
12 public function __construct($evhttp_request) {
13 $this->request = $evhttp_request;
14 $this->method = evhttp_request_method($this->request);
15 $this->uri = evhttp_request_uri($this->request);
16 $this->headers = evhttp_request_headers($this->request);
17 $this->body = evhttp_request_body($this->request);
18 $this->query_string = parse_url($this->uri, PHP_URL_QUERY);
19 $this->path = parse_url($this->uri, PHP_URL_PATH);
20 }
21
22 public function init() {
23 // Reset request-specific globals
24 foreach (array('_COOKIE', '_POST', '_GET', '_FILES', '_SESSION') as $global) {
25 $GLOBALS[$global] = array();
26 }
27
28 // Initialize SERVER data
29 $_SERVER["REQUEST_METHOD"] = $this->method;
30 $_SERVER["REQUEST_TIME"] = time();
31 $_SERVER["argv"] = $_SERVER["REQUEST_URI"] = $this->uri;
32
33 // Initialize HTTP data
34 foreach ($this->headers as $name => $value) {
35 $_SERVER["HTTP_" . str_replace("-", "_", strtoupper($name))] = $value;
36 }
37
38 // Initialize POST data
39 if ($this->method === "POST") {
40 parse_str($this->body, $_POST);
41 }
42
43 // Initialize GET data
44 $_SERVER['QUERY_STRING'] = $this->query_string;
45 parse_str($this->query_string, $_GET);
46 $_GET['q'] = trim($this->path, '/');
47
48 // Initialize COOKIE data
49 if ($this->headers['Cookie']) {
50 $cookies = explode(';', $this->headers['Cookie']);
51 foreach ($cookies as $cookie) {
52 list($name, $value) = explode('=', $cookie);
53 $_COOKIE[$name] = $value;
54 }
55 }
56 }
57}
58
059
=== added file 'DaemonResponse.php'
--- DaemonResponse.php 1970-01-01 00:00:00 +0000
+++ DaemonResponse.php 2010-08-22 07:23:38 +0000
@@ -0,0 +1,139 @@
1<?php
2class DaemonResponse {
3 public $request;
4 public $response;
5 public $code;
6 public $body;
7 public $headers = array();
8
9 public static $messages = array(
10 // Informational 1xx
11 100 => 'Continue',
12 101 => 'Switching Protocols',
13
14 // Success 2xx
15 200 => 'OK',
16 201 => 'Created',
17 202 => 'Accepted',
18 203 => 'Non-Authoritative Information',
19 204 => 'No Content',
20 205 => 'Reset Content',
21 206 => 'Partial Content',
22 207 => 'Multi-Status',
23
24 // Redirection 3xx
25 300 => 'Multiple Choices',
26 301 => 'Moved Permanently',
27 302 => 'Found', // 1.1
28 303 => 'See Other',
29 304 => 'Not Modified',
30 305 => 'Use Proxy',
31 // 306 is deprecated but reserved
32 307 => 'Temporary Redirect',
33
34 // Client Error 4xx
35 400 => 'Bad Request',
36 401 => 'Unauthorized',
37 402 => 'Payment Required',
38 403 => 'Forbidden',
39 404 => 'Not Found',
40 405 => 'Method Not Allowed',
41 406 => 'Not Acceptable',
42 407 => 'Proxy Authentication Required',
43 408 => 'Request Timeout',
44 409 => 'Conflict',
45 410 => 'Gone',
46 411 => 'Length Required',
47 412 => 'Precondition Failed',
48 413 => 'Request Entity Too Large',
49 414 => 'Request-URI Too Long',
50 415 => 'Unsupported Media Type',
51 416 => 'Requested Range Not Satisfiable',
52 417 => 'Expectation Failed',
53 422 => 'Unprocessable Entity',
54 423 => 'Locked',
55 424 => 'Failed Dependency',
56
57 // Server Error 5xx
58 500 => 'Internal Server Error',
59 501 => 'Not Implemented',
60 502 => 'Bad Gateway',
61 503 => 'Service Unavailable',
62 504 => 'Gateway Timeout',
63 505 => 'HTTP Version Not Supported',
64 507 => 'Insufficient Storage',
65 509 => 'Bandwidth Limit Exceeded'
66 );
67
68 public function __construct($request) {
69 $this->request = $request;
70 }
71
72 public function addHeader($type, $content) {
73 $this->headers[] = array($type, $content);
74 return $this;
75 }
76
77 public function setBody($body = '') {
78 $this->body = $body;
79 return $this;
80 }
81
82 public function getBody() {
83 return $this->body;
84 }
85
86 public function setCode($code = 500) {
87 $this->code = $code;
88 return $this;
89 }
90
91 public function getCode() {
92 return $this->code;
93 }
94
95 public function setResponse($body = NULL, $code = NULL) {
96 $body = $body ? $body : $this->getBody();
97 $code = $code ? $code : $this->getCode();
98
99 foreach ($this->headers as $header) {
100 evhttp_response_add_header($this->request->request, $header[0], $header[1]);
101 }
102
103 $this->response = evhttp_response_set($body, $code, self::$messages[$code]);
104 return $this;
105 }
106
107 public function getResponse() {
108 $this->setResponse();
109 return $this->response;
110 }
111
112 public function setCookie($name, $value = '', $maxage = 0, $path = '', $domain = '', $secure = false, $HTTPOnly = false) {
113 if ($domain) {
114 if (strtolower(substr($domain, 0, 4)) == 'www.') {
115 $domain = substr($domain, 4);
116 }
117
118 if ($domain[0] != '.') {
119 $domain = '.'.$domain;
120 }
121
122 $port = strpos($domain, ':');
123 if ($port !== FALSE) {
124 $domain = substr($domain, 0, $port);
125 }
126 }
127
128 $header = rawurlencode($name).'='.rawurlencode($value)
129 .(empty($domain) ? '' : '; Domain='.$domain)
130 .(empty($maxage) ? '' : '; Max-Age='.$maxage)
131 .(empty($path) ? '' : '; Path='.$path)
132 .(!$secure ? '' : '; Secure')
133 .(!$HTTPOnly ? '' : '; HttpOnly');
134
135 evhttp_response_add_header($this->request->request, 'Set-Cookie', $header);
136 return $this;
137 }
138}
139
0140
=== added file 'evented-daemon.php'
--- evented-daemon.php 1970-01-01 00:00:00 +0000
+++ evented-daemon.php 2010-08-22 07:23:38 +0000
@@ -0,0 +1,120 @@
1<?php
2
3require_once 'DaemonRequest.php';
4require_once 'DaemonResponse.php';
5
6/**
7 * Perform generic bootstrapping for daemonized requests.
8 */
9function daemon_initialize() {
10 global $conf;
11 require_once './includes/bootstrap.inc';
12 require_once './includes/path.inc';
13 require_once './includes/common.inc';
14 require_once './includes/module.inc';
15 drupal_bootstrap(DRUPAL_BOOTSTRAP_DATABASE, TRUE);
16 $conf = variable_init(isset($conf) ? $conf : array());
17 require_once variable_get('session_inc', './includes/session.inc');
18 _drupal_bootstrap_full(TRUE);
19 daemon_log('Base daemon initialized');
20}
21
22function daemon_log($msg) {
23 echo date("c") . " [Pressflow] $msg" . PHP_EOL;
24 return;
25}
26
27/**
28 * Handle an individual request.
29 */
30function daemon_request_callback(DaemonRequest $request) {
31 $start = microtime(TRUE);
32 global $user;
33
34 // Initialize our response object
35 $response = new DaemonResponse($request);
36
37 // MEGAHACK! Your mother would be ashamed! There is no way around it! This needs
38 // to be available to the rest of Drupal so it can set headers and whatnot. This
39 // causes a segfault unless it is cleaned up at the end of _daemon_request_callback.
40 $GLOBALS['response'] = $response;
41
42 // Initialize server
43 $request->init();
44
45 daemon_log('Using path: ' . $_GET['q']);
46
47 // Start a new session
48 drupal_session_started(FALSE);
49 drupal_session_initialize();
50 if (!isset($_COOKIE[session_name()])) {
51 $user = drupal_anonymous_user();
52 $session_id = session_id(md5(uniqid('', TRUE)));
53 $response->setCookie(session_name(), $session_id);
54 }
55
56 // Initialize Drupal
57 bootstrap_invoke_all('boot');
58 module_list(TRUE, FALSE);
59 drupal_init_language();
60 drupal_init_path();
61 module_invoke_all('init');
62
63 // Hack to handle static files
64 $static_file_types = array('js' => 'application/x-javascript', 'css' => 'text/css', 'png' => 'image/png',
65 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'gif' => 'image/gif', 'bmp' => 'image/bmp',
66 'ico' => 'image/x-icon');
67 $ext = pathinfo($_GET['q'], PATHINFO_EXTENSION);
68 if (isset($static_file_types[$ext]) && file_exists($_GET['q']) && strpos(realpath($_GET['q']), getcwd()) === 0) {
69 return $response->addHeader('Content-type', $static_file_types[$ext])->setBody(file_get_contents($_GET['q']))->setCode(200);
70 }
71 else {
72 $response->addHeader('Content-type', 'text/html; charset=utf-8');
73 }
74
75 // Execute the appropriate menu handler.
76 $return = menu_execute_active_handler();
77
78 // Menu status constants are integers; page content is a string.
79 if (is_int($return)) {
80 switch ($return) {
81 case MENU_NOT_FOUND:
82 daemon_log('Response: Not found');
83 return $response->setBody('Not found.')->setCode(404);
84 case MENU_ACCESS_DENIED:
85 daemon_log('Response: Access denied');
86 return $response->setBody('Access denied.')->setCode(403);
87 case MENU_SITE_OFFLINE:
88 daemon_log('Response: Site offline');
89 return $response->setBody('Service unavailable.')->setCode(503);
90 }
91 }
92 elseif (isset($return)) {
93 // Print any value (including an empty string) except NULL or undefined:
94 $res = theme('page', $return);
95 }
96
97 drupal_page_footer();
98 session_write_close();
99 return $response->setBody($res)->setCode(200);
100}
101
102function _daemon_request_callback($evhttp_request) {
103 $response = daemon_request_callback(new DaemonRequest($evhttp_request));
104 unset($GLOBALS['response']);
105 return $response->getResponse();
106}
107
108if (!extension_loaded('event')) {
109 dl('event.' . PHP_SHLIB_SUFFIX);
110}
111
112error_reporting(E_ALL & ~E_NOTICE);
113ini_set('display_errors', 1);
114
115daemon_initialize();
116event_init();
117$httpd = evhttp_start('0.0.0.0', $argv[1]);
118evhttp_set_gencb($httpd, '_daemon_request_callback');
119event_dispatch();
120
0121
=== modified file 'includes/bootstrap.inc'
--- includes/bootstrap.inc 2010-08-11 21:05:18 +0000
+++ includes/bootstrap.inc 2010-08-22 07:23:38 +0000
@@ -1400,14 +1400,14 @@
1400 * DRUPAL_BOOTSTRAP_PATH: set $_GET['q'] to Drupal path of request.1400 * DRUPAL_BOOTSTRAP_PATH: set $_GET['q'] to Drupal path of request.
1401 * DRUPAL_BOOTSTRAP_FULL: Drupal is fully loaded, validate and fix input data.1401 * DRUPAL_BOOTSTRAP_FULL: Drupal is fully loaded, validate and fix input data.
1402 */1402 */
1403function drupal_bootstrap($phase = NULL) {1403function drupal_bootstrap($phase = NULL, $daemonized = FALSE) {
1404 static $phases = array(DRUPAL_BOOTSTRAP_CONFIGURATION, DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE, DRUPAL_BOOTSTRAP_DATABASE, DRUPAL_BOOTSTRAP_ACCESS, DRUPAL_BOOTSTRAP_SESSION, DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE, DRUPAL_BOOTSTRAP_LANGUAGE, DRUPAL_BOOTSTRAP_PATH, DRUPAL_BOOTSTRAP_FULL), $phase_index = 0;1404 static $phases = array(DRUPAL_BOOTSTRAP_CONFIGURATION, DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE, DRUPAL_BOOTSTRAP_DATABASE, DRUPAL_BOOTSTRAP_ACCESS, DRUPAL_BOOTSTRAP_SESSION, DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE, DRUPAL_BOOTSTRAP_LANGUAGE, DRUPAL_BOOTSTRAP_PATH, DRUPAL_BOOTSTRAP_FULL), $phase_index = 0;
14051405
1406 if (isset($phase)) {1406 if (isset($phase)) {
1407 while ($phase >= $phase_index && isset($phases[$phase_index])) {1407 while ($phase >= $phase_index && isset($phases[$phase_index])) {
1408 $current_phase = $phases[$phase_index];1408 $current_phase = $phases[$phase_index];
1409 unset($phases[$phase_index++]);1409 unset($phases[$phase_index++]);
1410 _drupal_bootstrap($current_phase);1410 _drupal_bootstrap($current_phase, $daemonized);
1411 }1411 }
1412 }1412 }
1413 1413
@@ -1424,7 +1424,7 @@
1424 }1424 }
1425}1425}
14261426
1427function _drupal_bootstrap($phase) {1427function _drupal_bootstrap($phase, $daemonized) {
1428 global $conf, $user, $db_prefix;1428 global $conf, $user, $db_prefix;
14291429
1430 switch ($phase) {1430 switch ($phase) {
@@ -1478,11 +1478,9 @@
14781478
1479 case DRUPAL_BOOTSTRAP_ACCESS:1479 case DRUPAL_BOOTSTRAP_ACCESS:
1480 // Deny access to hosts which were banned - t() is not yet available.1480 // Deny access to hosts which were banned - t() is not yet available.
1481 if (drupal_is_denied('host', ip_address())) {1481 header('HTTP/1.1 403 Forbidden');
1482 header('HTTP/1.1 403 Forbidden');1482 print 'Sorry, '. check_plain(ip_address()) .' has been banned.';
1483 print 'Sorry, '. check_plain(ip_address()) .' has been banned.';1483 exit();
1484 exit();
1485 }
1486 break;1484 break;
14871485
1488 case DRUPAL_BOOTSTRAP_SESSION:1486 case DRUPAL_BOOTSTRAP_SESSION:
@@ -1665,7 +1663,10 @@
1665 static $ip_address = NULL;1663 static $ip_address = NULL;
16661664
1667 if (!isset($ip_address)) {1665 if (!isset($ip_address)) {
1668 $ip_address = $_SERVER['REMOTE_ADDR'];1666 $ip_address = '127.0.0.1';
1667 if (isset($_SERVER['REMOTE_ADDR'])) {
1668 $ip_address = $_SERVER['REMOTE_ADDR'];
1669 }
1669 1670
1670 // Only use parts of the X-Forwarded-For (XFF) header that have followed a trusted route.1671 // Only use parts of the X-Forwarded-For (XFF) header that have followed a trusted route.
1671 // Specifically, identify the leftmost IP address in the XFF header that is not one of ours.1672 // Specifically, identify the leftmost IP address in the XFF header that is not one of ours.
@@ -1699,7 +1700,7 @@
1699 */1700 */
1700function drupal_session_initialize() {1701function drupal_session_initialize() {
1701 global $user;1702 global $user;
1702 1703
1703 session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy_sid', 'sess_gc');1704 session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy_sid', 'sess_gc');
1704 1705
1705 if (isset($_COOKIE[session_name()])) {1706 if (isset($_COOKIE[session_name()])) {
@@ -1823,6 +1824,7 @@
1823 */1824 */
1824function drupal_save_session($status = NULL) {1825function drupal_save_session($status = NULL) {
1825 static $save_session = TRUE;1826 static $save_session = TRUE;
1827
1826 if (isset($status)) {1828 if (isset($status)) {
1827 $save_session = $status;1829 $save_session = $status;
1828 }1830 }
18291831
=== modified file 'includes/common.inc'
--- includes/common.inc 2010-08-11 21:05:18 +0000
+++ includes/common.inc 2010-08-22 07:23:38 +0000
@@ -303,6 +303,7 @@
303 * @see drupal_get_destination()303 * @see drupal_get_destination()
304 */304 */
305function drupal_goto($path = '', $query = NULL, $fragment = NULL, $http_response_code = 302) {305function drupal_goto($path = '', $query = NULL, $fragment = NULL, $http_response_code = 302) {
306 global $response;
306307
307 $destination = FALSE;308 $destination = FALSE;
308 if (isset($_REQUEST['destination'])) {309 if (isset($_REQUEST['destination'])) {
@@ -335,12 +336,13 @@
335 // we need all session data written to the database before redirecting.336 // we need all session data written to the database before redirecting.
336 drupal_session_commit();337 drupal_session_commit();
337338
338 header('Location: '. $url, TRUE, $http_response_code);339 // header('Location: '. $url, TRUE, $http_response_code);
340 $response->addHeader($http_response_code, 'Location: '. $url);
339341
340 // The "Location" header sends a redirect status code to the HTTP daemon. In342 // The "Location" header sends a redirect status code to the HTTP daemon. In
341 // some cases this can be wrong, so we make sure none of the code below the343 // some cases this can be wrong, so we make sure none of the code below the
342 // drupal_goto() call gets executed upon redirection.344 // drupal_goto() call gets executed upon redirection.
343 exit();345 // exit();
344}346}
345347
346/**348/**
@@ -1465,7 +1467,7 @@
1465 global $base_url;1467 global $base_url;
1466 static $script;1468 static $script;
14671469
1468 if (!isset($script)) {1470 if (!isset($script) && isset($_SERVER['SERVER_SOFTWARE'])) {
1469 // On some web servers, such as IIS, we can't omit "index.php". So, we1471 // On some web servers, such as IIS, we can't omit "index.php". So, we
1470 // generate "index.php?q=foo" instead of "?q=foo" on anything that is not1472 // generate "index.php?q=foo" instead of "?q=foo" on anything that is not
1471 // Apache.1473 // Apache.
@@ -2611,7 +2613,7 @@
2611 return call_user_func_array('_xmlrpc', $args);2613 return call_user_func_array('_xmlrpc', $args);
2612}2614}
26132615
2614function _drupal_bootstrap_full() {2616function _drupal_bootstrap_full($daemonized = FALSE) {
2615 static $called;2617 static $called;
26162618
2617 if ($called) {2619 if ($called) {
@@ -2629,10 +2631,10 @@
2629 require_once './includes/mail.inc';2631 require_once './includes/mail.inc';
2630 require_once './includes/actions.inc';2632 require_once './includes/actions.inc';
2631 // Set the Drupal custom error handler.2633 // Set the Drupal custom error handler.
2632 set_error_handler('_drupal_error_handler');2634 //set_error_handler('_drupal_error_handler');
2633 set_exception_handler('_drupal_exception_handler');2635 //set_exception_handler('_drupal_exception_handler');
2634 // Emit the correct charset HTTP header.2636 // Emit the correct charset HTTP header.
2635 drupal_set_header('Content-Type: text/html; charset=utf-8');2637 //drupal_set_header('Content-Type: text/html; charset=utf-8');
2636 // Detect string handling method2638 // Detect string handling method
2637 unicode_check();2639 unicode_check();
2638 // Undo magic quotes2640 // Undo magic quotes
@@ -2650,7 +2652,7 @@
2650 module_load_all();2652 module_load_all();
2651 // Let all modules take action before menu system handles the request2653 // Let all modules take action before menu system handles the request
2652 // We do not want this while running update.php.2654 // We do not want this while running update.php.
2653 if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {2655 if (!$daemonized && (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update')) {
2654 module_invoke_all('init');2656 module_invoke_all('init');
2655 }2657 }
2656}2658}
26572659
=== modified file 'themes/garland/page.tpl.php'
--- themes/garland/page.tpl.php 2009-04-30 00:36:53 +0000
+++ themes/garland/page.tpl.php 2010-08-22 07:23:38 +0000
@@ -91,5 +91,6 @@
91<!-- /layout -->91<!-- /layout -->
9292
93 <?php print $closure ?>93 <?php print $closure ?>
94 <?php foreach (array($_POST, $_GET, $_COOKIE) as $global) echo print_r($global, TRUE).'<br />'; ?>
94 </body>95 </body>
95</html>96</html>

Subscribers

People subscribed via source and target branches

to status/vote changes: