*/
const GETHEADER_LIST = 1;
+ /**
+ * The unique request ID.
+ * @var string
+ */
+ private static $reqId;
+
/**
* Lazy-init response object
* @var WebResponse
*/
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
*/
* @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;
}
+
+ /**
+ * Check if this request uses a "safe" HTTP method
+ *
+ * Safe methods are verbs (e.g. GET/HEAD/OPTIONS) used for obtaining content. Such requests
+ * are not expected to mutate content, especially in ways attributable to the client. Verbs
+ * like POST and PUT are typical of non-safe requests which often change content.
+ *
+ * @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 hasSafeMethod() {
+ if ( !isset( $_SERVER['REQUEST_METHOD'] ) ) {
+ return false; // CLI mode
+ }
+
+ return in_array( $_SERVER['REQUEST_METHOD'], [ 'GET', 'HEAD', 'OPTIONS', 'TRACE' ] );
+ }
+
+ /**
+ * 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 ( $this->markedAsSafe && $this->wasPosted() ) {
+ return true; // marked as a "safe" POST
+ }
+
+ return $this->hasSafeMethod();
+ }
+
+ /**
+ * Mark this request as 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;
+ }
}