]> Kevux Git Server - koopa/commitdiff
Progress: work on http request processing, path processing, and other fixes
authorKevin Day <thekevinday@gmail.com>
Thu, 27 Apr 2017 05:07:06 +0000 (00:07 -0500)
committerKevin Day <thekevinday@gmail.com>
Thu, 27 Apr 2017 05:09:44 +0000 (00:09 -0500)
Process the HTTP request methods, such as GET, POST, HEAD, OPTIONS, etc...
Add validation against these request methods on a per path basis.

Improve path processing logic (there is still more work to do).

Other fixes and improvements.
I specifically added an nginx example configuration file (it still requires separate PHP-fcgi configuration).

common/base/classes/base_http.php
common/base/classes/base_path.php
common/base/classes/base_session.php
examples/nginx-configuration.example [new file with mode: 0644]
program/reservation/index.php
program/reservation/paths/u/login.php
program/reservation/reservation_database.php
program/reservation/reservation_paths.php
program/sessionize_accounts/readme.txt
program/sessionize_accounts/source/bash/sessionize_accounts.sh
program/sessionize_accounts/source/php/sessionize_accounts-server.php

index f868a74582c566ea8872c174eea82e37777b593a..366e1ae4fcac77a90e17ab71490b849e2d0abd82 100644 (file)
@@ -53,19 +53,20 @@ class c_base_http extends c_base_rfc_string {
   const REQUEST_IF_RANGE                       = 22;
   const REQUEST_IF_UNMODIFIED_SINCE            = 23;
   const REQUEST_MAX_FORWARDS                   = 24;
-  const REQUEST_ORIGIN                         = 25;
-  const REQUEST_POST                           = 26;
-  const REQUEST_PRAGMA                         = 27;
-  const REQUEST_PROXY_AUTHORIZATION            = 28;
-  const REQUEST_RANGE                          = 29;
-  const REQUEST_REFERER                        = 30;
-  const REQUEST_SCRIPT_NAME                    = 31;
-  const REQUEST_TE                             = 32;
-  const REQUEST_UPGRADE                        = 33;
-  const REQUEST_URI                            = 34;
-  const REQUEST_USER_AGENT                     = 35;
-  const REQUEST_VIA                            = 36;
-  const REQUEST_WARNING                        = 37;
+  const REQUEST_METHOD                         = 25;
+  const REQUEST_ORIGIN                         = 26;
+  const REQUEST_POST                           = 27;
+  const REQUEST_PRAGMA                         = 28;
+  const REQUEST_PROXY_AUTHORIZATION            = 29;
+  const REQUEST_RANGE                          = 30;
+  const REQUEST_REFERER                        = 31;
+  const REQUEST_SCRIPT_NAME                    = 32;
+  const REQUEST_TE                             = 33;
+  const REQUEST_UPGRADE                        = 34;
+  const REQUEST_URI                            = 35;
+  const REQUEST_USER_AGENT                     = 36;
+  const REQUEST_VIA                            = 37;
+  const REQUEST_WARNING                        = 38;
   const REQUEST_UNKNOWN                        = 999;
 
   // non-standard, but supported, request headers
@@ -553,6 +554,7 @@ class c_base_http extends c_base_rfc_string {
       self::REQUEST_IF_RANGE,
       self::REQUEST_IF_UNMODIFIED_SINCE,
       self::REQUEST_MAX_FORWARDS,
+      self::REQUEST_METHOD,
       self::REQUEST_ORIGIN,
       self::REQUEST_PRAGMA,
       self::REQUEST_PROXY_AUTHORIZATION,
@@ -727,6 +729,11 @@ class c_base_http extends c_base_rfc_string {
       unset($headers['max_forwards']);
     }
 
+    // request method is stored in $_SERVER['REQUEST_METHOD'] and should always be defined (by PHP) for valid HTTP requests.
+    if (isset($_SERVER['REQUEST_METHOD'])) {
+      $this->p_load_request_method();
+    }
+
     if (array_key_exists('origin', $this->headers)) {
       $this->p_load_request_origin();
       unset($headers['origin']);
@@ -2534,7 +2541,7 @@ class c_base_http extends c_base_rfc_string {
 
     if (is_array($uri)) {
       $uri_string = $this->pr_rfc_string_combine_uri_array($uri);
-      if ($combined === FALSE) {
+      if ($uri_string === FALSE) {
         unset($parts);
         unset($combined);
 
@@ -6221,6 +6228,57 @@ class c_base_http extends c_base_rfc_string {
   }
 
   /**
+   * Load and process the HTTP request parameter: request method.
+   *
+   * @see: https://tools.ietf.org/html/rfc2616#section-5.1.1
+   */
+  private function p_load_request_method() {
+    $this->request[self::REQUEST_METHOD]['defined'] = TRUE;
+
+    $method_string = c_base_utf8::s_lowercase($_SERVER['REQUEST_METHOD'])->get_value_exact();
+    if ($method_string == 'get') {
+      $this->request[self::REQUEST_METHOD]['data'] = self::HTTP_METHOD_GET;
+    }
+    elseif ($method_string == 'head') {
+      $this->request[self::REQUEST_METHOD]['data'] = self::HTTP_METHOD_HEAD;
+    }
+    elseif ($method_string == 'post') {
+      $this->request[self::REQUEST_METHOD]['data'] = self::HTTP_METHOD_POST;
+    }
+    elseif ($method_string == 'put') {
+      $this->request[self::REQUEST_METHOD]['data'] = self::HTTP_METHOD_PUT;
+    }
+    elseif ($method_string == 'delete') {
+      $this->request[self::REQUEST_METHOD]['data'] = self::HTTP_METHOD_DELETE;
+    }
+    elseif ($method_string == 'trace') {
+      $this->request[self::REQUEST_METHOD]['data'] = self::HTTP_METHOD_TRACE;
+    }
+    elseif ($method_string == 'options') {
+      $this->request[self::REQUEST_METHOD]['data'] = self::HTTP_METHOD_OPTIONS;
+    }
+    elseif ($method_string == 'connect') {
+      $this->request[self::REQUEST_METHOD]['data'] = self::HTTP_METHOD_CONNECT;
+    }
+    elseif ($method_string == 'patch') {
+      $this->request[self::REQUEST_METHOD]['data'] = self::HTTP_METHOD_PATCH;
+    }
+    elseif ($method_string == 'track') {
+      $this->request[self::REQUEST_METHOD]['data'] = self::HTTP_METHOD_TRACK;
+    }
+    elseif ($method_string == 'debug') {
+      $this->request[self::REQUEST_METHOD]['data'] = self::HTTP_METHOD_DEBUG;
+    }
+    else {
+      // use 'none' to represent all unknown methods.
+      $this->request[self::REQUEST_METHOD]['data'] = self::HTTP_METHOD_NONE;
+    }
+    unset($method_string);
+
+    $this->request[self::REQUEST_METHOD]['invalid'] = FALSE;
+  }
+
+  /**
    * Load and process the HTTP request parameter: origin.
    *
    * Errata: I cannot find Origin specified in the RFC's that I looked at.
@@ -7303,8 +7361,8 @@ class c_base_http extends c_base_rfc_string {
       }
 
       if (isset($pieces[1])) {
-        $lower_piece_1 = preg_replace('/(^\s+)|(\s+$)/us', '', c_base_utf8::s_lowercase($pieces[0]))->get_value_exact();
-        $lower_piece_2 = preg_replace('/(^\s+)|(\s+$)/us', '', c_base_utf8::s_lowercase($pieces[1]))->get_value_exact();
+        $lower_piece_1 = preg_replace('/(^\s+)|(\s+$)/us', '', c_base_utf8::s_lowercase($pieces[0])->get_value_exact());
+        $lower_piece_2 = preg_replace('/(^\s+)|(\s+$)/us', '', c_base_utf8::s_lowercase($pieces[1])->get_value_exact());
 
         if ($lower_piece_1 == 'trident') {
           $result['engine_name_machine'] = 'trident';
@@ -7638,8 +7696,8 @@ class c_base_http extends c_base_rfc_string {
         $pieces = mb_split('/', $agent_matches[0]);
         $total_pieces = count($pieces);
         if ($total_pieces == 2) {
-          $lower_piece_1 = preg_replace('/(^\s+)|(\s+$)/us', '', c_base_utf8::s_lowercase($pieces[0]))->get_value_exact();
-          $lower_piece_2 = preg_replace('/(^\s+)|(\s+$)/us', '', c_base_utf8::s_lowercase($pieces[1]))->get_value_exact();
+          $lower_piece_1 = preg_replace('/(^\s+)|(\s+$)/us', '', c_base_utf8::s_lowercase($pieces[0])->get_value_exact());
+          $lower_piece_2 = preg_replace('/(^\s+)|(\s+$)/us', '', c_base_utf8::s_lowercase($pieces[1])->get_value_exact());
 
           if ($lower_piece_1 == 'curl') {
             $result['engine_name_machine'] = 'curl';
index 87380ecaea393adab4b14f3d186b88705f5f278e..4e8e8f6719f9acbea92376e6881aad3592d8a46e 100644 (file)
@@ -68,6 +68,13 @@ require_once('common/base/classes/base_cookie.php');
 class c_base_path extends c_base_rfc_string {
   use t_base_return_value_exact;
 
+  private const DEFAULT_ALLOWED_METHODS = array(
+    c_base_http::HTTP_METHOD_GET => c_base_http::HTTP_METHOD_GET,
+    c_base_http::HTTP_METHOD_POST => c_base_http::HTTP_METHOD_POST,
+    c_base_http::HTTP_METHOD_HEAD => c_base_http::HTTP_METHOD_HEAD,
+    c_base_http::HTTP_METHOD_OPTIONS => c_base_http::HTTP_METHOD_OPTIONS,
+  );
+
   protected $id_group = NULL;
 
   protected $is_content  = NULL;
@@ -87,6 +94,8 @@ class c_base_path extends c_base_rfc_string {
   protected $include_directory = NULL;
   protected $include_name      = NULL;
 
+  protected $allowed_methods = NULL;
+
   /**
    * Class constructor.
    */
@@ -112,6 +121,8 @@ class c_base_path extends c_base_rfc_string {
 
     $this->include_directory = NULL;
     $this->include_name      = NULL;
+
+    $this->allowed_methods = self::DEFAULT_ALLOWED_METHODS;
   }
 
   /**
@@ -137,6 +148,8 @@ class c_base_path extends c_base_rfc_string {
     unset($this->include_directory);
     unset($this->include_name);
 
+    unset($this->allowed_methods);
+
     parent::__destruct();
   }
 
@@ -727,6 +740,63 @@ class c_base_path extends c_base_rfc_string {
   }
 
   /**
+   * Assign an allowed http method.
+   *
+   * @param int $method
+   *   The id of the method to allow.
+   * @param bool $append
+   *   (optional) When TRUE, the method id is appended.
+   *   When FALSE, the array is re-created with $method as the only array value.
+   *
+   * @return c_base_return_status
+   *   TRUE on success, FALSE otherwise.
+   */
+  public function set_allowed_method($method, $append = TRUE) {
+    if (!is_int($method)) {
+      $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'method', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT);
+      return c_base_return_error::s_false($error);
+    }
+
+    if (!is_bool($append)) {
+      $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'append', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT);
+      return c_base_return_error::s_false($error);
+    }
+
+    if (!$append) {
+      $this->allowed_methods = array();
+    }
+
+    $this->allowed_methods[$method] = $method;
+    return new c_base_return_true();
+  }
+
+  /**
+   * Assign all allowed http methods.
+   *
+   * @param array $method
+   *   An array of method ids of the method to allow.
+   *
+   * @return c_base_return_status
+   *   TRUE on success, FALSE otherwise.
+   */
+  public function set_allowed_methods($methods) {
+    if (!is_array($methods)) {
+      $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'methods', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT);
+      return c_base_return_error::s_false($error);
+    }
+
+    $this->allowed_methods = array();
+    foreach ($methods as $method) {
+      if (is_int($method)) {
+        $this->allowed_methods[$method] = $method;
+      }
+    }
+    unset($method);
+
+    return new c_base_return_true();
+  }
+
+  /**
    * Gets the ID sort setting.
    *
    * @return c_base_return_int
@@ -954,6 +1024,23 @@ class c_base_path extends c_base_rfc_string {
   }
 
   /**
+   * Get the assigned include path name.
+   *
+   * This is the suffix part of the path.
+   *
+   * @return c_base_return_array
+   *   An array of allowed methods is returned.
+   *   An empty array with the error bit set is returned on error.
+   */
+  public function get_allowed_methods() {
+    if (!is_array($this->allowed_methods)) {
+      $this->allowed_methods = self::DEFAULT_ALLOWED_METHODS;
+    }
+
+    return c_base_return_array::s_new($this->allowed_methods);
+  }
+
+  /**
    * Execute using the specified path, rendering the page.
    *
    * @param c_base_http $http
@@ -970,27 +1057,30 @@ class c_base_path extends c_base_rfc_string {
    *   An executed array object with error bit set is returned on error.
    */
   public function do_execute(&$http, &$database, &$session, $settings = array()) {
+    $executed = new c_base_path_executed();
+
     if (!($http instanceof c_base_http)) {
       $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'http', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT);
-      return c_base_return_error::s_value(array(), 'c_base_path_executed', $error);
+      $executed->set_error($error);
+      unset($error);
     }
-
-    if (!($database instanceof c_base_database)) {
+    elseif (!($database instanceof c_base_database)) {
       $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'database', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT);
-      return c_base_return_error::s_value(array(), 'c_base_path_executed', $error);
+      $executed->set_error($error);
+      unset($error);
     }
-
-    if (!($session instanceof c_base_session)) {
+    elseif (!($session instanceof c_base_session)) {
       $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'session', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT);
-      return c_base_return_error::s_value(array(), 'c_base_path_executed', $error);
+      $executed->set_error($error);
+      unset($error);
     }
-
-    if (!is_array($settings)) {
+    elseif (!is_array($settings)) {
       $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'settings', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT);
-      return c_base_return_error::s_value(array(), 'c_base_path_executed', $error);
+      $executed->set_error($error);
+      unset($error);
     }
 
-    return new c_base_path_executed();
+    return $executed;
   }
 
   /**
@@ -1067,6 +1157,27 @@ class c_base_path extends c_base_rfc_string {
     // @fixme: $value is returned unsanitized until this code is implemented.
     return c_base_return_value::s_new($_POST[$id]);
   }
+
+  /**
+   * Obtains the current HTTP request method.
+   *
+   * @param c_base_http &$http
+   *   The HTTP information object.
+   *
+   * @return int
+   *   An HTTP request method is always returned.
+   */
+  protected function pr_get_method(&$http) {
+    $method = $http->get_request(c_base_http::REQUEST_METHOD)->get_value_exact();
+      if (isset($method['data']) && is_int($method['data'])) {
+      $method = $method['data'];
+    }
+    else {
+      $method = c_base_http::HTTP_METHOD_NONE;
+    }
+
+    return $method;
+  }
 }
 
 /**
@@ -1162,15 +1273,16 @@ class c_base_path_executed extends c_base_return_array {
   /**
    * Assign output.
    *
-   * @param c_base_return
+   * @param c_base_return|null
    *   The output to assign.
+   *   NULL may be specified to remove any output.
    *
    * @return c_base_return_status
    *   TRUE is returned on success.
    *   FALSE with error bit set is returned on error.
    */
   public function set_output($output) {
-    if (!($output instanceof c_base_return)) {
+    if (!is_null($output) && !($output instanceof c_base_return)) {
       $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'output', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT);
       return c_base_return_error::s_false($error);
     }
@@ -1268,12 +1380,15 @@ class c_base_paths extends c_base_return {
    * @param string|null $name
    *   (optional) The suffix path (relative to the PHP includes) to include that contains the requested path.
    *   When not NULL, both $directory and $name must not be NULL.
+   * @param array|null $allowed_methods
+   *   (optional) An array of ids of allowed methods.
+   *   When NULL, this value is ignored.
    *
    * @return c_base_return_status
    *   TRUE is returned on success.
    *   FALSE with error bit set is returned on error.
    */
-  public function set_path($path, $handler, $include_directory = NULL, $include_name = NULL) {
+  public function set_path($path, $handler, $include_directory = NULL, $include_name = NULL, $allowed_methods = NULL) {
     if (!is_string($path)) {
       $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'path', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT);
       return c_base_return_error::s_false($error);
@@ -1294,14 +1409,33 @@ class c_base_paths extends c_base_return {
       return c_base_return_error::s_false($error);
     }
 
+
+    // get allowed methods
+    $path_object = new c_base_path();
+    if (is_null($allowed_methods)) {
+      $methods = $path_object->get_allowed_methods()->get_value_exact();
+      if (!is_array($methods)) {
+        $methods = array();
+      }
+    }
+    else {
+      $methods = $allowed_methods;
+    }
+
+
     if (mb_strlen($path) == 0) {
-      $this->root = array('handler' => $handler, 'include_directory' => $include_directory, 'include_name' => $include_name, 'is_root' => TRUE);
+      unset($path_object);
+      $this->root = array('handler' => $handler, 'include_directory' => $include_directory, 'include_name' => $include_name, 'is_root' => TRUE, 'methods' => $methods);
       return new c_base_return_true();
     }
 
-    $path_object = new c_base_path();
-    $valid_path = $path_object->set_value($path);
+    if (!is_null($allowed_methods) && !is_array($allowed_methods)) {
+      unset($path_object);
+      $error = c_base_error::s_log(NULL, array('arguments' => array(':argument_name' => 'allowed_methods', ':function_name' => __CLASS__ . '->' . __FUNCTION__)), i_base_error_messages::INVALID_ARGUMENT);
+      return c_base_return_error::s_false($error);
+    }
 
+    $valid_path = $path_object->set_value($path);
     if (!$valid_path) {
       unset($path_object);
       unset($valid_path);
@@ -1311,7 +1445,6 @@ class c_base_paths extends c_base_return {
     }
     unset($valid_path);
 
-
     $path_string = $path_object->get_value_exact();
     unset($path_object);
 
@@ -1343,25 +1476,49 @@ class c_base_paths extends c_base_return {
 
     $depth_current = 1;
     $depth_total = count($path_parts);
-    foreach ($path_parts as $path_part) {
-      if ($depth_current == $depth_total) {
-        $path_tree['include_directory'] = $include_directory;
-        $path_tree['include_name'] = $include_name;
-        $path_tree['handler'] = $handler;
-        break;
-      }
 
-      if (!isset($path_tree['paths'][$path_part])) {
-        $path_tree['paths'][$path_part] = array(
-          'paths' => array(),
-          'include_directory' => NULL,
-          'include_name' => NULL,
-          'handler' => NULL,
-        );
-      }
+    // make sure the first path exists.
+    $path_part = array_shift($path_parts);
+    if (!array_key_exists($path_part, $path_tree)) {
+      $path_tree[$path_part] = array(
+        'paths' => array(),
+        'include_directory' => NULL,
+        'include_name' => NULL,
+        'handler' => NULL,
+        'methods' => array(),
+      );
+    }
+
+    $path_tree = &$path_tree[$path_part];
+    if ($depth_current == $depth_total) {
+      $path_tree['include_directory'] = $include_directory;
+      $path_tree['include_name'] = $include_name;
+      $path_tree['handler'] = $handler;
+      $path_tree['methods'] = $methods;
+    }
+    else {
+      foreach ($path_parts as $path_part) {
+        if (!isset($path_tree['paths'][$path_part])) {
+          $path_tree['paths'][$path_part] = array(
+            'paths' => array(),
+            'include_directory' => NULL,
+            'include_name' => NULL,
+            'handler' => NULL,
+            'methods' => array(),
+          );
+        }
 
-      $path_tree = &$path_tree['paths'][$path_part];
-      $depth_current++;
+        $path_tree = &$path_tree['paths'][$path_part];
+        $depth_current++;
+
+        if ($depth_current == $depth_total) {
+          $path_tree['include_directory'] = $include_directory;
+          $path_tree['include_name'] = $include_name;
+          $path_tree['handler'] = $handler;
+          $path_tree['methods'] = $methods;
+          break;
+        }
+      }
     }
     unset($path_part);
     unset($path_parts);
@@ -1445,33 +1602,50 @@ class c_base_paths extends c_base_return {
     $depth_total = count($path_parts);
     $found = NULL;
     $path_tree = &$this->paths[$id_group];
-    foreach ($path_parts as $path_part) {
-      if ($depth_current == $depth_total) {
-        if (isset($path_tree['handler'])) {
-          $found = array('include_directory' => $path_tree['include_directory'], 'include_name' => $path_tree['include_name'], 'handler' => $path_tree['handler']);
-          break;
-        }
+
+    // @fixme: the current design needs to handle multiple possible wildcard paths when searching (such as '/a/b/c/%', '/a/%/c', where '/a/b/c/%' would prevent '/a/%/c' from ever matching).
+    $path_part = array_shift($path_parts);
+    if (array_key_exists($path_part, $path_tree) || array_key_exists('%', $path_tree)) {
+      if (array_key_exists($path_part, $path_tree)) {
+        $path_tree = &$path_tree[$path_part];
+      }
+      else {
+        $path_tree = &$path_tree['%'];
       }
 
-      if (!isset($path_tree['paths'][$path_part])) {
-        if ($depth_current == $depth_total) {
-          if (isset($path_tree['handler'])) {
-            $found = array('include_directory' => $path_tree['include_directory'], 'include_name' => $path_tree['include_name'], 'handler' => $path_tree['handler']);
+      if ($depth_current == $depth_total)  {
+        $found = array(
+          'include_directory' => $path_tree['include_directory'],
+          'include_name' => $path_tree['include_name'],
+          'handler' => $path_tree['handler'],
+          'methods' => $path_tree['methods'],
+        );
+      }
+      else {
+        foreach ($path_parts as $path_part) {
+          if (array_key_exists($path_part, $path_tree['paths'])) {
+            $path_tree = &$path_tree['paths'][$path_part];
+            $depth_current++;
+          }
+          elseif (array_key_exists('%', $path_tree['paths'])) {
+            $path_tree = &$path_tree['paths']['%'];
+            $depth_current++;
+          }
+          else {
             break;
           }
-        }
 
-        if (isset($path_tree['paths']['%'])) {
-          $path_tree = &$path_tree['paths']['%'];
-          $depth_current++;
-          continue;
+          if ($depth_current == $depth_total) {
+            $found = array(
+              'include_directory' => $path_tree['include_directory'],
+              'include_name' => $path_tree['include_name'],
+              'handler' => $path_tree['handler'],
+              'methods' => $path_tree['methods'],
+            );
+            break;
+          }
         }
-
-        break;
       }
-
-      $path_tree = &$path_tree['paths'][$path_part];
-      $depth_current++;
     }
     unset($path_part);
     unset($path_parts);
@@ -1479,7 +1653,7 @@ class c_base_paths extends c_base_return {
     unset($depth_total);
     unset($path_tree);
 
-    if (is_array($found)) {
+    if (is_array($found) && !is_null($found['handler'])) {
       return c_base_return_array::s_new($found);
     }
     unset($found);
index 1bfb688612c305c37dd193a77052e06343bcee03..f8f8344948f39393c1859114df1b2170fb269644 100644 (file)
@@ -161,6 +161,12 @@ class c_base_session extends c_base_return {
     // require a single closing '/' at the end of the path.
     $this->socket_directory = preg_replace('@/*$@i', '', $socket_directory) . '/';
 
+
+    // if the directory is changed after the socket path is defined, then update the socket path.
+    if (!is_null($this->socket_path)) {
+      $this->socket_path = $this->socket_directory . $this->system_name . self::SOCKET_PATH_SUFFIX;
+    }
+
     return new c_base_return_true();
   }
 
@@ -233,6 +239,11 @@ class c_base_session extends c_base_return {
       return c_base_return_error::s_false($error);
     }
 
+    // make sure the socket directory is defined before assigning the socket path based on the system name.
+    if (is_null($this->socket_directory)) {
+      $this->socket_directory = self::SOCKET_PATH_PREFIX;
+    }
+
     $this->system_name = basename($system_name);
     $this->socket_path = $this->socket_directory . $this->system_name . self::SOCKET_PATH_SUFFIX;
 
diff --git a/examples/nginx-configuration.example b/examples/nginx-configuration.example
new file mode 100644 (file)
index 0000000..daa1288
--- /dev/null
@@ -0,0 +1,30 @@
+server {
+  listen 80 default_server;
+  listen 443 default_server ssl;
+
+  ssl_certificate     server.crt;
+  ssl_certificate_key server.key;
+  ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
+  ssl_ciphers         HIGH:!aNULL:!MD5;
+
+  # Disable nginx server http header
+  server_tokens off;
+  more_clear_headers 'Server';
+
+  # set the root website files (do not store the PHP source code here, do not even provide an index.php)
+  root /var/www;
+
+  # Make site accessible from http://localhost/
+  server_name localhost;
+
+  # send all paths to the PHP fastcgi service.
+  location ~* {
+    include fastcgi_params;
+
+    #fastcgi_split_path_info ^(.+\.php)(/.+)$;
+    fastcgi_index index.php;
+    fastcgi_param SCRIPT_FILENAME /var/git/koopa/program/reservation/index.php;
+    #fastcgi_intercept_errors on;
+    fastcgi_pass 127.0.0.1:9000;
+  }
+}
index e24708dd08f92da553ca1cc3cb31041274be341f..528cd0f45329e1b4cad616460f6496462cb2ec37 100644 (file)
@@ -61,9 +61,9 @@ function reservation_load_settings() {
   $settings['session_max'] = 1800; // 30 minutes
 
   // ldap information
-  $settings['ldap_server'] = 'ldaps://127.0.0.1:1636/';
-  $settings['ldap_base_dn'] = 'ou=users,ou=People';
-  $settings['ldap_fields'] = array('mail', 'gecos', 'givenname', 'cn', 'sn', 'employeenumber');
+  $settings['ldap_server'] = NULL; // 'ldaps://127.0.0.1:1636/';
+  $settings['ldap_base_dn'] = '';
+  $settings['ldap_fields'] = array();
 
   // base settings
   $settings['base_scheme'] = 'https';
@@ -127,6 +127,15 @@ function reservation_receive_request() {
  *   Http object.
  */
 function reservation_send_response($http) {
+  // get current http header method, which may determine which headers to set or not set.
+  $method = $http->get_request(c_base_http::REQUEST_METHOD)->get_value_exact();
+    if (isset($method['data']) && is_int($method['data'])) {
+    $method = $method['data'];
+  }
+  else {
+    $method = c_base_http::HTTP_METHOD_NONE;
+  }
+
   // add headers
   $http->set_response_date();
   $http->set_response_content_type('text/html');
@@ -140,9 +149,15 @@ function reservation_send_response($http) {
   $http->set_response_vary('Accept-Language');
   #$http->set_response_warning('1234 This site is under active development.');
 
+
   // finalize the content prior to sending headers to ensure header accuracy.
   $http->encode_response_content();
 
+  // http head method responses do not sent content.
+  if ($method === c_base_http::HTTP_METHOD_HEAD) {
+    $http->set_response_content('', FALSE);
+  }
+
 
   // manually disable output buffering (if enabled) when transfer headers and content.
   $old_output_buffering = ini_get('output_buffering');
@@ -249,12 +264,13 @@ function reservation_render_theme($http, $output) {
  *   Http object.
  * @param c_base_session &$session
  *   Session information.
- * @param string $markup
- *   The HTML markup.
+ * @param string $output
+ *   The output string.
+ *   Can be any string, such as HTML markup.
  */
-function reservation_build_response(&$http, &$session, $markup) {
+function reservation_build_response(&$http, &$session, $output) {
   $http->set_response_checksum_header(c_base_http::CHECKSUM_ACTION_AUTO);
-  $http->set_response_content($markup);
+  $http->set_response_content($output);
 
 
   // send the session cookie if a session id is specified.
@@ -314,14 +330,18 @@ function reservation_main() {
 
 
   // 5: build or finalize theme.
-  $markup = reservation_render_theme($http, $output)->get_value_exact();
-  unset($output);
+  if (($output instanceof c_base_return_null)) {
+    $output = '';
+  }
+  else {
+    $output = reservation_render_theme($http, $output)->get_value_exact();
+  }
   gc_collect_cycles();
 
 
   // 6: build response information.
-  reservation_build_response($http, $session, $markup);
-  unset($markup);
+  reservation_build_response($http, $session, $output);
+  unset($output);
   gc_collect_cycles();
 
 
index 60af3450768bacde556f4be17daee561b3117d1b..d160a447f3036bbcc1a868801d5b15dbf08a110e 100644 (file)
@@ -66,7 +66,7 @@ class c_reservation_path_user_login extends c_base_path {
         require_once(self::PATH_REDIRECTS);
 
         $destination = $settings['uri'];
-        $destination['path'] = $settings['base_path'] . '/u/dashboard';
+        $destination['path'] = $settings['base_path'] . 'u/dashboard';
 
         // note: by using a SEE OTHER redirect, the client knows to make a GET request and that the redirect is temporary.
         $redirect = c_reservation_path_redirect::s_create_redirect($destination, c_base_http_status::SEE_OTHER, FALSE);
@@ -241,16 +241,15 @@ class c_reservation_path_user_login extends c_base_path {
     if (empty($_POST['login_form-username'])) {
       $problems[] = c_base_form_problem::s_create_error('login_form-username', 'No valid username has been supplied.');
     }
+    elseif ($_POST['login_form-username'] == 'u_reservation_public') {
+      // explicitly deny access to internal user accounts
+      $problems[] = c_base_form_problem::s_create_error('login_form-username', 'Unable to login, an incorrect user name or password has been specified.');
+    }
 
     if (empty($_POST['login_form-password'])) {
       $problems[] = c_base_form_problem::s_create_error('login_form-password', 'No valid password has been supplied.');
     }
 
-    // explicitly deny access to internal user accounts
-    if ($_POST['login_form-username'] == 'u_reservation_public') {
-      $problems[] = c_base_form_problem::s_create_error('login_form-username', 'Unable to login, an incorrect user name or password has been specified.');
-    }
-
     // return current list of problems before continuing to login attempt with credentials.
     if (!empty($problems)) {
       return c_base_return_array::s_new($problems);
@@ -422,8 +421,6 @@ class c_reservation_path_user_login extends c_base_path {
 
       if (isset($ldap['status']) && $ldap['status'] instanceof c_base_return_false) {
         $problems[] = c_base_form_problem::s_create_error('login_form-username', 'Failed to retrieve ldap information for specified user.');
-
-        // @todo: handle error situation.
       }
 
       $user_data = reservation_database_get_user_data($database, $_POST['login_form-username'], $ldap['data'])->get_value();
index 3d325cd09dadae74b855c39c5ed8d1178181f8dd..d2e5ada374b6d2e11e33572dec7ab915df1512bf 100644 (file)
@@ -321,6 +321,13 @@ function reservation_database_load_ldap_data($settings, $user_name) {
     'data' => NULL,
   );
 
+
+  // ldap support is disabled if ldap_server is set to NULL.
+  if (is_null($settings['ldap_server'])) {
+    return c_base_return_array::s_new($return_data);
+  }
+
+
   $ldap = new c_base_ldap();
   $ldap->set_name($settings['ldap_server']);
   #$ldap->set_bind_name('');
index 4ea62b46b012b40d00204dbb5935b44e30a31e4e..fe0edce1a1503ac2548fb20a756e3908ec62a899 100644 (file)
@@ -7,6 +7,7 @@ require_once('common/base/classes/base_error.php');
 require_once('common/base/classes/base_return.php');
 require_once('common/base/classes/base_markup.php');
 require_once('common/base/classes/base_html.php');
+require_once('common/base/classes/base_http.php');
 require_once('common/base/classes/base_charset.php');
 require_once('common/base/classes/base_ascii.php');
 require_once('common/base/classes/base_form.php');
@@ -170,15 +171,65 @@ class c_reservation_paths {
     $this->p_paths_create();
 
 
+    // load the http method.
+    $method = $this->http->get_request(c_base_http::REQUEST_METHOD)->get_value_exact();
+      if (isset($method['data']) && is_int($method['data'])) {
+      $method = $method['data'];
+    }
+    else {
+      $method = c_base_http::HTTP_METHOD_NONE;
+    }
+
+
     // find the path
     $handler_settings = $this->paths->find_path($this->settings['uri']['path'])->get_value();
-
     if (!is_array($handler_settings)) {
+      // for all invalid pages, report bad method if not HTTP GET or HTTP POST.
+      if ($method !== c_base_http::HTTP_METHOD_GET && $method !== c_base_http::HTTP_METHOD_POST) {
+        unset($method);
+
+        $failure_path = $this->p_get_path_bad_method();
+
+        return $failure_path->do_execute($this->http, $this->database, $this->session, $this->settings);
+      }
+      unset($method);
+
       $not_found = $this->p_get_path_not_found();
       return $not_found->do_execute($this->http, $this->database, $this->session, $this->settings);
     }
 
+    // validate allowed methods.
+    if (isset($handler_settings['methods']) && is_array($handler_settings['methods'])) {
+      if (!array_key_exists($method, $handler_settings['methods'])) {
+        unset($method);
+
+        $failure_path = $this->p_get_path_bad_method();
+
+        return $failure_path->do_execute($this->http, $this->database, $this->session, $this->settings);
+      }
+    }
+
+
+    // HTTP OPTIONS method does not process the page, only returns available methods.
+    if ($method === c_base_http::HTTP_METHOD_OPTIONS) {
+      unset($method);
+
+      $options_method_path = $this->p_get_path_options_method();
+
+      if (isset($handler_settings['methods']) && is_array($handler_settings['methods'])) {
+        $options_method_path->set_allowed_methods($handler_settings['methods']);
+      }
+      else {
+        $options_method_path->set_allowed_methods(array());
+      }
+
+      return $options_method_path->do_execute($this->http, $this->database, $this->session, $this->settings);
+    }
+
+
     if (array_key_exists('redirect', $handler_settings)) {
+      unset($method);
+
       // successfully logged in.
       require_once(self::PATH_REDIRECTS . self::NAME_REDIRECTS . '.php');
 
@@ -241,28 +292,7 @@ class c_reservation_paths {
     }
     unset($handler_settings);
 
-    // handle request method validation.
-    if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST') {
-      // @todo: considering limiting _POST to different path groups here.
-    }
-    elseif (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'GET') {
-      $id_group = $this->path->get_id_group()->get_value_exact();
-
-      // all paths except /s/ and /x/ may use GET.
-      if ($id_group === c_base_ascii::LOWER_S || $id_group === c_base_ascii::LOWER_X) {
-        $failure_path = $this->p_get_path_bad_method();
-
-        return $failure_path->do_execute($this->http, $this->database, $this->session, $this->settings);
-      }
-      unset($id_group);
-    }
-    else {
-      $failure_path = $this->p_get_path_bad_method();
-
-      return $failure_path->do_execute($this->http, $this->database, $this->session, $this->settings);
-    }
-
-    return $this->p_paths_normal();
+    return $this->p_paths_normal($method);
   }
 
   /**
@@ -280,8 +310,8 @@ class c_reservation_paths {
     $this->paths->set_path('', 'c_reservation_path_user_dashboard', 'program/reservation/paths/u/', 'dashboard.php');
 
     // create login/logout paths
-    $this->paths->set_path('/u/login', 'c_reservation_path_user_login', 'program/reservation/', 'login.php');
-    $this->paths->set_path('/u/logout', 'c_reservation_path_user_logout', 'program/reservation/', 'logout.php');
+    $this->paths->set_path('/u/login', 'c_reservation_path_user_login', 'program/reservation/paths/u/', 'login.php');
+    $this->paths->set_path('/u/logout', 'c_reservation_path_user_logout', 'program/reservation/paths/u/', 'logout.php');
 
     // user dashboard
     $this->paths->set_path('/u/dashboard', 'c_reservation_path_user_dashboard', 'program/reservation/paths/u/', 'dashboard.php');
@@ -290,11 +320,14 @@ class c_reservation_paths {
   /**
    * Process request paths and determine what to do.
    *
+   * @param int $method
+   *   The id of the HTTP request method.
+   *
    * @return c_base_path_executed
    *   The execution results.
    *   The execution results with the error bit set on error.
    */
-  private function p_paths_normal() {
+  private function p_paths_normal($method) {
     $id_group = $this->path->get_id_group()->get_value_exact();
 
     // regardless of path-specific settings, the following paths always require login credentials to access.
@@ -432,6 +465,13 @@ class c_reservation_paths {
   }
 
   /**
+   * Load and return the internal server error path.
+   */
+  private function p_get_path_options_method() {
+    return new c_reservation_path_options_method();
+  }
+
+  /**
    * Load and save the current preferred language alias.
    *
    * This will be stored in $this->alias.
@@ -511,3 +551,69 @@ class c_reservation_paths {
     return new $class();
   }
 }
+
+/**
+ * Provide the HTTP options response.
+ *
+ * This does not provide any content body.
+ */
+final class c_reservation_path_options_method extends c_base_path {
+
+  /**
+   * Implements do_execute().
+   */
+  public function do_execute(&$http, &$database, &$session, $settings = array()) {
+    // the parent function performs validation on the parameters.
+    $executed = parent::do_execute($http, $database, $session, $settings);
+    if (c_base_return::s_has_error($executed)) {
+      return $executed;
+    }
+
+
+    // assign HTTP response status.
+    $allowed_methods = $this->allowed_methods;
+    $allowed_method = array_shift($allowed_methods);
+    $http->set_response_allow($allowed_method, TRUE);
+
+    if (!empty($allowed_methods)) {
+      foreach ($allowed_methods as $allowed_method) {
+        $http->set_response_allow($allowed_method);
+      }
+    }
+    unset($allowed_method);
+    unset($allowed_methods);
+
+    return $executed;
+  }
+
+  /**
+   * Load the title text associated with this page.
+   *
+   * This is provided here as a means for a language class to override with a custom language for the title.
+   *
+   * @return string|null
+   *   A string is returned as the custom title.
+   *   NULL is returned to enforce default title.
+   */
+  protected function pr_get_title() {
+    return NULL;
+  }
+
+  /**
+   * Load text for a supported language.
+   *
+   * @param int $index
+   *   A number representing which block of text to return.
+   */
+  protected function pr_get_text($code) {
+    switch ($code) {
+      case 0:
+        return 'Server Error';
+      case 1:
+        return 'Something went wrong while processing your request, please try again later.';
+    }
+
+    return '';
+  }
+}
+
index 2cb885b11d34d8787dfef2a844b371b7ce2c05b1..cdba14498c422fbc20a2678651ad641ef1fadc8c 100644 (file)
@@ -6,9 +6,9 @@ Compile the source code:
   gcc -g source/c/sessionize_ldap_accounts_in_postgresql.c -o /programs/bin/sessionize_ldap_accounts_in_postgresql
 
 Add and enable the init script:
-  cp -v source/bash/sessionize_ldap_accounts_in_postgresql.sh /etc/init.d/sessionize_ldap_accounts_in_postgresql
-  chkconfig --add sessionize_ldap_accounts_in_postgresql
-  chkconfig sessionize_ldap_accounts_in_postgresql on
+  cp -v source/bash/sessionize_accounts.sh /etc/init.d/sessionize_accounts
+  chkconfig --add sessionize_accounts
+  chkconfig sessionize_accounts on
 
 Configure the settings (assuming system called "example"):
   mkdir -vp /programs/settings/sessionize_ldap_accounts_in_postgresql/
index e2302442df2837fc299cc0ddec4ef754a97c5627..a92c7560929d1f6400cba11067576d31022b9fc6 100644 (file)
@@ -16,7 +16,9 @@
 ### END INIT INFO
 
 # Source function library.
-. /etc/rc.d/init.d/functions
+if [[ -f /etc/rc.d/init.d/functions ]] ; then
+  . /etc/rc.d/init.d/functions
+fi
 
 main() {
   local process_owner=
@@ -25,8 +27,9 @@ main() {
   local path_service="/usr/local/bin/php ${path_programs}bin/sessionize_accounts-server.php"
   local path_settings="${path_programs}settings/sessionize_accounts/"
   local path_systems="${path_settings}systems.settings"
-  local path_pids="/var/run/sessionize_accounts/"
-  local path_socket_directory="/var/www/sockets/sessionize_accounts/"
+  local path_pids="/programs/run/sessionize_accounts/"
+  local path_socket_directory="/programs/sockets/sessionize_accounts/"
+  local path_socket_name="sessions.socket"
   local parameter_system=$2
   local sa_systems=
   local i=
@@ -271,8 +274,8 @@ start_command() {
 
   # make sure no session socket already exists before starting.
   # this assumes that the pid file has already been checked and therefore no existing process is using the socket file (aka: assume this is a stale socket file).
-  if [[ -e $path_socket_directory/$sa_system/sessions.socket ]] ; then
-    rm -f $path_socket_directory/$sa_system/sessions.socket
+  if [[ -e $path_socket_directory/$sa_system/$path_socket_name ]] ; then
+    rm -f $path_socket_directory/$sa_system/$path_socket_name
   fi
 
   if [[ $process_owner == "" ]] ; then
@@ -283,6 +286,11 @@ start_command() {
     result=$?
   fi
 
+  # make sure the socket can be written to.
+  if [[ -e $path_socket_directory/$sa_system/$path_socket_name ]] ; then
+    chmod ugo+w $path_socket_directory/$sa_system/$path_socket_name
+  fi
+
   if [[ $result -ne 0 ]] ; then
     echo "Failed to start process, command: $path_service \"$sa_system\"."
     any_failure=1
@@ -306,7 +314,7 @@ stop_command() {
     sleep 0.1
 
     # cleanup the session socket ad pid file.
-    rm -f $path_socket_directory/$sa_system/sessions.socket
+    rm -f $path_socket_directory/$sa_system/$path_socket_name
     rm -f $pid_file
   fi
 }
index 57649baed2e8ac7bce6111767bca89eee371033f..4674420aa909fe2bc1ab2a4f86e81e6905c6d5cd 100644 (file)
@@ -99,9 +99,9 @@ function main($argc, $argv) {
   // long running processes should have PHP's garbage collection enabled, otherwise no cleanup ever happens.
   gc_enable();
 
-  $pid_path_directory = '/var/run/sessionize_accounts/';
+  $pid_path_directory = '/programs/run/sessionize_accounts/';
   $pid_path = $pid_path_directory . $argv[1] . '.pid';
-  $socket_path = '/var/www/sockets/sessionize_accounts/' . $argv[1] . '/sessions.socket';
+  $socket_path = '/programs/sockets/sessionize_accounts/' . $argv[1] . '/sessions.socket';
   $socket_family = AF_UNIX;
   $socket_port = 0;
   $socket_protocol = 0;