MediaWiki master
OpenSearchDescriptionHandler.php
Go to the documentation of this file.
1<?php
2
22
36
50
51 private UrlUtils $urlUtils;
52
54 private string $favicon;
55
57 private array $templates;
58
59 public function __construct( Config $config, UrlUtils $urlUtils ) {
60 $this->favicon = $config->get( MainConfigNames::Favicon );
61 $this->templates = $config->get( MainConfigNames::OpenSearchTemplates );
62 $this->urlUtils = $urlUtils;
63 }
64
65 public function execute(): Response {
66 $ctype = $this->getContentType();
67
68 $response = $this->getResponseFactory()->create();
69 $response->setHeader( 'Content-type', $ctype );
70
71 // Set an Expires header so that CDN can cache it for a short time
72 // Short enough so that the sysadmin barely notices when $wgSitename is changed
73 $expiryTime = 600; # 10 minutes
74 $response->setHeader( 'Expires', gmdate( 'D, d M Y H:i:s', time() + $expiryTime ) . ' GMT' );
75 $response->setHeader( 'Cache-control', 'max-age=600' );
76
77 $body = new StringStream();
78
79 $body->write( '<?xml version="1.0"?>' );
80 $body->write( Xml::openElement( 'OpenSearchDescription',
81 [
82 'xmlns' => 'http://a9.com/-/spec/opensearch/1.1/',
83 'xmlns:moz' => 'http://www.mozilla.org/2006/browser/search/' ] ) );
84
85 // The spec says the ShortName must be no longer than 16 characters,
86 // but 16 is *realllly* short. In practice, browsers don't appear to care
87 // when we give them a longer string, so we're no longer attempting to trim.
88 //
89 // Note: ShortName and the <link title=""> need to match; they are used as
90 // a key for identifying if the search engine has been added already, *and*
91 // as the display name presented to the end-user.
92 //
93 // Behavior seems about the same between Firefox and IE 7/8 here.
94 // 'Description' doesn't appear to be used by either.
95 $fullName = wfMessage( 'opensearch-desc' )->inContentLanguage()->text();
96 $body->write( Xml::element( 'ShortName', null, $fullName ) );
97 $body->write( Xml::element( 'Description', null, $fullName ) );
98
99 // By default we'll use the site favicon.
100 // Double-check if IE supports this properly?
101 $body->write( Xml::element( 'Image',
102 [
103 'height' => 16,
104 'width' => 16,
105 'type' => 'image/x-icon'
106 ],
107 (string)$this->urlUtils->expand( $this->favicon, PROTO_CURRENT )
108 ) );
109
110 $urls = [];
111
112 // General search template. Given an input term, this should bring up
113 // search results or a specific found page.
114 // At least Firefox and IE 7 support this.
115 $searchPage = SpecialPage::getTitleFor( 'Search' );
116 $urls[] = [
117 'type' => 'text/html',
118 'method' => 'get',
119 'template' => $searchPage->getCanonicalURL( 'search={searchTerms}' ) ];
120
121 // TODO: add v1/search/ endpoints?
122
123 foreach ( $this->templates as $type => $template ) {
124 if ( !$template ) {
125 $template = ApiOpenSearch::getOpenSearchTemplate( $type );
126 }
127
128 if ( $template ) {
129 $urls[] = [
130 'type' => $type,
131 'method' => 'get',
132 'template' => $template,
133 ];
134 }
135 }
136
137 // Allow hooks to override the suggestion URL settings in a more
138 // general way than overriding the whole search engine...
139 ( new HookRunner( $this->getHookContainer() ) )->onOpenSearchUrls( $urls );
140
141 foreach ( $urls as $attribs ) {
142 $body->write( Xml::element( 'Url', $attribs ) );
143 }
144
145 // And for good measure, add a link to the straight search form.
146 // This is a custom format extension for Firefox, which otherwise
147 // sends you to the domain root if you hit "enter" with an empty
148 // search box.
149 $body->write( Xml::element( 'moz:SearchForm', null,
150 $searchPage->getCanonicalURL() ) );
151
152 $body->write( Xml::closeElement( 'OpenSearchDescription' ) );
153
154 $response->setBody( $body );
155 return $response;
156 }
157
165 private function getContentType(): string {
166 $params = $this->getValidatedParams();
167 if ( $params['ctype'] == 'application/xml' ) {
168 // Makes testing tweaks about a billion times easier
169 return 'application/xml';
170 }
171
172 $acceptHeader = $this->getRequest()->getHeader( 'accept' );
173
174 if ( $acceptHeader ) {
175 $parser = new HttpAcceptParser();
176 $acceptableTypes = $parser->parseAccept( $acceptHeader[0] );
177
178 foreach ( $acceptableTypes as $acc ) {
179 if ( $acc['type'] === 'application/xml' ) {
180 return 'application/xml';
181 }
182 }
183 }
184
185 return 'application/opensearchdescription+xml';
186 }
187
188 protected function generateResponseSpec( string $method ): array {
189 $spec = parent::generateResponseSpec( $method );
190
191 $spec['200']['content']['application/opensearchdescription+xml']['schema']['type'] = 'string';
192
193 return $spec;
194 }
195
196 public function getParamSettings() {
197 return [
198 'ctype' => [
199 self::PARAM_SOURCE => 'query',
200 Handler::PARAM_DESCRIPTION => new MessageValue( 'rest-param-desc-opensearch-ctype' ),
201 ]
202 ];
203 }
204
205}
const PROTO_CURRENT
Definition Defines.php:236
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
static getOpenSearchTemplate( $type)
Fetch the template for a type.
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
static openElement( $element, $attribs=[])
Identical to rawElement(), but has no third parameter and omits the end tag (and the self-closing '/'...
Definition Html.php:242
static closeElement( $element)
Returns "</$element>".
Definition Html.php:306
static element( $element, $attribs=[], $contents='')
Identical to rawElement(), but HTML-escapes $contents (like Xml::element()).
Definition Html.php:218
A class containing constants representing the names of configuration variables.
const OpenSearchTemplates
Name constant for the OpenSearchTemplates setting, for use with Config::get()
const Favicon
Name constant for the Favicon setting, for use with Config::get()
This class contains schema declarations for all configuration variables known to MediaWiki core.
Handler for generating an OpenSearch description document.
getParamSettings()
Fetch ParamValidator settings for parameters.
generateResponseSpec(string $method)
Returns an OpenAPI Responses Object specification structure as an associative array.
Base class for REST route handlers.
Definition Handler.php:25
getHookContainer()
Get a HookContainer, for running extension hooks or for hook metadata.
Definition Handler.php:1039
getRequest()
Get the current request.
Definition Handler.php:326
getValidatedParams()
Fetch the validated parameters.
Definition Handler.php:874
getResponseFactory()
Get the ResponseFactory which can be used to generate Response objects.
Definition Handler.php:355
setHeader( $name, $value)
Set or replace the specified header.
Definition Response.php:94
A stream class which uses a string as the underlying storage.
Parent class for all special pages.
static getTitleFor( $name, $subpage=false, $fragment='')
Get a localised Title object for a specified special page name If you don't need a full Title object,...
A service to expand, parse, and otherwise manipulate URLs.
Definition UrlUtils.php:16
Module of static functions for generating XML.
Definition Xml.php:37
Value object representing a message for i18n.
Interface for configuration instances.
Definition Config.php:32
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
array $params
The job parameters.
Copyright (C) 2011-2020 Wikimedia Foundation and others.