Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ParsoidFormatHelper
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 3
210
0.00% covered (danger)
0.00%
0 / 1
 getContentType
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
56
 setContentType
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 parseContentTypeHeader
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2/**
3 * Copyright (C) 2011-2020 Wikimedia Foundation and others.
4 *
5 * @license GPL-2.0-or-later
6 */
7
8namespace MediaWiki\Rest\Handler\Helper;
9
10use InvalidArgumentException;
11use MediaWiki\Rest\ResponseInterface;
12
13/**
14 * Format-related REST API helper.
15 * Probably should be turned into an object encapsulating format and content version at some point.
16 */
17class ParsoidFormatHelper {
18
19    public const FORMAT_WIKITEXT = 'wikitext';
20    public const FORMAT_HTML = 'html';
21    public const FORMAT_PAGEBUNDLE = 'pagebundle';
22    public const FORMAT_LINT = 'lint';
23
24    public const ERROR_ENCODING = [
25        self::FORMAT_WIKITEXT => 'plain',
26        self::FORMAT_HTML => 'html',
27        self::FORMAT_PAGEBUNDLE => 'json',
28        self::FORMAT_LINT => 'json',
29    ];
30
31    public const VALID_PAGE = [
32        self::FORMAT_WIKITEXT, self::FORMAT_HTML, self::FORMAT_PAGEBUNDLE, self::FORMAT_LINT
33    ];
34
35    public const VALID_TRANSFORM = [
36        self::FORMAT_WIKITEXT => [ self::FORMAT_HTML, self::FORMAT_PAGEBUNDLE, self::FORMAT_LINT ],
37        self::FORMAT_HTML => [ self::FORMAT_WIKITEXT ],
38        self::FORMAT_PAGEBUNDLE => [ self::FORMAT_WIKITEXT, self::FORMAT_PAGEBUNDLE ],
39    ];
40
41    /**
42     * Get the content type appropriate for a given response format.
43     * @param string $format One of the FORMAT_* constants
44     * @param ?string $contentVersion Output version, only for HTML and pagebundle
45     *   formats. See Env::getcontentVersion().
46     * @return string
47     */
48    public static function getContentType(
49        string $format, ?string $contentVersion = null
50    ): string {
51        if ( $format !== self::FORMAT_WIKITEXT && !$contentVersion ) {
52            throw new InvalidArgumentException( '$contentVersion is required for this format' );
53        }
54
55        switch ( $format ) {
56            case self::FORMAT_WIKITEXT:
57                $contentType = 'text/plain';
58                // PORT-FIXME in the original the version number is from MWParserEnvironment.wikitextVersion
59                // but it did not seem to be used anywhere
60                $profile = 'https://www.mediawiki.org/wiki/Specs/wikitext/1.0.0';
61                break;
62            case self::FORMAT_HTML:
63                $contentType = 'text/html';
64                $profile = 'https://www.mediawiki.org/wiki/Specs/HTML/' . $contentVersion;
65                break;
66            case self::FORMAT_PAGEBUNDLE:
67                $contentType = 'application/json';
68                $profile = 'https://www.mediawiki.org/wiki/Specs/pagebundle/' . $contentVersion;
69                break;
70            default:
71                throw new InvalidArgumentException( "Invalid format $format" );
72        }
73        return "$contentType; charset=utf-8; profile=\"$profile\"";
74    }
75
76    /**
77     * Set the Content-Type header appropriate for a given response format.
78     * @param ResponseInterface $response
79     * @param string $format One of the FORMAT_* constants
80     * @param ?string $contentVersion Output version, only for HTML and pagebundle
81     *   formats. See Env::getcontentVersion().
82     */
83    public static function setContentType(
84        ResponseInterface $response, string $format,
85        ?string $contentVersion = null
86    ): void {
87        $response->setHeader( 'Content-Type', self::getContentType( $format, $contentVersion ) );
88    }
89
90    /**
91     * Parse a Content-Type header and return the format type and version.
92     * Mostly the inverse of getContentType() but also accounts for legacy formats.
93     * @param string $contentTypeHeader The value of the Content-Type header.
94     * @param ?string &$format Format type will be set here (as a FORMAT_* constant).
95     * @return ?string Format version, or null if it couldn't be identified.
96     * @see Env::getInputContentVersion()
97     */
98    public static function parseContentTypeHeader(
99        string $contentTypeHeader, ?string &$format = null
100    ): ?string {
101        $newProfileSyntax = 'https://www.mediawiki.org/wiki/Specs/(HTML|pagebundle)/';
102        $oldProfileSyntax = 'mediawiki.org/specs/(html)/';
103        $profileRegex = "#\bprofile=\"(?:$newProfileSyntax|$oldProfileSyntax)(\d+\.\d+\.\d+)\"#";
104        preg_match( $profileRegex, $contentTypeHeader, $m );
105        if ( $m ) {
106            switch ( $m[1] ?: $m[2] ) {
107                case 'HTML':
108                case 'html':
109                    $format = self::FORMAT_HTML;
110                    break;
111                case 'pagebundle':
112                    $format = self::FORMAT_PAGEBUNDLE;
113                    break;
114            }
115            return $m[3];
116        }
117        return null;
118    }
119
120}