Skip to content

Instantly share code, notes, and snippets.

@zcorpan
Created October 20, 2015 08:31
Show Gist options
  • Save zcorpan/17ab08f86cdbf6c0d531 to your computer and use it in GitHub Desktop.
Save zcorpan/17ab08f86cdbf6c0d531 to your computer and use it in GitHub Desktop.
<!doctype html>
<meta charset=utf-8>
<script src=https://w3c-test.org/resources/testharness.js></script>
<script>
function collectCharacters(input, pos, chars) {
var startPos = pos;
while (chars.indexOf(input[pos]) != -1) {
pos++;
if (input[pos] === undefined) {
break;
}
}
return [input.substr(startPos, pos), pos];
}
var spaceCharacters = [' ', '\t', '\n', '\f', '\r'];
var asciiDigits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
function skipWhitespace(input, pos) {
return collectCharacters(input, pos, spaceCharacters);
}
function parseMetaRefresh(input) {
var time = 0;
var url = '';
// If another meta element with an http-equiv attribute in the Refresh state has
// already been successfully processed (i.e. when it was inserted the user agent
// processed it and reached the last step of this list of steps), then abort these
// steps.
//
// If the meta element has no content attribute, or if that attribute's value is
// the empty string, then abort these steps.
if (input === '') {
return [];
}
// Let input be the value of the element's content attribute.
//
// Let position point at the first character of input.
var pos = 0;
// Skip whitespace.
[, pos] = skipWhitespace(input, pos);
// Collect a sequence of characters that are ASCII digits, and parse the resulting
// string using the rules for parsing non-negative integers. If the sequence of
// characters collected is the empty string, then no number will have been parsed;
// abort these steps. Otherwise, let time be the parsed number.
var digits;
[digits, pos] = collectCharacters(input, pos, asciiDigits);
if (digits === '') {
return [];
}
var time = parseInt(digits, 10);
// Collect a sequence of characters that are ASCII digits and U+002E FULL STOP
// characters (.). Ignore any collected characters.
[, pos] = collectCharacters(input, pos, [...asciiDigits, '.']);
// Let url be the address of the current page.
url = null;
// If position is past the end of input, jump to the last step.
lastStep: {
if (input[pos] === undefined) {
break lastStep;
}
// If the character in input pointed to by position is not a U+003B SEMICOLON
// character (;), a U+002C COMMA character (,), or a space character, then abort
// these steps.
if ([';', ',', ...spaceCharacters].indexOf(input[pos]) == -1) {
return [];
}
// Skip whitespace.
[, pos] = skipWhitespace(input, pos);
// If the character in input pointed to by position is a U+003B SEMICOLON character
// (;), a U+002C COMMA character (,), then advance position to the next character.
if ([';', ','].indexOf(input[pos]) != -1) {
pos++;
}
// Skip whitespace.
[, pos] = skipWhitespace(input, pos);
// If position is past the end of input, jump to the last step.
if (input[pos] === undefined) {
break lastStep;
}
// Let url be equal to the substring of input from the character at position to the
// end of the string.
url = input.substr(pos);
trim : {
skipQuotes : {
// If the character in input pointed to by position is a U+0055 LATIN CAPITAL
// LETTER U character (U) or a U+0075 LATIN SMALL LETTER U character (u), then
// advance position to the next character. Otherwise, jump to the step labeled skip
// quotes.
if (['U', 'u'].indexOf(input[pos]) != -1) {
pos++;
} else {
break skipQuotes;
}
// If the character in input pointed to by position is a U+0052 LATIN CAPITAL
// LETTER R character (R) or a U+0072 LATIN SMALL LETTER R character (r), then
// advance position to the next character. Otherwise, jump to the step labeled
// trim.
if (['R', 'r'].indexOf(input[pos]) != -1) {
pos++;
} else {
break trim;
}
// If the character in input pointed to by position is s U+004C LATIN CAPITAL
// LETTER L character (L) or a U+006C LATIN SMALL LETTER L character (l), then
// advance position to the next character. Otherwise, jump to the step labeled
// trim.
if (['L', 'l'].indexOf(input[pos]) != -1) {
pos++;
} else {
break trim;
}
// Skip whitespace.
[, pos] = skipWhitespace(input, pos);
// If the character in input pointed to by position is a U+003D EQUALS SIGN (=),
// then advance position to the next character. Otherwise, jump to the step labeled
// trim.
if (input[pos] === '=') {
pos++;
} else {
break trim;
}
// Skip whitespace.
[, pos] = skipWhitespace(input, pos);
} // end label skipQuotes
// Skip quotes: If the character in input pointed to by position is either a U+0027
// APOSTROPHE character (') or U+0022 QUOTATION MARK character ("), then let quote
// be that character, and advance position to the next character. Otherwise, let
// quote be the empty string.
var quote = '';
if (['\'', '"'].indexOf(input[pos]) != -1) {
quote = input[pos];
pos++;
}
// Let url be equal to the substring of input from the character at position to the
// end of the string.
url = input.substr(pos);
// If quote is not the empty string, and there is a character in url equal to
// quote, then truncate url at that character, so that it and all subsequent
// characters are removed.
if (quote !== '' && url.indexOf(quote) != -1) {
url = url.substr(0, url.indexOf(quote));
}
} // end label trim
// Trim: Strip any trailing space characters from the end of url.
url = url.replace(new RegExp('[' + spaceCharacters.join('') + ']+$'), '');
// Strip any U+0009 CHARACTER TABULATION (tab), U+000A LINE FEED (LF), and U+000D
// CARRIAGE RETURN (CR) characters from url.
url = url.replace(/[\t\n\r]/g, '');
// Resolve the url value to an absolute URL, relative to the meta element. If this
// fails, abort these steps.
} // end label lastStep
// Perform one or more of the following steps:
//
// ...
return [time, url];
}
// failure is []
// success is [time, url] where url is unresolved, and null means document's current address
var tests = [
{input: '', expected: []},
{input: '1', expected: [1, null]},
{input: '1;', expected: [1, null]},
{input: '1,', expected: [1, null]},
{input: '1; url=foo', expected: [1, 'foo']},
{input: '1, url=foo', expected: [1, 'foo']},
{input: '1 url=foo', expected: [1, 'foo']},
{input: '1url=foo', expected: []},
{input: '1x;url=foo', expected: []},
{input: '1 x;url=foo', expected: [1, 'x;url=foo']},
{input: '1;;url=foo', expected: [1, ';url=foo']},
{input: ' 1 ; url = foo', expected: [1, 'foo']},
{input: '1; url=foo ', expected: [1, 'foo']},
{input: '1; url=f\to\no', expected: [1, 'foo']},
{input: '1; url="foo"bar', expected: [1, 'foo']},
{input: '1; url=\'foo\'bar', expected: [1, 'foo']},
{input: '1; url="foo\'bar', expected: [1, 'foo\'bar']},
{input: '1; url foo', expected: [1, 'url foo']},
{input: '1; urlfoo', expected: [1, 'urlfoo']},
{input: '1; urfoo', expected: [1, 'urfoo']},
{input: '1; ufoo', expected: [1, 'ufoo']},
{input: '1; "foo"bar', expected: [1, 'foo']},
{input: '; foo', expected: []},
{input: ', foo', expected: []},
{input: 'foo', expected: []},
{input: '+1; url=foo', expected: []},
{input: '-1; url=foo', expected: []},
{input: '-0; url=foo', expected: []},
{input: '1.9; url=foo', expected: [1, 'foo']},
{input: '1.9..5.; url=foo', expected: [1, 'foo']},
{input: '.9; url=foo', expected: []},
];
tests.forEach(function(t) {
test(function() {
assert_array_equals(parseMetaRefresh(t.input), t.expected);
}, format_value(t.input));
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment