Author: jmsnell Date: Thu Dec 22 05:30:31 2011 New Revision: 1222042 URL: http://svn.apache.org/viewvc?rev=1222042&view=rev Log: Test cases and fixes....
now we're passing all but one of these: http://greenbytes.de/tech/tc/httplink/ the one we're not is a crazy edge case.. not worried about it for now Added: abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/WebLinkTest.java (with props) Modified: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Authentication.java abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Preference.java abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/WebLink.java abdera/abdera2/common/src/main/java/org/apache/abdera2/common/text/CharUtils.java abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/AuthenticationTest.java Modified: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Authentication.java URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Authentication.java?rev=1222042&r1=1222041&r2=1222042&view=diff ============================================================================== --- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Authentication.java (original) +++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Authentication.java Thu Dec 22 05:30:31 2011 @@ -29,6 +29,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.abdera2.common.misc.MoreFunctions; +import org.apache.abdera2.common.text.CharUtils; import org.apache.abdera2.common.text.CharUtils.Profile; import org.apache.abdera2.common.text.Codec; @@ -91,13 +92,6 @@ public class Authentication implements I } }; - public static String unescape(String quoted) { - StringBuilder buf = new StringBuilder(); - for (char c : quoted.toCharArray()) - if (c != '\\') buf.append(c); - return buf.toString(); - } - public static Iterable<Authentication> parse(String challenge) { checkNotNull(challenge); List<Authentication> challenges = new ArrayList<Authentication>(); @@ -119,7 +113,7 @@ public class Authentication implements I String name = ps[0]; if (name.charAt(name.length()-1)=='*') name = name.substring(0,name.length()-1); - auth.param(name, Codec.decode(unquote(unescape(ps[1])))); + auth.param(name, Codec.decode(unquote(CharUtils.unescape(ps[1])))); } } challenges.add(auth.get()); Modified: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Preference.java URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Preference.java?rev=1222042&r1=1222041&r2=1222042&view=diff ============================================================================== --- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Preference.java (original) +++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/Preference.java Thu Dec 22 05:30:31 2011 @@ -364,7 +364,7 @@ public class Preference implements Seria String[] ps = pref.split("\\s*\\*?=\\s*", 2); token = ps[0].trim(); if (ps.length == 2) - tokenval = Codec.decode(CharUtils.unquote(Authentication.unescape(ps[1]))); + tokenval = Codec.decode(CharUtils.unquote(CharUtils.unescape(ps[1]))); } Preference.Builder maker = @@ -375,7 +375,7 @@ public class Preference implements Seria String p = mparams.group(1); String[] ps = p.split("\\s*\\*?=\\s*", 2); if (ps.length == 2) - maker.param(ps[0], Codec.decode(CharUtils.unquote(Authentication.unescape(ps[1])))); + maker.param(ps[0], Codec.decode(CharUtils.unquote(CharUtils.unescape(ps[1])))); else maker.param(ps[0]); } } Modified: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/WebLink.java URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/WebLink.java?rev=1222042&r1=1222041&r2=1222042&view=diff ============================================================================== --- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/WebLink.java (original) +++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/http/WebLink.java Thu Dec 22 05:30:31 2011 @@ -426,26 +426,26 @@ public class WebLink implements Serializ String name = text.substring(s+1,text.charAt(e-1)=='*'?e-1:e).trim(); s = scanFor(';', text,e+1,false); String val = s!=-1?text.substring(e+1,s).trim():text.substring(e+1).trim(); - val = Codec.decode(val).toLowerCase(Locale.US); + val = unescape(unquote(Codec.decode(val))); if (name.equals("rel")) - for (String v : unquote(val).split("\\s+")) + for (String v : val.toLowerCase(Locale.US).split("\\s+")) maker.rel(v); else if (name.equals("anchor")) maker.anchor(unwrap(val, '<', '>')); else if (name.equals("rev")) - for (String v : unquote(val).split("\\s+")) + for (String v : val.toLowerCase(Locale.US).split("\\s+")) maker.rev(v); else if (name.equals("hreflang")) - maker.lang(unquote(val)); + maker.lang(val.toLowerCase(Locale.US)); else if (name.equals("media")) - for (String v : unquote(val).split("\\s+")) + for (String v : val.toLowerCase(Locale.US).split("\\s+")) maker.media(v); else if (name.equals("title")) - maker.title(unquote(val)); + maker.title(val); else if (name.equals("type")) - maker.mediaType(unquote(val)); + maker.mediaType(val.toLowerCase(Locale.US)); else - maker.param(name,unquote(val)); + maker.param(name,val); } links.add(maker.get()); if (s == -1) break; Modified: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/text/CharUtils.java URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/text/CharUtils.java?rev=1222042&r1=1222041&r2=1222042&view=diff ============================================================================== --- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/text/CharUtils.java (original) +++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/text/CharUtils.java Thu Dec 22 05:30:31 2011 @@ -122,12 +122,20 @@ public final class CharUtils { } public static String unquote(String s) { - if (s == null || s.length() == 0) - return s; - int n = 0, e = s.length(); - if (s.charAt(0) == '"') n++; - if (s.charAt(e-1) == '"' && s.charAt(e-2) != '\\') e--; - return s.substring(n,e); + StringBuilder buf = new StringBuilder(); + int i = s.length(); + boolean quoted = false, escaped = false; + for (int n = 0; n < s.length(); n++) { + char c = s.charAt(n); + if (n == 0 && c == '"') { + quoted = true; + } else if (!(quoted && n+1==i && !escaped && c == '"')) + buf.append(c); + if (escaped) escaped = false; + else if (c == '\\' && !escaped) + escaped = true; + } + return buf.toString(); } public static String[] splitAndTrim( @@ -210,4 +218,18 @@ public final class CharUtils { public static final Joiner joiner = Joiner.on(',').skipNulls(); + public static String unescape(String quoted) { + StringBuilder buf = new StringBuilder(); + int i = quoted.length(); + for (int n = 0; n < i; n++) { + char c = quoted.charAt(n); + if (c != '\\') buf.append(c); + else if (n < i-1 && quoted.charAt(n+1) == '\\') { + buf.append(c); + n++; + } + } + return buf.toString(); + } + } Modified: abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/AuthenticationTest.java URL: http://svn.apache.org/viewvc/abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/AuthenticationTest.java?rev=1222042&r1=1222041&r2=1222042&view=diff ============================================================================== --- abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/AuthenticationTest.java (original) +++ abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/AuthenticationTest.java Thu Dec 22 05:30:31 2011 @@ -11,7 +11,7 @@ import org.apache.abdera2.common.http.Au import org.junit.Test; import com.google.common.collect.Iterables; - +@SuppressWarnings("unchecked") public class AuthenticationTest { @Test Added: abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/WebLinkTest.java URL: http://svn.apache.org/viewvc/abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/WebLinkTest.java?rev=1222042&view=auto ============================================================================== --- abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/WebLinkTest.java (added) +++ abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/WebLinkTest.java Thu Dec 22 05:30:31 2011 @@ -0,0 +1,282 @@ +package org.apache.abdera2.test.common.http; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.apache.abdera2.common.http.WebLink; +import org.apache.abdera2.common.iri.IRI; +import org.apache.abdera2.common.mediatype.MimeTypeHelper; +import org.junit.Test; +import static org.junit.Assert.assertThat; +import static org.junit.matchers.JUnitMatchers.*; +import static org.hamcrest.CoreMatchers.*; + +import com.google.common.collect.Iterables; +import org.apache.abdera2.common.text.InvalidCharacterException; + +public class WebLinkTest { + + @Test + public void simplecss() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals(new IRI("simple.css"),link.getIri()); + assertThat(link.getRel(),hasItem("stylesheet")); + } + + @Test(expected=InvalidCharacterException.class) + public void simplecssreversed() { + WebLink.parse("rel=stylesheet; <fail.css>"); + } + + @Test + public void simplecsssq() { + Iterable<WebLink> il = WebLink.parse("<fail.css>; rel='stylesheet'"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertThat(link.getRel(),not(hasItem("stylesheet"))); // it will be 'stylesheet', which is incorrect + } + + @Test + public void simplecssmrel() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; rel=\"foobar stylesheet\""); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals(new IRI("simple.css"),link.getIri()); + assertThat(link.getRel(),hasItems("stylesheet","foobar")); + } + + @SuppressWarnings("unchecked") + @Test + public void simplecssmlink() { + Iterable<WebLink> il = WebLink.parse("<foo>; rel=bar, <simple.css>; rel=stylesheet"); + assertEquals(2,Iterables.size(il)); + for (WebLink link : il) { + assertThat(link.getIri().toString(), anyOf(is("foo"),is("simple.css"))); + assertThat(link.getRel(), anyOf(hasItems("bar"),hasItems("stylesheet"))); + } + } + + @Test + public void simplecssanchr() { + Iterable<WebLink> il = WebLink.parse("<fail.css>; anchor=\"http://example.com/\"; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("fail.css",link.getIri().toString()); + assertEquals("http://example.com/fail.css",link.getResolvedIri(new IRI("http://foo.com/")).toString()); + // this is a redflag! this IRI resolved to a different base URI than + // what was passed in! applications need to take great care as this + // could be a possible attack vector! + } + + @Test + public void simplecssanchrsame() { + Iterable<WebLink> il = WebLink.parse("<fail.css>; anchor=\"\"; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("fail.css",link.getIri().toString()); + assertEquals("http://foo.com/fail.css",link.getResolvedIri(new IRI("http://foo.com/")).toString()); + // this is an appropriate response + } + + @Test + public void simplecssanchrsame2() { + Iterable<WebLink> il = WebLink.parse("<fail.css>; anchor=\"\"; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("fail.css",link.getIri().toString()); + assertEquals("http://foo.com/fail.css",link.getResolvedIri(new IRI("http://foo.com/#foo")).toString()); + // this is an appropriate response + } + + @Test + public void simplecssanchrsamefrag() { + Iterable<WebLink> il = WebLink.parse("<fail.css>; anchor=\"#foo\"; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("fail.css",link.getIri().toString()); + assertEquals("http://foo.com/fail.css",link.getResolvedIri(new IRI("http://foo.com/")).toString()); + // this is an appropriate response + } + + @Test + public void simplecssanchrsamefrag2() { + Iterable<WebLink> il = WebLink.parse("<fail.css>; anchor=\"#foo\"; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("fail.css",link.getIri().toString()); + assertEquals("http://foo.com/fail.css",link.getResolvedIri(new IRI("http://foo.com/#foo")).toString()); + // this is an appropriate response + } + + @Test + public void simplexslttypenotype() { + Iterable<WebLink> il = WebLink.parse("<simple.xslt>; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("simple.xslt",link.getIri().toString()); + assertThat(link.getRel(),hasItem("stylesheet")); + } + + @Test + public void simplexslttypedepr() { + Iterable<WebLink> il = WebLink.parse("<simple.xslt>; rel=stylesheet; type=\"text/xsl\""); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("simple.xslt",link.getIri().toString()); + assertThat(link.getRel(),hasItem("stylesheet")); + assertTrue(MimeTypeHelper.isMatch(link.getMediaType(), MimeTypeHelper.create("text/xsl"))); + } + + @Test + public void simplexslttypedepr2() { + Iterable<WebLink> il = WebLink.parse("<simple.xslt.asis>; rel=stylesheet; type=\"text/xsl\""); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("simple.xslt.asis",link.getIri().toString()); + assertThat(link.getRel(),hasItem("stylesheet")); + assertTrue(MimeTypeHelper.isMatch(link.getMediaType(), MimeTypeHelper.create("text/xsl"))); + } + + @Test + public void simplexslttypeoff() { + Iterable<WebLink> il = WebLink.parse("<simple.xslt>; rel=stylesheet; type=\"application/xslt+xml\""); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("simple.xslt.asis",link.getIri().toString()); + assertThat(link.getRel(),hasItem("stylesheet")); + assertTrue(MimeTypeHelper.isMatch(link.getMediaType(), MimeTypeHelper.create("text/xsl"))); + } + + @Test + public void simplecsstitle() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; rel=stylesheet; title=\"A simple CSS stylesheet\""); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("simple.css",link.getIri().toString()); + assertThat(link.getRel(),hasItem("stylesheet")); + assertEquals(link.getTitle(),"A simple CSS stylesheet"); + } + + @Test + public void simplecsstitleq() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; rel=stylesheet; title=\"title with a DQUOTE \\\" and backslash: \\\\\""); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("title with a DQUOTE \" and backslash: \\",link.getTitle()); + } + + @Test + public void simplecsstitleq2() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; title=\"title with a DQUOTE \\\" and backslash: \\\\\"; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("title with a DQUOTE \" and backslash: \\",link.getTitle()); + } + + @Test + public void simplecsstitletok() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; rel=stylesheet; title=AsimpleCSSstylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("AsimpleCSSstylesheet",link.getTitle()); + // not strictly allowed per the spec + } + + @Test + public void simplecsstitle5987() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; rel=stylesheet; title*=UTF-8''stylesheet-%E2%82%AC"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("stylesheet-\u20AC",link.getTitle()); + } + + @Test + public void simplecsstitle5987r() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; title*=UTF-8''stylesheet-%E2%82%AC; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("stylesheet-\u20AC",link.getTitle()); + } + + @Test + public void simplecsstitle5987iso88591() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; title*=iso-8859-1''stylesheet-%E4; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("stylesheet-\u00E4",link.getTitle()); + } + + @Test + public void simplecsstitle5987noenc() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; title*=''A%20simple%20CSS%20stylesheet; title=\"fallback title\"; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("fallback title", link.getTitle()); + // this passes, but not for the reason its supposed to + } + + @Test + public void simplecsstitle5987parseerror() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; title*=foobar; title=\"fallback title\"; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("fallback title", link.getTitle()); + // this passes, but not for the reason its supposed to + } + + @Test + public void simplecsstitle5987parseerror2() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; title*=UTF-8''foobar%; title=\"fallback title\"; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("fallback title", link.getTitle()); + // this passes, but not for the reason its supposed to + } + + @Test + public void simpleext() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; ext=foo; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("foo",link.getParam("ext")); + } + + @Test + public void simpleextq() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; ext=\"\\\"\"; rel=stylesheet"); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertEquals("\"",link.getParam("ext")); + } + +// This isn't supported +// @Test +// public void simpleexta() { +// Iterable<WebLink> il = WebLink.parse("<simple.css>; ext1='start; rel=stylesheet; ext2=end'"); +// assertEquals(1,Iterables.size(il)); +// WebLink link = il.iterator().next(); +// System.out.println(link.getParam("ext1")); +// } + + @Test + public void simpleextrel() { + Iterable<WebLink> il = WebLink.parse("<simple.css>; rel=\"http://example.com/myrel stylesheet\""); + assertEquals(1,Iterables.size(il)); + WebLink link = il.iterator().next(); + assertThat(link.getRel(),hasItems("stylesheet","http://example.com/myrel")); + } + + @Test + public void simplecss2() { + Iterable<WebLink> il = WebLink.parse("<ybg.css>; rel=stylesheet, <simple.css>; rel=stylesheet"); + assertEquals(2, Iterables.size(il)); + } + + @Test + public void simplecssafterother() { + Iterable<WebLink> il = WebLink.parse("<ybf.css>; rel=foobar, <simple.css>; rel=stylesheet"); + assertEquals(2, Iterables.size(il)); + } +} Propchange: abdera/abdera2/test/src/main/java/org/apache/abdera2/test/common/http/WebLinkTest.java ------------------------------------------------------------------------------ svn:mime-type = text/plain
