Merge "Fix documentation for Revision::getComment and WikiPage::getComment"
[lhc/web/wiklou.git] / includes / linkeddata / PageDataRequestHandler.php
1 <?php
2 /**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20
21 use Wikimedia\Http\HttpAcceptParser;
22 use Wikimedia\Http\HttpAcceptNegotiator;
23
24 /**
25 * Request handler implementing a data interface for mediawiki pages.
26 *
27 * @author Daniel Kinzler
28 * @author Amir Sarabadanai
29 */
30 class PageDataRequestHandler {
31
32 /**
33 * Checks whether the request is complete, i.e. whether it contains all information needed
34 * to reply with page data.
35 *
36 * This does not check whether the request is valid and will actually produce a successful
37 * response.
38 *
39 * @param string|null $subPage
40 * @param WebRequest $request
41 *
42 * @return bool
43 */
44 public function canHandleRequest( $subPage, WebRequest $request ) {
45 if ( $subPage === '' || $subPage === null ) {
46 if ( $request->getText( 'target', '' ) === '' ) {
47 return false;
48 } else {
49 return true;
50 }
51 }
52
53 $parts = explode( '/', $subPage, 2 );
54 if ( $parts !== 2 ) {
55 $slot = $parts[0];
56 if ( $slot === 'main' || $slot === '' ) {
57 return true;
58 }
59 }
60
61 return false;
62 }
63
64 /**
65 * Main method for handling requests.
66 *
67 * @param string $subPage
68 * @param WebRequest $request The request parameters. Known parameters are:
69 * - title: the page title
70 * - format: the format
71 * - oldid|revision: the revision ID
72 * @param OutputPage $output
73 *
74 * @note Instead of an output page, a WebResponse could be sufficient, but
75 * redirect logic is currently implemented in OutputPage.
76 *
77 * @throws HttpError
78 */
79 public function handleRequest( $subPage, WebRequest $request, OutputPage $output ) {
80 // No matter what: The response is always public
81 $output->getRequest()->response()->header( 'Access-Control-Allow-Origin: *' );
82
83 if ( !$this->canHandleRequest( $subPage, $request ) ) {
84 throw new HttpError( 400, wfMessage( 'pagedata-bad-title', $subPage ) );
85 }
86
87 $revision = 0;
88
89 $parts = explode( '/', $subPage, 2 );
90 if ( $subPage !== '' ) {
91 $title = $parts[1];
92 } else {
93 $title = $request->getText( 'target', '' );
94 }
95
96 $revision = $request->getInt( 'oldid', $revision );
97 $revision = $request->getInt( 'revision', $revision );
98
99 if ( $title === null || $title === '' ) {
100 //TODO: different error message?
101 throw new HttpError( 400, wfMessage( 'pagedata-bad-title', $title ) );
102 }
103
104 try {
105 $title = Title::newFromTextThrow( $title );
106 } catch ( MalformedTitleException $ex ) {
107 throw new HttpError( 400, wfMessage( 'pagedata-bad-title', $title ) );
108 }
109
110 $this->httpContentNegotiation( $request, $output, $title, $revision );
111 }
112
113 /**
114 * Applies HTTP content negotiation.
115 * If the negotiation is successful, this method will set the appropriate redirect
116 * in the OutputPage object and return. Otherwise, an HttpError is thrown.
117 *
118 * @param WebRequest $request
119 * @param OutputPage $output
120 * @param Title $title
121 * @param int $revision The desired revision
122 *
123 * @throws HttpError
124 */
125 public function httpContentNegotiation(
126 WebRequest $request,
127 OutputPage $output,
128 Title $title,
129 $revision = 0
130 ) {
131 $contentHandler = ContentHandler::getForTitle( $title );
132 $mimeTypes = $contentHandler->getSupportedFormats();
133
134 $acceptHeader = $request->getHeader( 'Accept' );
135 if ( $acceptHeader !== false ) {
136 $parser = new HttpAcceptParser();
137 $accept = $parser->parseWeights( $acceptHeader );
138 } else {
139 // anything goes
140 $accept = [
141 '*' => 0.1 // just to make extra sure
142 ];
143 // prefer the default
144 $accept[$mimeTypes[0]] = 1;
145 }
146
147 $negotiator = new HttpAcceptNegotiator( $mimeTypes );
148 $format = $negotiator->getBestSupportedKey( $accept, null );
149
150 if ( $format === null ) {
151 $format = isset( $accept['text/html'] ) ? 'text/html' : null;
152 }
153
154 if ( $format === null ) {
155 $msg = wfMessage( 'pagedata-not-acceptable', implode( ', ', $mimeTypes ) );
156 throw new HttpError( 406, $msg );
157 }
158
159 $url = $this->getDocUrl( $title, $format, $revision );
160 $output->redirect( $url, 303 );
161 }
162
163 /**
164 * Returns a url representing the given title.
165 *
166 * @param Title $title
167 * @param string|null $format The (normalized) format name, or ''
168 * @param int $revision
169 * @return string
170 */
171 private function getDocUrl( Title $title, $format = '', $revision = 0 ) {
172 $params = [];
173
174 if ( $revision > 0 ) {
175 $params['oldid'] = $revision;
176 }
177
178 if ( $format === 'text/html' ) {
179 return $title->getFullURL( $params );
180 }
181
182 $params[ 'action' ] = 'raw';
183
184 return $title->getFullURL( $params );
185 }
186
187 }