Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 32
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 / 32
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 / 16
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 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20namespace MediaWiki\Rest\Handler\Helper;
21
22use InvalidArgumentException;
23use MediaWiki\Rest\ResponseInterface;
24
25/**
26 * Format-related REST API helper.
27 * Probably should be turned into an object encapsulating format and content version at some point.
28 */
29class ParsoidFormatHelper {
30
31    public const FORMAT_WIKITEXT = 'wikitext';
32    public const FORMAT_HTML = 'html';
33    public const FORMAT_PAGEBUNDLE = 'pagebundle';
34    public const FORMAT_LINT = 'lint';
35
36    public const ERROR_ENCODING = [
37        self::FORMAT_WIKITEXT => 'plain',
38        self::FORMAT_HTML => 'html',
39        self::FORMAT_PAGEBUNDLE => 'json',
40        self::FORMAT_LINT => 'json',
41    ];
42
43    public const VALID_PAGE = [
44        self::FORMAT_WIKITEXT, self::FORMAT_HTML, self::FORMAT_PAGEBUNDLE, self::FORMAT_LINT
45    ];
46
47    public const VALID_TRANSFORM = [
48        self::FORMAT_WIKITEXT => [ self::FORMAT_HTML, self::FORMAT_PAGEBUNDLE, self::FORMAT_LINT ],
49        self::FORMAT_HTML => [ self::FORMAT_WIKITEXT ],
50        self::FORMAT_PAGEBUNDLE => [ self::FORMAT_WIKITEXT, self::FORMAT_PAGEBUNDLE ],
51    ];
52
53    /**
54     * Get the content type appropriate for a given response format.
55     * @param string $format One of the FORMAT_* constants
56     * @param ?string $contentVersion Output version, only for HTML and pagebundle
57     *   formats. See Env::getcontentVersion().
58     * @return string
59     */
60    public static function getContentType(
61        string $format, ?string $contentVersion = null
62    ): string {
63        if ( $format !== self::FORMAT_WIKITEXT && !$contentVersion ) {
64            throw new InvalidArgumentException( '$contentVersion is required for this format' );
65        }
66
67        switch ( $format ) {
68            case self::FORMAT_WIKITEXT:
69                $contentType = 'text/plain';
70                // PORT-FIXME in the original the version number is from MWParserEnvironment.wikitextVersion
71                // but it did not seem to be used anywhere
72                $profile = 'https://www.mediawiki.org/wiki/Specs/wikitext/1.0.0';
73                break;
74            case self::FORMAT_HTML:
75                $contentType = 'text/html';
76                $profile = 'https://www.mediawiki.org/wiki/Specs/HTML/' . $contentVersion;
77                break;
78            case self::FORMAT_PAGEBUNDLE:
79                $contentType = 'application/json';
80                $profile = 'https://www.mediawiki.org/wiki/Specs/pagebundle/' . $contentVersion;
81                break;
82            default:
83                throw new InvalidArgumentException( "Invalid format $format" );
84        }
85        return "$contentType; charset=utf-8; profile=\"$profile\"";
86    }
87
88    /**
89     * Set the Content-Type header appropriate for a given response format.
90     * @param ResponseInterface $response
91     * @param string $format One of the FORMAT_* constants
92     * @param ?string $contentVersion Output version, only for HTML and pagebundle
93     *   formats. See Env::getcontentVersion().
94     */
95    public static function setContentType(
96        ResponseInterface $response, string $format,
97        ?string $contentVersion = null
98    ): void {
99        $response->setHeader( 'Content-Type', self::getContentType( $format, $contentVersion ) );
100    }
101
102    /**
103     * Parse a Content-Type header and return the format type and version.
104     * Mostly the inverse of getContentType() but also accounts for legacy formats.
105     * @param string $contentTypeHeader The value of the Content-Type header.
106     * @param ?string &$format Format type will be set here (as a FORMAT_* constant).
107     * @return ?string Format version, or null if it couldn't be identified.
108     * @see Env::getInputContentVersion()
109     */
110    public static function parseContentTypeHeader(
111        string $contentTypeHeader, ?string &$format = null
112    ): ?string {
113        $newProfileSyntax = 'https://www.mediawiki.org/wiki/Specs/(HTML|pagebundle)/';
114        $oldProfileSyntax = 'mediawiki.org/specs/(html)/';
115        $profileRegex = "#\bprofile=\"(?:$newProfileSyntax|$oldProfileSyntax)(\d+\.\d+\.\d+)\"#";
116        preg_match( $profileRegex, $contentTypeHeader, $m );
117        if ( $m ) {
118            switch ( $m[1] ?: $m[2] ) {
119                case 'HTML':
120                case 'html':
121                    $format = self::FORMAT_HTML;
122                    break;
123                case 'pagebundle':
124                    $format = self::FORMAT_PAGEBUNDLE;
125                    break;
126            }
127            return $m[3];
128        }
129        return null;
130    }
131
132}