You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

request.php 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. <?php
  2. /**
  3. * Copyright (c) 2012 Bart Visscher <bartv@thisnet.nl>
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. class OC_Request {
  9. const USER_AGENT_IE = '/MSIE/';
  10. // Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent
  11. const USER_AGENT_ANDROID_MOBILE_CHROME = '#Android.*Chrome/[.0-9]*#';
  12. const USER_AGENT_FREEBOX = '#^Mozilla/5\.0$#';
  13. const REGEX_LOCALHOST = '/^(127\.0\.0\.1|localhost)(:[0-9]+|)$/';
  14. /**
  15. * @brief Check overwrite condition
  16. * @param string $type
  17. * @returns bool
  18. */
  19. private static function isOverwriteCondition($type = '') {
  20. $regex = '/' . OC_Config::getValue('overwritecondaddr', '') . '/';
  21. return $regex === '//' or preg_match($regex, $_SERVER['REMOTE_ADDR']) === 1
  22. or ($type !== 'protocol' and OC_Config::getValue('forcessl', false));
  23. }
  24. /**
  25. * @brief Checks whether a domain is considered as trusted from the list
  26. * of trusted domains. If no trusted domains have been configured, returns
  27. * true.
  28. * This is used to prevent Host Header Poisoning.
  29. * @param string $domain
  30. * @return bool true if the given domain is trusted or if no trusted domains
  31. * have been configured
  32. */
  33. public static function isTrustedDomain($domain) {
  34. $trustedList = \OC_Config::getValue('trusted_domains', array());
  35. if (empty($trustedList)) {
  36. return true;
  37. }
  38. if (preg_match(self::REGEX_LOCALHOST, $domain) === 1) {
  39. return true;
  40. }
  41. return in_array($domain, $trustedList);
  42. }
  43. /**
  44. * @brief Returns the unverified server host from the headers without checking
  45. * whether it is a trusted domain
  46. * @returns string the server host
  47. *
  48. * Returns the server host, even if the website uses one or more
  49. * reverse proxies
  50. */
  51. public static function insecureServerHost() {
  52. $host = null;
  53. if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
  54. if (strpos($_SERVER['HTTP_X_FORWARDED_HOST'], ",") !== false) {
  55. $parts = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
  56. $host = trim(current($parts));
  57. } else {
  58. $host = $_SERVER['HTTP_X_FORWARDED_HOST'];
  59. }
  60. } else {
  61. if (isset($_SERVER['HTTP_HOST'])) {
  62. $host = $_SERVER['HTTP_HOST'];
  63. } else if (isset($_SERVER['SERVER_NAME'])) {
  64. $host = $_SERVER['SERVER_NAME'];
  65. }
  66. }
  67. return $host;
  68. }
  69. /**
  70. * Returns the overwritehost setting from the config if set and
  71. * if the overwrite condition is met
  72. * @return string|null overwritehost value or null if not defined or the defined condition
  73. * isn't met
  74. */
  75. public static function getOverwriteHost() {
  76. if(OC_Config::getValue('overwritehost', '') !== '' and self::isOverwriteCondition()) {
  77. return OC_Config::getValue('overwritehost');
  78. }
  79. return null;
  80. }
  81. /**
  82. * @brief Returns the server host from the headers, or the first configured
  83. * trusted domain if the host isn't in the trusted list
  84. * @returns string the server host
  85. *
  86. * Returns the server host, even if the website uses one or more
  87. * reverse proxies
  88. */
  89. public static function serverHost() {
  90. if(OC::$CLI) {
  91. return 'localhost';
  92. }
  93. // overwritehost is always trusted
  94. $host = self::getOverwriteHost();
  95. if ($host !== null) {
  96. return $host;
  97. }
  98. // get the host from the headers
  99. $host = self::insecureServerHost();
  100. // Verify that the host is a trusted domain if the trusted domains
  101. // are defined
  102. // If no trusted domain is provided the first trusted domain is returned
  103. if (self::isTrustedDomain($host)) {
  104. return $host;
  105. } else {
  106. $trustedList = \OC_Config::getValue('trusted_domains', array(''));
  107. return $trustedList[0];
  108. }
  109. }
  110. /**
  111. * @brief Returns the server protocol
  112. * @returns string the server protocol
  113. *
  114. * Returns the server protocol. It respects reverse proxy servers and load balancers
  115. */
  116. public static function serverProtocol() {
  117. if(OC_Config::getValue('overwriteprotocol', '') !== '' and self::isOverwriteCondition('protocol')) {
  118. return OC_Config::getValue('overwriteprotocol');
  119. }
  120. if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
  121. $proto = strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']);
  122. // Verify that the protocol is always HTTP or HTTPS
  123. // default to http if an invalid value is provided
  124. return $proto === 'https' ? 'https' : 'http';
  125. }
  126. if (isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') {
  127. return 'https';
  128. }
  129. return 'http';
  130. }
  131. /**
  132. * @brief Returns the request uri
  133. * @returns string the request uri
  134. *
  135. * Returns the request uri, even if the website uses one or more
  136. * reverse proxies
  137. * @return string
  138. */
  139. public static function requestUri() {
  140. $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
  141. if (OC_Config::getValue('overwritewebroot', '') !== '' and self::isOverwriteCondition()) {
  142. $uri = self::scriptName() . substr($uri, strlen($_SERVER['SCRIPT_NAME']));
  143. }
  144. return $uri;
  145. }
  146. /**
  147. * @brief Returns the script name
  148. * @return string the script name
  149. *
  150. * Returns the script name, even if the website uses one or more
  151. * reverse proxies
  152. */
  153. public static function scriptName() {
  154. $name = $_SERVER['SCRIPT_NAME'];
  155. $overwriteWebRoot = OC_Config::getValue('overwritewebroot', '');
  156. if ($overwriteWebRoot !== '' and self::isOverwriteCondition()) {
  157. $serverroot = str_replace("\\", '/', substr(__DIR__, 0, -strlen('lib/private/')));
  158. $suburi = str_replace("\\", "/", substr(realpath($_SERVER["SCRIPT_FILENAME"]), strlen($serverroot)));
  159. $name = '/' . ltrim($overwriteWebRoot . $suburi, '/');
  160. }
  161. return $name;
  162. }
  163. /**
  164. * @brief get Path info from request
  165. * @return string Path info or false when not found
  166. */
  167. public static function getPathInfo() {
  168. if (array_key_exists('PATH_INFO', $_SERVER)) {
  169. $path_info = $_SERVER['PATH_INFO'];
  170. }else{
  171. $path_info = self::getRawPathInfo();
  172. // following is taken from Sabre_DAV_URLUtil::decodePathSegment
  173. $path_info = rawurldecode($path_info);
  174. $encoding = mb_detect_encoding($path_info, array('UTF-8', 'ISO-8859-1'));
  175. switch($encoding) {
  176. case 'ISO-8859-1' :
  177. $path_info = utf8_encode($path_info);
  178. }
  179. // end copy
  180. }
  181. return $path_info;
  182. }
  183. /**
  184. * @brief get Path info from request, not urldecoded
  185. * @throws Exception
  186. * @return string Path info or false when not found
  187. */
  188. public static function getRawPathInfo() {
  189. $requestUri = $_SERVER['REQUEST_URI'];
  190. // remove too many leading slashes - can be caused by reverse proxy configuration
  191. if (strpos($requestUri, '/') === 0) {
  192. $requestUri = '/' . ltrim($requestUri, '/');
  193. }
  194. // Remove the query string from REQUEST_URI
  195. if ($pos = strpos($requestUri, '?')) {
  196. $requestUri = substr($requestUri, 0, $pos);
  197. }
  198. $scriptName = $_SERVER['SCRIPT_NAME'];
  199. $path_info = $requestUri;
  200. // strip off the script name's dir and file name
  201. list($path, $name) = \Sabre_DAV_URLUtil::splitPath($scriptName);
  202. if (!empty($path)) {
  203. if( $path === $path_info || strpos($path_info, $path.'/') === 0) {
  204. $path_info = substr($path_info, strlen($path));
  205. } else {
  206. throw new Exception("The requested uri($requestUri) cannot be processed by the script '$scriptName')");
  207. }
  208. }
  209. if (strpos($path_info, '/'.$name) === 0) {
  210. $path_info = substr($path_info, strlen($name) + 1);
  211. }
  212. if (strpos($path_info, $name) === 0) {
  213. $path_info = substr($path_info, strlen($name));
  214. }
  215. if($path_info === '/'){
  216. return '';
  217. } else {
  218. return $path_info;
  219. }
  220. }
  221. /**
  222. * @brief Check if the requester sent along an mtime
  223. * @return false or an mtime
  224. */
  225. static public function hasModificationTime () {
  226. if (isset($_SERVER['HTTP_X_OC_MTIME'])) {
  227. return $_SERVER['HTTP_X_OC_MTIME'];
  228. } else {
  229. return false;
  230. }
  231. }
  232. /**
  233. * Checks whether the user agent matches a given regex
  234. * @param string|array $agent agent name or array of agent names
  235. * @return boolean true if at least one of the given agent matches,
  236. * false otherwise
  237. */
  238. static public function isUserAgent($agent) {
  239. if (!is_array($agent)) {
  240. $agent = array($agent);
  241. }
  242. foreach ($agent as $regex) {
  243. if (preg_match($regex, $_SERVER['HTTP_USER_AGENT'])) {
  244. return true;
  245. }
  246. }
  247. return false;
  248. }
  249. }