12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- 'use strict';
- var token = '%[a-f0-9]{2}';
- var singleMatcher = new RegExp('(' + token + ')|([^%]+?)', 'gi');
- var multiMatcher = new RegExp('(' + token + ')+', 'gi');
- function decodeComponents(components, split) {
- try {
- // Try to decode the entire string first
- return [decodeURIComponent(components.join(''))];
- } catch (err) {
- // Do nothing
- }
- if (components.length === 1) {
- return components;
- }
- split = split || 1;
- // Split the array in 2 parts
- var left = components.slice(0, split);
- var right = components.slice(split);
- return Array.prototype.concat.call([], decodeComponents(left), decodeComponents(right));
- }
- function decode(input) {
- try {
- return decodeURIComponent(input);
- } catch (err) {
- var tokens = input.match(singleMatcher) || [];
- for (var i = 1; i < tokens.length; i++) {
- input = decodeComponents(tokens, i).join('');
- tokens = input.match(singleMatcher) || [];
- }
- return input;
- }
- }
- function customDecodeURIComponent(input) {
- // Keep track of all the replacements and prefill the map with the `BOM`
- var replaceMap = {
- '%FE%FF': '\uFFFD\uFFFD',
- '%FF%FE': '\uFFFD\uFFFD'
- };
- var match = multiMatcher.exec(input);
- while (match) {
- try {
- // Decode as big chunks as possible
- replaceMap[match[0]] = decodeURIComponent(match[0]);
- } catch (err) {
- var result = decode(match[0]);
- if (result !== match[0]) {
- replaceMap[match[0]] = result;
- }
- }
- match = multiMatcher.exec(input);
- }
- // Add `%C2` at the end of the map to make sure it does not replace the combinator before everything else
- replaceMap['%C2'] = '\uFFFD';
- var entries = Object.keys(replaceMap);
- for (var i = 0; i < entries.length; i++) {
- // Replace all decoded components
- var key = entries[i];
- input = input.replace(new RegExp(key, 'g'), replaceMap[key]);
- }
- return input;
- }
- module.exports = function (encodedURI) {
- if (typeof encodedURI !== 'string') {
- throw new TypeError('Expected `encodedURI` to be of type `string`, got `' + typeof encodedURI + '`');
- }
- try {
- encodedURI = encodedURI.replace(/\+/g, ' ');
- // Try the built in decoder first
- return decodeURIComponent(encodedURI);
- } catch (err) {
- // Fallback to a more advanced decoder
- return customDecodeURIComponent(encodedURI);
- }
- };
|