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 * @license GPL-2.0-or-later
9 * @file
10 * @ingroup entrypoint
11 * @ingroup API
12 */
13
14namespace MediaWiki\Api;
15
16use LogicException;
17use MediaWiki\Context\RequestContext;
18use MediaWiki\EntryPointEnvironment;
19use MediaWiki\HookContainer\HookRunner;
20use MediaWiki\MediaWikiEntryPoint;
21use MediaWiki\MediaWikiServices;
22use MediaWiki\Title\Title;
23use Throwable;
24
25/**
26 * Implementation of the API entry point, for web browser navigations, usually via an
27 * Action or SpecialPage subclass.
28 *
29 * This is used by bots to fetch content and information about the wiki,
30 * its pages, and its users. See <https://www.mediawiki.org/wiki/API> for more
31 * information.
32 *
33 * @see /api.php The corresponding HTTP entry point.
34 * @internal
35 */
36class ApiEntryPoint extends MediaWikiEntryPoint {
37
38    public function __construct(
39        RequestContext $context,
40        EntryPointEnvironment $environment,
41        MediaWikiServices $services
42    ) {
43        parent::__construct(
44            $context,
45            $environment,
46            $services
47        );
48    }
49
50    /**
51     * Overwritten to narrow the return type to RequestContext
52     */
53    protected function getContext(): RequestContext {
54        /** @var RequestContext $context */
55        $context = parent::getContext();
56
57        // @phan-suppress-next-line PhanTypeMismatchReturnSuperType see $context in the constructor
58        return $context;
59    }
60
61    /**
62     * Executes a request to the action API.
63     *
64     * It begins by constructing a new ApiMain using the parameter passed to it
65     * as an argument in the URL ('?action='). It then invokes "execute()" on the
66     * ApiMain object instance, which produces output in the format specified in
67     * the URL.
68     */
69    protected function execute() {
70        // phpcs:ignore MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgTitle
71        global $wgTitle;
72
73        $context = $this->getContext();
74        $request = $this->getRequest();
75
76        $services = $this->getServiceContainer();
77
78        // PATH_INFO can be used for stupid things. We don't support it for api.php at
79        // all, so error out if it's present. (T128209)
80        $pathInfo = $this->environment->getServerInfo( 'PATH_INFO', '' );
81        if ( $pathInfo != '' ) {
82            $correctUrl = wfAppendQuery(
83                wfScript( 'api' ),
84                $request->getQueryValuesOnly()
85            );
86            $correctUrl = (string)$services->getUrlUtils()->expand(
87                $correctUrl,
88                PROTO_CANONICAL
89            );
90            $this->header(
91                "Location: $correctUrl",
92                true,
93                301
94            );
95            $this->print(
96                'This endpoint does not support "path info", i.e. extra text ' .
97                'between "api.php" and the "?". Remove any such text and try again.'
98            );
99            $this->exit( 1 );
100        }
101
102        // Set a dummy $wgTitle, because $wgTitle == null breaks various things
103        // In a perfect world this wouldn't be necessary
104        $wgTitle = Title::makeTitle(
105            NS_SPECIAL,
106            'Badtitle/dummy title for API calls set in api.php'
107        );
108
109        // RequestContext will read from $wgTitle, but it will also whine about it.
110        // In a perfect world this wouldn't be necessary either.
111        $context->setTitle( $wgTitle );
112
113        try {
114            // Construct an ApiMain with the arguments passed via the URL. What we get back
115            // is some form of an ApiMain, possibly even one that produces an error message,
116            // but we don't care here, as that is handled by the constructor.
117            $processor = new ApiMain(
118                $context,
119                true,
120                false
121            );
122
123            // Last chance hook before executing the API
124            ( new HookRunner( $services->getHookContainer() ) )->onApiBeforeMain( $processor );
125            if ( !$processor instanceof ApiMain ) {
126                throw new LogicException(
127                    'ApiBeforeMain hook set $processor to a non-ApiMain class'
128                );
129            }
130        } catch ( Throwable $e ) {
131            // Crap. Try to report the exception in API format to be friendly to clients.
132            ApiMain::handleApiBeforeMainException( $e );
133            $processor = false;
134        }
135
136        // Process data & print results
137        if ( $processor ) {
138            $processor->execute();
139        }
140    }
141}