* @file
*/
+use MediaWiki\Session\Session;
+use MediaWiki\Session\SessionId;
use MediaWiki\Session\SessionManager;
/**
*/
const GETHEADER_LIST = 1;
+ /**
+ * The unique request ID.
+ * @var string
+ */
+ private static $reqId;
+
/**
* Lazy-init response object
* @var WebResponse
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 );
* @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;
}
/**
*
* @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
*/
* @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 ) {
/**
* 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;
* 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
*/
* @param mixed $data
*/
public function setSessionData( $key, $data ) {
- return $this->getSession()->set( $key, $data );
+ $this->getSession()->set( $key, $data );
}
/**
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;
+ }
}