Skip to content

Commit

Permalink
sys: MimeType.parseParams enhance to handle empty values for Safari c…
Browse files Browse the repository at this point in the history
…ookies
  • Loading branch information
briansfrank committed Jul 10, 2024
1 parent 1529383 commit 16ba22f
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 26 deletions.
14 changes: 9 additions & 5 deletions src/sys/es/fan/MimeType.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,14 @@ class MimeType extends Obj {
static #doParseParams(s, offset) {
const params = Map.make(Str.type$, Str.type$);
params.caseInsensitive(true);
let len = s.length;
let inQuotes = false;
let keyStart = offset;
let valStart = -1;
let valEnd = -1;
let eq = -1;
let hasEsc = false;
for (let i=keyStart; i<s.length; ++i) {
for (let i=keyStart; i<len; ++i) {
let c = s.charAt(i);

// let parens slide since sometimes they occur in cookies
Expand All @@ -104,10 +105,12 @@ class MimeType extends Obj {

if (c == '=' && eq < 0 && !inQuotes) {
eq = i++;
while (MimeType.#isSpace(s, i)) ++i;
while (i<len && MimeType.#isSpace(s, i)) ++i;
if (i >= len) break;
if (s.charAt(i) == '"') { inQuotes = true; ++i; c = s.charAt(i); }
else inQuotes = false;
valStart = i;
c = s.charAt(i);
}

if (c == ';' && eq < 0 && !inQuotes) {
Expand Down Expand Up @@ -145,13 +148,14 @@ class MimeType extends Obj {
}
}

if (keyStart < s.length) {
if (valEnd < 0) valEnd = s.length-1;
if (keyStart < len) {
if (eq < 0) {
var key = Str.trim(s.slice(keyStart, s.length));
var key = Str.trim(s.slice(keyStart, len));
params.set(key, "");
}
else {
if (valStart < 0) valStart = eq+1;
if (valEnd < 0) valEnd = len-1;
let key = Str.trim(s.slice(keyStart, eq));
let val = Str.trim(s.slice(valStart, valEnd+1));
if (hasEsc) val = MimeType.#unescape(val);
Expand Down
18 changes: 12 additions & 6 deletions src/sys/java/fan/sys/MimeType.java
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,15 @@ private static Map doParseParams(String s, int offset)
{
Map params = new Map(Sys.StrType, Sys.StrType);
params.caseInsensitive(true);
int len = s.length();
boolean inQuotes = false;
int keyStart = offset;
int valStart = -1;
int valEnd = -1;
int eq = -1;
boolean hasEsc = false;
for (int i = keyStart; i<s.length(); ++i)

for (int i = keyStart; i<len; ++i)
{
int c = s.charAt(i);

Expand All @@ -127,10 +129,12 @@ private static Map doParseParams(String s, int offset)
if (c == '=' && !inQuotes && valStart < 0)
{
eq = i++;
while (FanInt.isSpace(s.charAt(i))) ++i;
while (i<len && FanInt.isSpace(s.charAt(i))) ++i;
if (i >= len) break;
if (s.charAt(i) == '"') { inQuotes = true; ++i; c=s.charAt(i); }
else inQuotes = false;
valStart = i;
c = s.charAt(i);
}

if (c == ';' && eq < 0 && !inQuotes)
Expand Down Expand Up @@ -172,16 +176,17 @@ private static Map doParseParams(String s, int offset)
}
}

if (keyStart < s.length())
if (keyStart < len)
{
if (valEnd < 0) valEnd = s.length()-1;
if (eq < 0)
{
String key = s.substring(keyStart, s.length()).trim();
String key = s.substring(keyStart, len).trim();
params.set(key, "");
}
else
{
if (valStart < 0) valStart = eq+1;
if (valEnd < 0) valEnd = len-1;
String key = s.substring(keyStart, eq).trim();
String val = s.substring(valStart, valEnd+1).trim();
if (hasEsc) val = unescape(val);
Expand Down Expand Up @@ -338,4 +343,5 @@ static Map emptyParams()
private Map params;
private String str;

}
}

19 changes: 12 additions & 7 deletions src/sys/js/fan/MimeType.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,14 @@ fan.sys.MimeType.doParseParams = function(s, offset)
{
var params = fan.sys.Map.make(fan.sys.Str.$type, fan.sys.Str.$type);
params.caseInsensitive$(true);
var len = s.length;
var inQuotes = false;
var keyStart = offset;
var valStart = -1;
var valEnd = -1;
var eq = -1;
var hasEsc = false;
for (var i=keyStart; i<s.length; ++i)
for (var i=keyStart; i<len; ++i)
{
var c = s.charAt(i);

Expand All @@ -96,10 +97,12 @@ fan.sys.MimeType.doParseParams = function(s, offset)
if (c == '=' && eq < 0 && !inQuotes)
{
eq = i++;
while (fan.sys.MimeType.isSpace(s, i)) ++i;
while (i<len && fan.sys.MimeType.isSpace(s, i)) ++i;
if (i >= len) break;
if (s.charAt(i) == '"') { inQuotes = true; ++i; c = s.charAt(i); }
else inQuotes = false;
valStart = i;
c = s.charAt(i);
}

if (c == ';' && eq < 0 && !inQuotes)
Expand Down Expand Up @@ -141,19 +144,20 @@ fan.sys.MimeType.doParseParams = function(s, offset)
}
}

if (keyStart < s.length)
if (keyStart < len)
{
if (valEnd < 0) valEnd = s.length-1;
if (eq < 0)
{
var key = fan.sys.Str.trim(s.substring(keyStart, s.length));
var key = fan.sys.Str.trim(s.substring(keyStart, len));
params.set(key, "");
}
else
{
if (valStart < 0) valStart = eq+1;
if (valEnd < 0) valEnd = len-1;
var key = fan.sys.Str.trim(s.substring(keyStart, eq));
var val = fan.sys.Str.trim(s.substring(valStart, valEnd+1));
if (hasEsc) val = fan.sys.MimeType.unscape(val);
if (hasEsc) val = fan.sys.MimeType.unescape(val);
params.set(key, val);
}
}
Expand Down Expand Up @@ -313,4 +317,5 @@ fan.sys.MimeType.predefined = function(media, sub, params)
// Static Fields
//////////////////////////////////////////////////////////////////////////

// see sysPod.js
// see sysPod.js

22 changes: 15 additions & 7 deletions src/testSys/fan/MimeTypeTest.fan
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ class MimeTypeTest : Test
verifyFromStr("a/b; charset=foo (comment)", "a", "b", ["charset":"foo (comment)"])

verifyFromStrBad("foo")
verifyFromStrBad("a/b; x=")
}

Void verifyFromStr(Str s, Str media, Str sub, [Str:Str]? params)
Expand Down Expand Up @@ -141,6 +140,17 @@ class MimeTypeTest : Test
verifyParseParams("a=b; c", ["a":"b", "c":""])
verifyParseParams("a=b; cx", ["a":"b", "cx":""])

// not sure this is valid to have empty string; but have seen
// Safari send cookies like this
verifyParseParams("a=", ["a":""])
verifyParseParams("a =", ["a":""])
verifyParseParams("a= ", ["a":""])
verifyParseParams("a = ", ["a":""])
verifyParseParams("a=; b=foo", ["a":"", "b":"foo"])
verifyParseParams("a=foo; b=", ["a":"foo", "b":""])
verifyParseParams("a=foo; b=; c=bar", ["a":"foo", "b":"", "c":"bar"])
verifyParseParams("a = foo; b = ; c =bar ", ["a":"foo", "b":"", "c":"bar"])

// not sure this is actually correctly formatted to have equals
// in unquoted values, but have seen Chrome send cookies like this
verifyParseParams("""a=sdecbc682; tz=America/New_York; b="05df13cc-9ef1"; c=MDI1MzE=; d=ABC=""",
Expand All @@ -149,15 +159,12 @@ class MimeTypeTest : Test
"b": "05df13cc-9ef1",
"c": "MDI1MzE=",
"d": "ABC="])

verifyEq(MimeType.parseParams("n=", false), null)
verifyErr(ParseErr#) { MimeType.parseParams("x=f;y=") }
}

Void verifyParseParams(Str s, Str:Str params)
Void verifyParseParams(Str s, Str:Str expect)
{
p := MimeType.parseParams(s)
verifyEq(p, params)
verifyEq(p, expect)
verifyEq(p.caseInsensitive, true)
}

Expand Down Expand Up @@ -218,4 +225,5 @@ class MimeTypeTest : Test
x := MimeType(s)
verifyEq(x.isText, expect)
}
}
}

10 changes: 9 additions & 1 deletion src/web/test/CookieTest.fan
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ class CookieTest : Test
"VERSION-foo%2Fbar": "unspecified",
"__u": "1303429918|un=(referral)|ud=referral"])

// test key=(no val)
s = "mm_testcookie_storage=; foobar=123; _ga_DGW3P9MPX4=GS1.2.1720526761"
verifyEq(MimeType.parseParams(s),
["mm_testcookie_storage": "",
"foobar": "123",
"_ga_DGW3P9MPX4": "GS1.2.1720526761"])

verifyCookie(Cookie("foo=bar"), Cookie("foo", "bar"))
verifyCookie(Cookie("foo=\"bar baz\""), Cookie("foo", "\"bar baz\""))
verifyCookie(Cookie("foo=\"_\\\"quot\\\"_\""), Cookie("foo", "\"_\\\"quot\\\"_\""))
Expand Down Expand Up @@ -68,4 +75,5 @@ class CookieTest : Test
verifyEq(c.sameSite, "strict")
}

}
}

0 comments on commit 16ba22f

Please sign in to comment.