Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
58.00% covered (warning)
58.00%
29 / 50
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiEntryPoint
58.00% covered (warning)
58.00%
29 / 50
66.67% covered (warning)
66.67%
2 / 3
10.63
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 getContext
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 execute
51.16% covered (warning)
51.16%
22 / 43
0.00% covered (danger)
0.00%
0 / 1
7.91
1<?php
2/**
3 * Entry point implementation for all %Action API queries, handled by ApiMain
4 * and ApiBase subclasses.
5 *
6 * @see /api.php The corresponding HTTP entry point.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * http://www.gnu.org/copyleft/gpl.html
22 *
23 * @file
24 * @ingroup entrypoint
25 * @ingroup API
26 */
27
28namespace MediaWiki\Api;
29
30use LogicException;
31use MediaWiki\Context\RequestContext;
32use MediaWiki\EntryPointEnvironment;
33use MediaWiki\HookContainer\HookRunner;
34use MediaWiki\MediaWikiEntryPoint;
35use MediaWiki\MediaWikiServices;
36use MediaWiki\Title\Title;
37use Throwable;
38
39/**
40 * Implementation of the API entry point, for web browser navigations, usually via an
41 * Action or SpecialPage subclass.
42 *
43 * This is used by bots to fetch content and information about the wiki,
44 * its pages, and its users. See <https://www.mediawiki.org/wiki/API> for more
45 * information.
46 *
47 * @see /api.php The corresponding HTTP entry point.
48 * @internal
49 */
50class ApiEntryPoint extends MediaWikiEntryPoint {
51
52    public function __construct(
53        RequestContext $context,
54        EntryPointEnvironment $environment,
55        MediaWikiServices $services
56    ) {
57        parent::__construct(
58            $context,
59            $environment,
60            $services
61        );
62    }
63
64    /**
65     * Overwritten to narrow the return type to RequestContext
66     */
67    protected function getContext(): RequestContext {
68        /** @var RequestContext $context */
69        $context = parent::getContext();
70
71        // @phan-suppress-next-line PhanTypeMismatchReturnSuperType see $context in the constructor
72        return $context;
73    }
74
75    /**
76     * Executes a request to the action API.
77     *
78     * It begins by constructing a new ApiMain using the parameter passed to it
79     * as an argument in the URL ('?action='). It then invokes "execute()" on the
80     * ApiMain object instance, which produces output in the format specified in
81     * the URL.
82     */
83    protected function execute() {
84        // phpcs:ignore MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgTitle
85        global $wgTitle;
86
87        $context = $this->getContext();
88        $request = $this->getRequest();
89
90        $services = $this->getServiceContainer();
91
92        // PATH_INFO can be used for stupid things. We don't support it for api.php at
93        // all, so error out if it's present. (T128209)
94        $pathInfo = $this->environment->getServerInfo( 'PATH_INFO', '' );
95        if ( $pathInfo != '' ) {
96            $correctUrl = wfAppendQuery(
97                wfScript( 'api' ),
98                $request->getQueryValuesOnly()
99            );
100            $correctUrl = (string)$services->getUrlUtils()->expand(
101                $correctUrl,
102                PROTO_CANONICAL
103            );
104            $this->header(
105                "Location: $correctUrl",
106                true,
107                301
108            );
109            $this->print(
110                'This endpoint does not support "path info", i.e. extra text ' .
111                'between "api.php" and the "?". Remove any such text and try again.'
112            );
113            $this->exit( 1 );
114        }
115
116        // Set a dummy $wgTitle, because $wgTitle == null breaks various things
117        // In a perfect world this wouldn't be necessary
118        $wgTitle = Title::makeTitle(
119            NS_SPECIAL,
120            'Badtitle/dummy title for API calls set in api.php'
121        );
122
123        // RequestContext will read from $wgTitle, but it will also whine about it.
124        // In a perfect world this wouldn't be necessary either.
125        $context->setTitle( $wgTitle );
126
127        try {
128            // Construct an ApiMain with the arguments passed via the URL. What we get back
129            // is some form of an ApiMain, possibly even one that produces an error message,
130            // but we don't care here, as that is handled by the constructor.
131            $processor = new ApiMain(
132                $context,
133                true,
134                false
135            );
136
137            // Last chance hook before executing the API
138            ( new HookRunner( $services->getHookContainer() ) )->onApiBeforeMain( $processor );
139            if ( !$processor instanceof ApiMain ) {
140                throw new LogicException(
141                    'ApiBeforeMain hook set $processor to a non-ApiMain class'
142                );
143            }
144        } catch ( Throwable $e ) {
145            // Crap. Try to report the exception in API format to be friendly to clients.
146            ApiMain::handleApiBeforeMainException( $e );
147            $processor = false;
148        }
149
150        // Process data & print results
151        if ( $processor ) {
152            $processor->execute();
153        }
154    }
155}