Note: calling msg() with no parameter was never supported,
doing this on a RequestContext for example would result in:
PHP Warning: Missing argument 1 for wfMessage() ...followed
by a bunch of fallout.
So this patch only formally declares what was already a
requirement in reality.
Change-Id: I1864afb8bcc641698689828914949a06506d8f3a
It's unreasonable to expect newbies to know that "bug 12345" means "Task T14345"
except where it doesn't, so let's just standardise on the real numbers.
Change-Id: I6f59febaf8fc96e80f8cfc11f4356283f461142a
Utility methods like getFuzzyBool already use getRawVal instead
of getVal (see 83df6d8). But there was still direct use of getVal
which meant we still pay for WebRequest normalisation in load.php.
ResourceLoaderContext::__construct's use of WebRequest::getVal
accounts for 0.12% of execution time according to a Xenon daily log
(2016-09-27.all.reversed.svgz). The total use of WebRequest::getVal
is 0.26% of execution time. So almost half of that comes from RL.
Change-Id: Id37619ceadb5c990abf83f7910104cbc95523d28
Ensure that messages created using ResourceLoaderContext::msg() have a
title set so they don't trigger the GlobalTitleFail log. We use a dummy
title since there is no real title we can use here, and the cache
doesn't vary on a title anyways. This particular title was picked
especially for Roan.
This patch should quiet the GlobalTitleFail logs for
MFResourceLoaderParsedMessageModule and VisualEditorDataModule.
Change-Id: I502faa22776e1cb34a6ef17be96567f121c80081
* Fix up one last use of global config vars in this class.
Other places in this class already used $rl->getConfig().
This way we don't inherit all of MediaWikiTestCase.
* Add unit tests covering all of ResourceLoaderContext
except expandModuleNames and getImageObj (tested in better
places already with the right @covers).
* Increase coverage for expandModuleNames(), add missing case
of when modules are not in alphabetical order.
Change-Id: Id19b084d37a6c3a77b36e03509adffb6b156fee1
HTML formatting of the queue was distributed over several OutputPage methods.
Each method demanding a snippet of HTML by calling makeResourceLoaderLink()
with a limited amount of information. As such, makeResourceLoaderLink() was
unable to provide the client with the proper state information.
Centralising it also allows it to better reduce duplication in HTML output
and maintain a more accurate state.
Problems fixed by centralising:
1. The 'user' module is special (due to per-user 'version' and 'user' params).
It is manually requested via script-src. To avoid a separate (and wrong)
request from something that requires it, we set state=loading directly.
However, because the module is in the bottom, the old HTML formatter could
only put state=loading in the bottom also. This sometimes caused a wrong
request to be fired for modules=user if something in the top queue
triggered a requirement for it.
2. Since a464d1d4 (T87871) we track states of page-style modules, with purpose
of allowing dependencies on style modules without risking duplicate loading
on pages where the styles are loaded already. This didn't work, because the
state information about page-style modules is output near the stylesheet,
which is after the script tag with mw.loader.load(). That runs first, and
mw.loader would still make a duplicate request before it learns the state.
Changes:
* Document reasons for style/script tag order in getHeadHtml (per 09537e83).
* Pass $type from getModuleStyles() to getAllowedModules(). This wasn't needed
before since a duplicate check in makeResourceLoaderLink() verified the
origin a second time.
* Declare explicit position 'top' on 'user.options' and 'user.tokens' module.
Previously, OutputPage hardcoded them in the top. The new formatter doesn't.
* Remove getHeadScripts().
* Remove getInlineHeadScripts().
* Remove getExternalHeadScripts().
* Remove buildCssLinks().
* Remove getScriptsForBottomQueue().
* Change where Skin::setupSkinUserCss() is called. This methods lets the skin
add modules to the queue. Previously it was called from buildCssLinks(),
via headElement(), via prepareQuickTemplate(), via OutputPage::output().
It's now in OutputPage::output() directly (slightly earlier). This is needed
because prepareQuickTemplate() calls bottomScripts() before headElement().
And bottomScript() would lazy-initialise the queue and lock it before
setupSkinUserCss() is called from headElement().
This makes execution order more predictable instead of being dependent on
the arbitrary order of data extraction in prepareQuickTemplate (which varies
from one skin to another).
* Compute isUserModulePreview() and isKnownEmpty() for the 'user' module early
on so. This avoids wrongful loading and fixes problem 1.
Effective changes in output:
* mw.loader.state() is now before mw.loader.load(). This fixes problem 2.
* mw.loader.state() now sets 'user.options' and 'user.tokens' to "loading".
* mw.loader.state() now sets 'user' (as "loading" or "ready"). Fixes problem 1.
* The <script async src> tag for 'startup' changed position (slightly).
Previously it was after all inline scripts and stylesheets. It's still after
all inline scripts and after most stylesheets, but before any user styles.
Since the queue is now formatted outside OutputPage, it can't inject the
meta-ResourceLoaderDynamicStyles tag and user-stylesheet hack in the middle
of existing output. This shouldn't have any noticable impact.
Bug: T87871
Change-Id: I605b8cd1e1fc009b4662a0edbc54d09dd65ee1df
Most code paths already wrongly assume this behaviour.
This patch removes the now-redundant check from the two modules
that did account for it.
Change-Id: Ic85258f184db8aa68e19d8e667e396d08ee5de0c
This makes it easier to fetch messages without having to manually
call inLanguage() on each wfMessage() call, which is currently
causing some code forget this and use plain wfMessage() which
defaults to MediaWiki user language from session.
I've considered setting $wgLang or RequestContext::getMain(),
but that's still bad since modules get passed a context in their
methods and shouldn't be using global context either.
The warnings provided by MW_NO_SESSION are exactly what we want.
Change-Id: I1288fa5622d9f82d21bb66c8eb6518b90e7cddb4
Remove optimization that avoids unstubbing $wgUser because $wgUser
is not a plain object for the current user name.
It's a stub with mFrom='session' until methods are called that need
the info, such as getName(), which then lazy loads the object based on
the session information.
We want to make load.php session-less.
Bug: T127233
Change-Id: Ica482e5d1892cb29456e6f2a91cd70017cf414c5
* Add logger to ResourceLoaderContext for convenient use within modules.
* Group related members within ResourceLoaderContext.
Change-Id: Ifbc3de1b6e0838386735f1573df328d9b331ac37
This parameter was introduced last year as a way to extract
bare scripts from modules without any 'mw.loader.state()' suffix.
When ResourceFileCache is used ($wgUseFileCache) this causes
cache pollution as it didn't include getRaw() in the hash.
Change-Id: I7b9f9b6a5756777462395b911abafb62468cbefa
* No effective change. Only code reformatting.
* Logically group related members.
* Break up items one per line in getHash().
Change-Id: I8ccbe9d071a5c39f5c3d36d0d990574fb0ed8d72
The direction is derived from the language code, which is included
already. The method was added for convenience to consuming code,
but including it in the cache key seems pointless.
Main rationale here is runtime performance. getDirection() incurs
Language::factory() and Language::getDir() which require loading
of LCStore files.
Change-Id: I397a1c483203ec2c4903046c9494cae1c9480f8c
Follows-up r96280 (368dbc5f5b), and r82927 (1e67922842).
Language::isValidCode() (used by index.php) allows a very wide range of values,
which inflates the msg_resource cache quite a bit (T102058). This is a first
step toward locking it down.
This change affects both handling of incoming load.php requests, and the
formatting of request urls by OutputPage. As such, OutputPage will no longer
forward invalid uselang values that are valid for index.php to load.php.
Change-Id: I27857ce5949bc616c7179f5f47b24aa2f6765f5f
Functions must not contain multiple empty lines in a row
(Squiz.WhiteSpace.SuperfluousWhitespace sniff).
Bug: T102774
Change-Id: Ib706e4fc34b95c0d7c887e54af0ea61227767d8f
getDirection() isn't a simple getter value like the others. It actually
is tightly coupled with getLanguage() and lazy-initialised.
When calling setLanguage(), we shouldn't reset direction back to the
parent class but make sure getDirection() will recompute it based
on the local value.
Added regression test (which fails without this patch).
The parent getDirection() looks for $this->request, but the subclass
doesn't assign that member in the constructor. getRequest() forwards
it accordingly, so make sure getRequest() is also used internally.
Change-Id: Ifec703647368c3bb58748288ed754aaaf3730e19
The ResourceLoaderContext class used null to determine absence of
an overridde in the derivative object.
However three of the members in question allow null as legitimate value.
(Namely 'only', 'user', and 'version').
This makes is impossible for a derivative context to remove one
of those values if the parent context has them set.
Use case: I782df43c needs to create a derivative context of
load.php?only=scripts&modules=startup without 'only'.
Use -1 instead as internal placeholder value.
Also:
* ResourceLoaderContext::getSkin() was documented as returning 'string|null' when in
fact it always has a default value. Never returns null.
* DerivativeResourceLoaderContext::setOnly() and setVersion() were missing
type hint for 'null' (as it was incompatible with their getter). Adding 'false'.
* Swap if/else statements to handle the special case first (inheriting).
Allowing the rest of the function body to handle the local value.
In preparation for further development.
Change-Id: I058884525237effe8aef35469ed7693bb7cea591
Modules now track their version via getVersionHash() instead of getModifiedTime().
== Background ==
While some resources have observeable timestamps (e.g. files stored on disk),
many other resources do not. E.g. config variables, and module definitions.
For static file modules, one can e.g. revert one of more files in a module to a
previous version and not affect the max timestamp.
Wiki modules include pages only if they exist. The user module supports common.js
and skin.js. By default neither exists. If a user has both, and then the
less-recently modified one is deleted, the max-timestamp remains unchanged.
For client-side caching, batch requests use "Math.max" on the relevant timestamps.
Again, if a module changes but another module is more recent (e.g. out-of-order
deployment, or out-of-order discovery), the change would not result in a cache miss.
More scenarios can be found in the associated Phabricator tasks.
== Version hash ==
Previously we virtually mapped these variables to a timestamp by storing the current
time alongside a hash of the value in ObjectCache. Considering the number of
possible request contexts (wikis * modules * users * skins * languages) this doesn't
work well. It results in needless cache invalidation when the first time observation
is purged due to LRU algorithms. It also has other minor bugs leading to fewer
cache hits.
All modules automatically get the benefits of version hashing with this change.
The old getDefinitionMtime() and getHashMtime() have been replaced with dummies
that return 1. These functions are often called from getModifiedTime() in subclasses.
For backward-compatibility, their respective values (definition summary and hash)
are now included in getVersionHash directly.
As examples, the following modules have been updated to use getVersionHash directly.
Other modules still work fine and can be updated later.
* ResourceLoaderFileModule
* ResourceLoaderEditToolbarModule
* ResourceLoaderStartUpModule
* ResourceLoaderWikiModule
The presence of hashes in place of timestamps increases the startup module size on
a default MediaWiki install from 4.4k to 5.8k (after gzip and minification).
== ETag ==
Since timestamps are no longer tracked, we need a different way to implement caching
for cache proxies (e.g. Varnish) and web browsers. Previously we used the
Last-Modified header (in combination with Cache-Control and Expires).
Instead of Last-Modified (and If-Modified-Since), we use ETag (and If-None-Match).
Entity tags (new in HTTP/1.1) are much stricter than Last-Modified by default.
They instruct browsers to allow usage of partial Range requests. Since our responses
are dynamically generated, we need to use the Weak version of ETag.
While this sounds bad, it's no different than Last-Modified. As reassured by
RFC 2616 <http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3.3> the
specified behaviour behind Last-Modified follows the same "Weak" caching logic as
Entity tags. It's just that entity tags are capable of a stricter mode (whereas
Last-Modified is inherently weak).
== File cache ==
If $wgUseFileCache is enabled, ResourceLoader uses ResourceFileCache to cache
load.php responses. While the blind TTL handling (during the allowed expiry period)
is still maxage/timestamp based, tryRespondNotModified() now requires the caller to
know the expected ETag.
For this to work, the FileCache handling had to be moved from the top of
ResoureLoader::respond() to after the expected ETag is computed.
This also allows us to remove the duplicate tryRespondNotModified() handling since
that's is already handled by ResourceLoader::respond() meanwhile.
== Misc ==
* Remove redundant modifiedTime cache in ResourceLoaderFileModule.
* Change bugzilla references to Phabricator.
* Centralised inclusion of wgCacheEpoch using getDefinitionSummary. Previously this
logic was duplicated in each place the modified timestamp was used.
* It's easy to forget calling the parent class in getDefinitionSummary().
Previously this method only tracked 'class' by default. As such, various
extensions hardcoded that one value instead of calling the parent and extending
the array. To better prevent this in the future, getVersionHash() now asserts
that the '_cacheEpoch' property made it through.
* tests: Don't use getDefinitionSummary() as an API.
Fix ResourceLoaderWikiModuleTest to call getPages properly.
* In tests, the default timestamp used to be 1388534400000 (which is the unix time
of 20140101000000; the unit tests' CacheEpoch). The new version hash of these
modules is "XyCC+PSK", which is the base64 encoded prefix of the SHA1 digest of:
'{"_class":"ResourceLoaderTestModule","_cacheEpoch":"20140101000000"}'
* Add sha1.js library for client-side hash generation.
Compared various different implementations for code size (after minfication/gzip),
and speed (when used for short hexidecimal strings).
https://jsperf.com/sha1-implementations
- CryptoJS <https://code.google.com/p/crypto-js/#SHA-1> (min+gzip: 2.5k)
http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/sha1.js
Chrome: 45k, Firefox: 89k, Safari: 92k
- jsSHA <https://github.com/Caligatio/jsSHA>
https://github.com/Caligatio/jsSHA/blob/3c1d4f2e/src/sha1.js (min+gzip: 1.8k)
Chrome: 65k, Firefox: 53k, Safari: 69k
- phpjs-sha1 <https://github.com/kvz/phpjs> (RL min+gzip: 0.8k)
https://github.com/kvz/phpjs/blob/1eaab15d/functions/strings/sha1.js
Chrome: 200k, Firefox: 280k, Safari: 78k
Modern browsers implement the HTML5 Crypto API. However, this API is asynchronous,
only enabled when on HTTPS in Chromium, and is quite low-level. It requires boilerplate
code to actually use with TextEncoder, ArrayBuffer and Uint32Array. Due this being
needed in the module loader, we'd have to load the fallback regardless. Considering
this is not used in a critical path for performance, it's not worth shipping two
implementations for this optimisation.
May also resolve:
* T44094
* T90411
* T94810
Bug: T94074
Change-Id: Ibb292d2416839327d1807a66c78fd96dac0637d0
ResourceLoaderImageModule needs a set of SVG files and some data in
the module definition, and produces styles for a set of CSS classes,
one for each image, optionally with differently colored variants,
generated in SVG and PNG, data-URI-embedded if possible, compatible
with all browsers, and generally slick.
The intended usage is to ship icon libraries with MediaWiki that can
be used throughout the pages with no additional code.
* ResourceLoaderImageModule implements all of the logic for data
parsing and CSS generation.
* ResourceLoaderImage implements the logic for SVG image colorization
(for variants) and rasterization.
* ResourceLoader and ResourceLoaderContext were extended to serve a
new kind of load.php request that delivers a single image file. This
is used for fallback PNG images served to browsers that don't
understand SVG.
See change Ic6a76bfb for a demo.
Bug: T76473
Co-Authored-By: Trevor Parscal <trevorparscal@gmail.com>
Co-Authored-By: Bartosz Dziewoński <matma.rex@gmail.com>
Change-Id: Idf6ff4eb8e94f45946f15d283d34108b881fae6e
Introduces ResourceLoaderContext::getUserObj(), which gets
a (possibly cached) User object for the context's username.
Use this instead of the $wgUser global.
Change-Id: Ifd9f634db145381625ab68067ae67791a3f494b8
To do so, created ResourceLoader::createLoaderURL(), which takes a
ResourceLoaderContext object. ResourceLoader::makeLoaderURL() was
deprecated.
While reviewing usage of the old function, many of the callers only
differed by one or two parameters from their respective
ResourceLoaderContext object. To simplify that use case, I created
DerivativeResourceLoaderContext, based of off DerivativeContext for
IContextSource.
Change-Id: I961c641ab953153057be3e3b8cf6c07435e9a0b0
Swapped some "$var type" to "type $var" or added missing types
before the $var. Changed some other types to match the more common
spelling. Makes beginning of some text in captial.
Change-Id: Ifbb1da2a6278b0bde2a6f6ce2e7bd383ee3fb28a
Doxygen expects parameter types to come before the
parameter name in @param tags. Used a quick regex
to switch everything around where possible. This
only fixes cases where a primitve variable (or a
primitive followed by other types) is the variable
type. Other cases will need to be fixed manually.
Change-Id: Ic59fd20856eb0489d70f3469a56ebce0efb3db13
Added/removed spaces around logical/arithmetic operator
Reduced multiple empty lines to one empty line
Removed wrong tabs before comments at end of line
Removed too many spaces in assigments
Change-Id: I2bba4e72f9b5f88c53324d7b70e6042f1aad8f6b
This is needed for mobile scripts that are supposed to work on dumb
devices and as such can't rely on client-side RL, but still can take
advantage of server-side minification and concatenation.
Patchset 2: Allow loading raw modules with &raw=true appended to URL.
Change-Id: I9410ffbf6633075e07bd06b10a98a4d12d9b6106
Also:
* Introduce classes mw-float-end, mw-float-start so we don't have to use inline css depending on wfUILang()/$wgLang (see HistoryPage and SpecialFileDuplicateSearch)
* Add direction mark to protection log
* Remove specialpageattributes as it is obsoleted by this commit (also fixes bug 28572)
* Add two direction marks in wfSpecialList, which makes ltr links on rtl wiki (and vice versa) display nicely as well (only on those special pages however)
* Revert r91340 partially: use mw-content-ltr/rtl class anyway in shared.css. Both ways have their [dis]advantages...
* Set the direction of input fields by default to the content language direction (except buttons etc.) in shared.css
* Replace the overly paranoid regex with a function that simulates IE6's behavior
* Remove the UA check in isPathInfoBad(), was causing more problems than it was worth
* Revert r87711, going back to using dots for dots in ResourceLoader URLs, instead of exclamation marks
* Append &* to ResourceLoader URLs. * is an illegal character in extensions, and putting it at the end of the URL ensures that both IE6 and our detection function will deem the URL to have no extension (unless something like .html? appears in the query string, but in that case we're screwed no matter what)