Author: toad
Date: 2006-10-27 23:23:42 +0000 (Fri, 27 Oct 2006)
New Revision: 10717
Added:
trunk/freenet/src/freenet/clients/http/filter/CommentException.java
Modified:
trunk/freenet/src/freenet/clients/http/filter/CSSParser.java
trunk/freenet/src/freenet/clients/http/filter/CSSTokenizerFilter.java
trunk/freenet/src/freenet/clients/http/filter/CSSTokenizerFilter.jflex
trunk/freenet/src/freenet/clients/http/filter/FilterCallback.java
trunk/freenet/src/freenet/clients/http/filter/GenericReadFilterCallback.java
trunk/freenet/src/freenet/clients/http/filter/HTMLFilter.java
Log:
If a URL is dropped by the filter because it is invalid, return feedback in
comments explaining why.
Modified: trunk/freenet/src/freenet/clients/http/filter/CSSParser.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/filter/CSSParser.java
2006-10-27 19:47:14 UTC (rev 10716)
+++ trunk/freenet/src/freenet/clients/http/filter/CSSParser.java
2006-10-27 23:23:42 UTC (rev 10717)
@@ -41,11 +41,11 @@
HTMLFilter.throwFilterException(s);
}
- String processImportURL(String s) {
+ String processImportURL(String s) throws CommentException {
return HTMLFilter.sanitizeURI(HTMLFilter.stripQuotes(s),
"text/css", null, cb);
}
- String processURL(String s) {
+ String processURL(String s) throws CommentException {
return HTMLFilter.sanitizeURI(HTMLFilter.stripQuotes(s), null,
null, cb);
}
Modified: trunk/freenet/src/freenet/clients/http/filter/CSSTokenizerFilter.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/filter/CSSTokenizerFilter.java
2006-10-27 19:47:14 UTC (rev 10716)
+++ trunk/freenet/src/freenet/clients/http/filter/CSSTokenizerFilter.java
2006-10-27 23:23:42 UTC (rev 10717)
@@ -1,4 +1,4 @@
-/* The following code was generated by JFlex 1.4.1 on 06/10/06 19:33 */
+/* The following code was generated by JFlex 1.4.1 on 28/10/06 00:17 */
/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
@@ -14,7 +14,7 @@
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.4.1
- * on 06/10/06 19:33 from the specification file
+ * on 28/10/06 00:17 from the specification file
* <tt>freenet/clients/http/filter/CSSTokenizerFilter.jflex</tt>
*/
class CSSTokenizerFilter {
@@ -852,11 +852,11 @@
throw new IllegalStateException("You MUST override
throwError!");
}
- String processImportURL(String s) {
+ String processImportURL(String s) throws CommentException {
throw new IllegalStateException("You MUST override
processImportURL!");
}
- String processURL(String s) {
+ String processURL(String s) throws CommentException {
throw new IllegalStateException("You MUST override
processURL!");
}
@@ -1003,6 +1003,18 @@
return sb.toString();
}
}
+
+ String commentEncode(String s) {
+ StringBuffer sb = new StringBuffer(s.length());
+ for(int i=0;i<s.length();i++) {
+ char c = sb.charAt(i);
+ if(c == '/')
+ sb.append("\\/");
+ else
+ sb.append(c);
+ }
+ return sb.toString();
+ }
/**
@@ -1292,30 +1304,63 @@
zzMarkedPos = zzMarkedPosL;
switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
+ case 23:
+ { // This is horrible. However it seems that there is no other way
to do it with either jflex or CUP, as {URL} cannot be an unambiguous token :(
+ String s = yytext();
+ if(debug) log("Recognized URL: "+s);
+
+ DecodedStringThingy dst = new DecodedStringThingy(s);
+
+ if(!dst.url) {
+ throw new IllegalStateException("parsing url().. isn't a
url()");
+ }
+ if(dst.suffix.length() > 0) {
+ yypushback(dst.suffix.length());
+ dst.suffix = "";
+ }
+
+ s = dst.data;
+ if(debug) log("URL now: "+s);
+ try {
+ s = processURL(s);
+ dst.data = s;
+ if(s == null || s.equals("")) {
+ if(debug) log("URL invalid");
+ w.write("url()");
+ } else {
+ s = dst.toString();
+ if(debug) log("Writing: "+s);
+ w.write(s);
+ }
+ } catch (CommentException e) {
+ w.write("/* "+commentEncode(e.getMessage())+" */");
+ }
+ }
+ case 31: break;
case 18:
{ String s = yytext();
w.write(s);
if(debug) log("Matched unicode: "+s);
}
- case 31: break;
+ case 32: break;
case 8:
{ String s = yytext();
w.write(s);
if(debug) log("Matched close braces: "+s);
}
- case 32: break;
+ case 33: break;
case 22:
{ String s = yytext();
w.write(s);
if(debug) log("Matched HTML comment: "+s);
}
- case 33: break;
+ case 34: break;
case 16:
{ String s = yytext();
w.write(s);
if(debug) log("Matched ~=: "+s);
}
- case 34: break;
+ case 35: break;
case 12:
{ String s = yytext();
if(debug) log("Matched string: "+s);
@@ -1326,87 +1371,81 @@
w.write(s);
}
}
- case 35: break;
+ case 36: break;
case 25:
{ String s = yytext();
w.write(s);
if(debug) log("Matched @page: "+s);
}
- case 36: break;
+ case 37: break;
case 13:
{ String s = yytext();
w.write(s);
if(debug) log("Matched number: "+s);
}
- case 37: break;
+ case 38: break;
case 1:
{ String s = yytext();
char c = s.charAt(0);
log("Matched anything: "+yytext()+" - ignoring");
w.write("/* ignored unmatched char: "+c+" */"); // single char cannot
break out of comment
}
- case 38: break;
+ case 39: break;
case 6:
{ String s = yytext();
w.write(s);
if(debug) log("Matched semicolon: "+s);
}
- case 39: break;
+ case 40: break;
case 20:
{ String s = yytext();
if(debug) log("Got hexcolor: "+s);
w.write(s);
}
- case 40: break;
+ case 41: break;
case 7:
{ String s = yytext();
w.write(s);
if(debug) log("Matched open braces: "+s);
}
- case 41: break;
+ case 42: break;
case 26:
{ String s = yytext();
s = s.substring("@media".length()).trim();
w.write("@media "+s+" ");
if(debug) log("Matched @media: "+s);
}
- case 42: break;
+ case 43: break;
case 2:
{ String s = yytext();
w.write(s);
if(debug) log("Matched ident: "+s);
}
- case 43: break;
+ case 44: break;
case 24:
{ String s = yytext();
w.write(s);
if(debug) log("Matched unicode range: "+s);
}
- case 44: break;
+ case 45: break;
case 28:
{ String s = yytext();
w.write(s);
if(debug) log("Matched @font-face: "+s);
}
- case 45: break;
+ case 46: break;
case 19:
{ String s = yytext();
w.write(s);
if(debug) log("Matched HTML comment: "+s);
}
- case 46: break;
+ case 47: break;
case 9:
{ String s = yytext();
if(s.startsWith("url")) throwError("Invalid contents of url()");
w.write(s);
if(debug) log("Matched function start: "+s);
}
- case 47: break;
- case 3:
- { String s = yytext();
- w.write(s);
- if(debug) log("Matched whitespace: "+s);
- }
case 48: break;
case 27:
{ String s = yytext();
@@ -1416,25 +1455,35 @@
DecodedStringThingy dst = new DecodedStringThingy(s);
s = dst.data;
if(debug) log("URL: "+s);
- s = processImportURL(s);
- dst.data = s;
- if(debug) log("Processed URL: "+s);
- if(dst.quote == ' ') dst.quote = '\"';
- if (!(s == null || s.equals(""))) {
- if(debug) log("URL now: "+s);
- s = "@import "+dst.toString();
- if(debug) log("Writing: "+s);
- w.write(s);
- } else
- if(debug) log("Dropped @import");
+ try {
+ s = processImportURL(s);
+ dst.data = s;
+ if(debug) log("Processed URL: "+s);
+ if(dst.quote == ' ') dst.quote = '\"';
+ if (!(s == null || s.equals(""))) {
+ if(debug) log("URL now: "+s);
+ s = "@import "+dst.toString();
+ if(debug) log("Writing: "+s);
+ w.write(s);
+ } else
+ if(debug) log("Dropped @import");
+ } catch (CommentException e) {
+ w.write("/* " + commentEncode(e.getMessage()) + " */");
+ }
}
case 49: break;
+ case 3:
+ { String s = yytext();
+ w.write(s);
+ if(debug) log("Matched whitespace: "+s);
+ }
+ case 50: break;
case 29:
{ String s = yytext();
w.write(s);
if(debug) log("Matched important: "+s);
}
- case 50: break;
+ case 51: break;
case 21:
{ String s = yytext();
StringBuffer sb = new StringBuffer(s.length());
@@ -1459,7 +1508,7 @@
w.write(sb.toString());
if(debug) log("Matched comment: "+s+" -> "+sb.toString());
}
- case 51: break;
+ case 52: break;
case 15:
{ if(!deleteErrors) {
throwError("Unknown @identifier "+yytext());
@@ -1469,35 +1518,6 @@
// Ignore
}
}
- case 52: break;
- case 23:
- { // This is horrible. However it seems that there is no other way
to do it with either jflex or CUP, as {URL} cannot be an unambiguous token :(
- String s = yytext();
- if(debug) log("Recognized URL: "+s);
-
- DecodedStringThingy dst = new DecodedStringThingy(s);
-
- if(!dst.url) {
- throw new IllegalStateException("parsing url().. isn't a
url()");
- }
- if(dst.suffix.length() > 0) {
- yypushback(dst.suffix.length());
- dst.suffix = "";
- }
-
- s = dst.data;
- if(debug) log("URL now: "+s);
- s = processURL(s);
- dst.data = s;
- if(s == null || s.equals("")) {
- if(debug) log("URL invalid");
- w.write("url()");
- } else {
- s = dst.toString();
- if(debug) log("Writing: "+s);
- w.write(s);
- }
- }
case 53: break;
case 11:
{ String s = yytext();
Modified: trunk/freenet/src/freenet/clients/http/filter/CSSTokenizerFilter.jflex
===================================================================
--- trunk/freenet/src/freenet/clients/http/filter/CSSTokenizerFilter.jflex
2006-10-27 19:47:14 UTC (rev 10716)
+++ trunk/freenet/src/freenet/clients/http/filter/CSSTokenizerFilter.jflex
2006-10-27 23:23:42 UTC (rev 10717)
@@ -41,11 +41,11 @@
throw new IllegalStateException("You MUST override
throwError!");
}
- String processImportURL(String s) {
+ String processImportURL(String s) throws CommentException {
throw new IllegalStateException("You MUST override
processImportURL!");
}
- String processURL(String s) {
+ String processURL(String s) throws CommentException {
throw new IllegalStateException("You MUST override
processURL!");
}
@@ -192,6 +192,18 @@
return sb.toString();
}
}
+
+ String commentEncode(String s) {
+ StringBuffer sb = new StringBuffer(s.length());
+ for(int i=0;i<s.length();i++) {
+ char c = sb.charAt(i);
+ if(c == '/')
+ sb.append("\\/");
+ else
+ sb.append(c);
+ }
+ return sb.toString();
+ }
%}
%class CSSTokenizerFilter
@@ -265,15 +277,19 @@
s = dst.data;
if(debug) log("URL now: "+s);
- s = processURL(s);
- dst.data = s;
- if(s == null || s.equals("")) {
- if(debug) log("URL invalid");
- w.write("url()");
- } else {
- s = dst.toString();
- if(debug) log("Writing: "+s);
- w.write(s);
+ try {
+ s = processURL(s);
+ dst.data = s;
+ if(s == null || s.equals("")) {
+ if(debug) log("URL invalid");
+ w.write("url()");
+ } else {
+ s = dst.toString();
+ if(debug) log("Writing: "+s);
+ w.write(s);
+ }
+ } catch (CommentException e) {
+ w.write("/* "+commentEncode(e.getMessage())+" */");
}
}
"@import"{W}{W}*({STRING}|{URL}|{REALURL})({W}*{W}{MEDIUMS})?";" {
@@ -284,17 +300,21 @@
DecodedStringThingy dst = new DecodedStringThingy(s);
s = dst.data;
if(debug) log("URL: "+s);
- s = processImportURL(s);
- dst.data = s;
- if(debug) log("Processed URL: "+s);
- if(dst.quote == ' ') dst.quote = '\"';
- if (!(s == null || s.equals(""))) {
- if(debug) log("URL now: "+s);
- s = "@import "+dst.toString();
- if(debug) log("Writing: "+s);
- w.write(s);
- } else
- if(debug) log("Dropped @import");
+ try {
+ s = processImportURL(s);
+ dst.data = s;
+ if(debug) log("Processed URL: "+s);
+ if(dst.quote == ' ') dst.quote = '\"';
+ if (!(s == null || s.equals(""))) {
+ if(debug) log("URL now: "+s);
+ s = "@import "+dst.toString();
+ if(debug) log("Writing: "+s);
+ w.write(s);
+ } else
+ if(debug) log("Dropped @import");
+ } catch (CommentException e) {
+ w.write("/* " + commentEncode(e.getMessage()) + " */");
+ }
}
{W}"{"{W} {
String s = yytext();
Added: trunk/freenet/src/freenet/clients/http/filter/CommentException.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/filter/CommentException.java
2006-10-27 19:47:14 UTC (rev 10716)
+++ trunk/freenet/src/freenet/clients/http/filter/CommentException.java
2006-10-27 23:23:42 UTC (rev 10717)
@@ -0,0 +1,19 @@
+/* This code is part of Freenet. It is distributed under the GNU General
+ * Public License, version 2 (or at your option any later version). See
+ * http://www.gnu.org/ for further details of the GPL. */
+package freenet.clients.http.filter;
+
+/**
+ * Thrown when a filter operation cannot complete and the filter has produced
some error output to help guide the user in
+ * resolving the situation.
+ *
+ * Note that the message is not yet encoded, and may contain data-dependant
information; that is the responsibility of the
+ * catcher.
+ */
+public class CommentException extends Exception {
+
+ public CommentException(String msg) {
+ super(msg);
+ }
+
+}
Modified: trunk/freenet/src/freenet/clients/http/filter/FilterCallback.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/filter/FilterCallback.java
2006-10-27 19:47:14 UTC (rev 10716)
+++ trunk/freenet/src/freenet/clients/http/filter/FilterCallback.java
2006-10-27 23:23:42 UTC (rev 10717)
@@ -1,5 +1,7 @@
package freenet.clients.http.filter;
+import java.net.MalformedURLException;
+
/**
* Callback to be provided to a content filter.
*/
@@ -9,8 +11,9 @@
* Process a URI.
* If it cannot be turned into something sufficiently safe, then return
null.
* @param overrideType Force the return type.
+ * @throws CommentException If the URI is nvalid or unacceptable in
some way.
*/
- public String processURI(String uri, String overrideType);
+ public String processURI(String uri, String overrideType) throws
CommentException;
/**
* Should we allow GET forms?
Modified:
trunk/freenet/src/freenet/clients/http/filter/GenericReadFilterCallback.java
===================================================================
---
trunk/freenet/src/freenet/clients/http/filter/GenericReadFilterCallback.java
2006-10-27 19:47:14 UTC (rev 10716)
+++
trunk/freenet/src/freenet/clients/http/filter/GenericReadFilterCallback.java
2006-10-27 23:23:42 UTC (rev 10717)
@@ -56,11 +56,11 @@
return false;
}
- public String processURI(String u, String overrideType) {
+ public String processURI(String u, String overrideType) throws
CommentException {
return processURI(u, overrideType, false);
}
- public String processURI(String u, String overrideType, boolean
noRelative) {
+ public String processURI(String u, String overrideType, boolean
noRelative) throws CommentException {
URI uri;
URI resolved;
boolean logMINOR = Logger.shouldLog(Logger.MINOR, this);
@@ -75,7 +75,7 @@
if(logMINOR) Logger.minor(this, "Resolved: "+resolved);
} catch (URISyntaxException e1) {
if(logMINOR) Logger.minor(this, "Failed to parse URI:
"+e1);
- return null;
+ throw new CommentException("Filter could not parse URI:
"+e1.getMessage());
}
String path = uri.getPath();
@@ -96,11 +96,13 @@
}
}
+ String reason = "";
+
// Try as an absolute URI
String rpath = uri.getPath();
if(rpath != null) {
- if(logMINOR) Logger.minor(this, "Resolved URI: "+rpath);
+ if(logMINOR) Logger.minor(this, "Resolved URI (rpath
absolute): "+rpath);
// Valid FreenetURI?
try {
@@ -111,14 +113,16 @@
return processURI(furi, uri, overrideType,
noRelative);
} catch (MalformedURLException e) {
// Not a FreenetURI
+ if(logMINOR) Logger.minor(this, "Malformed URL
(a): "+e, e);
+ reason = "Malformed URL (absolute):
"+e.getMessage();
}
}
// Probably a relative URI.
rpath = resolved.getPath();
- if(rpath == null) return null;
- if(logMINOR) Logger.minor(this, "Resolved URI: "+rpath);
+ if(rpath == null) throw new CommentException("No URI");
+ if(logMINOR) Logger.minor(this, "Resolved URI (rpath relative):
"+rpath);
// Valid FreenetURI?
try {
@@ -128,13 +132,21 @@
if(logMINOR) Logger.minor(this, "Parsed: "+furi);
return processURI(furi, uri, overrideType, noRelative);
} catch (MalformedURLException e) {
+ if(logMINOR) Logger.minor(this, "Malformed URL (b):
"+e, e);
+ if(reason.length() > 0)
+ reason += " , ";
+ reason += "Malformed URL (relative): "+e.getMessage();
// Not a FreenetURI
}
if(GenericReadFilterCallback.allowedProtocols.contains(uri.getScheme()))
return
"/?"+GenericReadFilterCallback.magicHTTPEscapeString+"="+uri;
- else
- return null;
+ else {
+ if(uri.getScheme() == null) {
+ throw new CommentException("Invalid freenet
URL: "+reason);
+ }
+ throw new CommentException("Not an escaped protocol:
"+uri.getScheme());
+ }
}
private String finishProcess(HTTPRequest req, String overrideType,
String path, URI u, boolean noRelative) {
@@ -163,7 +175,7 @@
}catch (UnsupportedEncodingException e1){
}
}
- return null;
+ return p;
}
}
@@ -176,7 +188,13 @@
}
public String onBaseHref(String baseHref) {
- String ret = processURI(baseHref, null, true);
+ String ret;
+ try {
+ ret = processURI(baseHref, null, true);
+ } catch (CommentException e1) {
+ Logger.error(this, "Failed to parse base href:
"+baseHref+" -> "+e1.getMessage());
+ ret = null;
+ }
if(ret == null) {
Logger.error(this, "onBaseHref() failed: cannot
sanitize "+baseHref);
return null;
Modified: trunk/freenet/src/freenet/clients/http/filter/HTMLFilter.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/filter/HTMLFilter.java
2006-10-27 19:47:14 UTC (rev 10716)
+++ trunk/freenet/src/freenet/clients/http/filter/HTMLFilter.java
2006-10-27 23:23:42 UTC (rev 10717)
@@ -1160,7 +1160,7 @@
// Java's URL handling doesn't
seem suitable
String uri = (String) o;
uri = HTMLDecoder.decode(uri);
- uri = sanitizeURI(uri, null,
null, pc.cb);
+ uri = htmlSanitizeURI(uri,
null, null, pc.cb, pc);
if (uri != null) {
uri =
HTMLEncoder.encode(uri);
hn.put(x, uri);
@@ -1529,7 +1529,7 @@
// type+"
and charset "+charset,
//
Logger.DEBUG);
href = HTMLDecoder.decode(href);
- href = sanitizeURI(href, type, charset, pc.cb);
+ href = htmlSanitizeURI(href, type, charset,
pc.cb, pc);
if (href != null) {
href = HTMLEncoder.encode(href);
hn.put("href", href);
@@ -1864,7 +1864,7 @@
return null;
}
- static String sanitizeURI(String uri, FilterCallback cb) {
+ static String sanitizeURI(String uri, FilterCallback cb) throws
CommentException {
return sanitizeURI(uri, null, null, cb);
}
@@ -1929,11 +1929,25 @@
}
}
+ static String htmlSanitizeURI(
+ String suri,
+ String overrideType,
+ String overrideCharset,
+ FilterCallback cb,
+ HTMLParseContext pc) {
+ try {
+ return sanitizeURI(suri, overrideType, overrideCharset,
cb);
+ } catch (CommentException e) {
+ pc.writeAfterTag.append("<!--
"+HTMLEncoder.encode(e.toString())+" -->");
+ return null;
+ }
+ }
+
static String sanitizeURI(
String suri,
String overrideType,
String overrideCharset,
- FilterCallback cb) {
+ FilterCallback cb) throws CommentException {
if(logMINOR)
Logger.minor(HTMLFilter.class, "Sanitizing URI:
"+suri+" ( override type "+overrideType +" override charset "+overrideCharset+"
)");
if((overrideCharset != null) && (overrideCharset.length() > 0))