Merge "Localisation updates from https://translatewiki.net."
[lhc/web/wiklou.git] / includes / WebRequest.php
index f4b4871..2333c78 100644 (file)
@@ -23,6 +23,8 @@
  * @file
  */
 
+use MediaWiki\Session\Session;
+use MediaWiki\Session\SessionId;
 use MediaWiki\Session\SessionManager;
 
 /**
@@ -41,6 +43,12 @@ class WebRequest {
         */
        const GETHEADER_LIST = 1;
 
+       /**
+        * The unique request ID.
+        * @var string
+        */
+       private static $reqId;
+
        /**
         * Lazy-init response object
         * @var WebResponse
@@ -66,12 +74,15 @@ class WebRequest {
        protected $protocol;
 
        /**
-        * @var \\MediaWiki\\Session\\SessionId|null Session ID to use for this
+        * @var SessionId|null Session ID to use for this
         *  request. We can't save the session directly due to reference cycles not
         *  working too well (slow GC in Zend and never collected in HHVM).
         */
        protected $sessionId = null;
 
+       /** @var bool Whether this HTTP request is "safe" (even if it is an HTTP post) */
+       protected $markedAsSafe = false;
+
        public function __construct() {
                $this->requestTime = isset( $_SERVER['REQUEST_TIME_FLOAT'] )
                        ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime( true );
@@ -255,14 +266,23 @@ class WebRequest {
         * @since 1.27
         */
        public static function getRequestId() {
-               static $reqId;
-
-               if ( !$reqId ) {
-                       $reqId = isset( $_SERVER['UNIQUE_ID'] )
+               if ( !self::$reqId ) {
+                       self::$reqId = isset( $_SERVER['UNIQUE_ID'] )
                                ? $_SERVER['UNIQUE_ID'] : wfRandomString( 24 );
                }
 
-               return $reqId;
+               return self::$reqId;
+       }
+
+       /**
+        * Override the unique request ID. This is for sub-requests, such as jobs,
+        * that wish to use the same id but are not part of the same execution context.
+        *
+        * @param string $id
+        * @since 1.27
+        */
+       public static function overrideRequestId( $id ) {
+               self::$reqId = $id;
        }
 
        /**
@@ -301,7 +321,7 @@ class WebRequest {
         *
         * @param string $path The URL path given from the client
         * @param array $bases One or more URLs, optionally with $1 at the end
-        * @param string $key If provided, the matching key in $bases will be
+        * @param string|bool $key If provided, the matching key in $bases will be
         *    passed on as the value of this URL parameter
         * @return array Array of URL variables to interpolate; empty if no match
         */
@@ -670,7 +690,7 @@ class WebRequest {
         * @since 1.27
         * @note For performance, keep the session locally if you will be making
         *  much use of it instead of calling this method repeatedly.
-        * @return MediaWiki\\Session\\Session
+        * @return Session
         */
        public function getSession() {
                if ( $this->sessionId !== null ) {
@@ -688,18 +708,18 @@ class WebRequest {
        /**
         * Set the session for this request
         * @since 1.27
-        * @private For use by MediaWiki\\Session classes only
-        * @param MediaWiki\\Session\\SessionId $sessionId
+        * @private For use by MediaWiki\Session classes only
+        * @param SessionId $sessionId
         */
-       public function setSessionId( MediaWiki\Session\SessionId $sessionId ) {
+       public function setSessionId( SessionId $sessionId ) {
                $this->sessionId = $sessionId;
        }
 
        /**
         * Get the session id for this request, if any
         * @since 1.27
-        * @private For use by MediaWiki\\Session classes only
-        * @return MediaWiki\\Session\\SessionId|null
+        * @private For use by MediaWiki\Session classes only
+        * @return SessionId|null
         */
        public function getSessionId() {
                return $this->sessionId;
@@ -710,7 +730,7 @@ class WebRequest {
         * This does not necessarily mean that the user is logged in!
         *
         * @deprecated since 1.27, use
-        *  \\MediaWiki\\Session\\SessionManager::singleton()->getPersistedSessionId()
+        *  \MediaWiki\Session\SessionManager::singleton()->getPersistedSessionId()
         *  instead.
         * @return bool
         */
@@ -1005,7 +1025,7 @@ class WebRequest {
         * @param mixed $data
         */
        public function setSessionData( $key, $data ) {
-               return $this->getSession()->set( $key, $data );
+               $this->getSession()->set( $key, $data );
        }
 
        /**
@@ -1228,4 +1248,50 @@ HTML;
        public function setIP( $ip ) {
                $this->ip = $ip;
        }
+
+       /**
+        * Whether this request should be identified as being "safe"
+        *
+        * This means that the client is not requesting any state changes and that database writes
+        * are not inherently required. Ideally, no visible updates would happen at all. If they
+        * must, then they should not be publically attributed to the end user.
+        *
+        * In more detail:
+        *   - Cache populations and refreshes MAY occur.
+        *   - Private user session updates and private server logging MAY occur.
+        *   - Updates to private viewing activity data MAY occur via DeferredUpdates.
+        *   - Other updates SHOULD NOT occur (e.g. modifying content assets).
+        *
+        * @return bool
+        * @see https://tools.ietf.org/html/rfc7231#section-4.2.1
+        * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
+        * @since 1.28
+        */
+       public function isSafeRequest() {
+               if ( !isset( $_SERVER['REQUEST_METHOD'] ) ) {
+                       return false; // CLI mode
+               }
+
+               if ( $_SERVER['REQUEST_METHOD'] === 'POST' ) {
+                       return $this->markedAsSafe;
+               } elseif ( in_array( $_SERVER['REQUEST_METHOD'], [ 'GET', 'HEAD', 'OPTIONS' ] ) ) {
+                       return true; // HTTP "safe methods"
+               }
+
+               return false; // PUT/DELETE
+       }
+
+       /**
+        * Mark this request is identified as being nullipotent even if it is a POST request
+        *
+        * POST requests are often used due to the need for a client payload, even if the request
+        * is otherwise equivalent to a "safe method" request.
+        *
+        * @see https://tools.ietf.org/html/rfc7231#section-4.2.1
+        * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
+        * @since 1.28
+        */
+       public function markAsSafeRequest() {
+               $this->markedAsSafe = true;
+       }
 }