Polish CssLinkResourceTransformer
This commit is contained in:
@@ -22,9 +22,10 @@ import java.nio.charset.Charset;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
import java.util.TreeSet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
@@ -82,25 +83,23 @@ public class CssLinkResourceTransformer extends ResourceTransformerSupport {
|
|||||||
byte[] bytes = FileCopyUtils.copyToByteArray(resource.getInputStream());
|
byte[] bytes = FileCopyUtils.copyToByteArray(resource.getInputStream());
|
||||||
String content = new String(bytes, DEFAULT_CHARSET);
|
String content = new String(bytes, DEFAULT_CHARSET);
|
||||||
|
|
||||||
List<Segment> linkSegments = new ArrayList<>(8);
|
SortedSet<ContentChunkInfo> links = new TreeSet<>();
|
||||||
for (LinkParser parser : this.linkParsers) {
|
for (LinkParser parser : this.linkParsers) {
|
||||||
linkSegments.addAll(parser.parseLink(content));
|
parser.parse(content, links);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (linkSegments.isEmpty()) {
|
if (links.isEmpty()) {
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("No links found.");
|
logger.trace("No links found.");
|
||||||
}
|
}
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.sort(linkSegments);
|
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
StringWriter writer = new StringWriter();
|
StringWriter writer = new StringWriter();
|
||||||
for (Segment linkSegment : linkSegments) {
|
for (ContentChunkInfo linkContentChunkInfo : links) {
|
||||||
writer.write(content.substring(index, linkSegment.getStart()));
|
writer.write(content.substring(index, linkContentChunkInfo.getStart()));
|
||||||
String link = content.substring(linkSegment.getStart(), linkSegment.getEnd());
|
String link = content.substring(linkContentChunkInfo.getStart(), linkContentChunkInfo.getEnd());
|
||||||
String newLink = null;
|
String newLink = null;
|
||||||
if (!hasScheme(link)) {
|
if (!hasScheme(link)) {
|
||||||
String absolutePath = toAbsolutePath(link, request);
|
String absolutePath = toAbsolutePath(link, request);
|
||||||
@@ -115,7 +114,7 @@ public class CssLinkResourceTransformer extends ResourceTransformerSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
writer.write(newLink != null ? newLink : link);
|
writer.write(newLink != null ? newLink : link);
|
||||||
index = linkSegment.getEnd();
|
index = linkContentChunkInfo.getEnd();
|
||||||
}
|
}
|
||||||
writer.write(content.substring(index));
|
writer.write(content.substring(index));
|
||||||
|
|
||||||
@@ -128,60 +127,51 @@ public class CssLinkResourceTransformer extends ResourceTransformerSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract content chunks that represent links.
|
||||||
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
protected interface LinkParser {
|
protected interface LinkParser {
|
||||||
|
|
||||||
Set<Segment> parseLink(String content);
|
void parse(String content, SortedSet<ContentChunkInfo> result);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected static abstract class AbstractLinkParser implements LinkParser {
|
protected static abstract class AbstractLinkParser implements LinkParser {
|
||||||
|
|
||||||
/**
|
/** Return the keyword to use to search for links, e.g. "@import", "url(" */
|
||||||
* Return the keyword to use to search for links.
|
|
||||||
*/
|
|
||||||
protected abstract String getKeyword();
|
protected abstract String getKeyword();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<Segment> parseLink(String content) {
|
public void parse(String content, SortedSet<ContentChunkInfo> result) {
|
||||||
Set<Segment> linksToAdd = new HashSet<>(8);
|
int position = 0;
|
||||||
int index = 0;
|
while (true) {
|
||||||
do {
|
position = content.indexOf(getKeyword(), position);
|
||||||
index = content.indexOf(getKeyword(), index);
|
if (position == -1) {
|
||||||
if (index == -1) {
|
return;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
index = skipWhitespace(content, index + getKeyword().length());
|
position += getKeyword().length();
|
||||||
if (content.charAt(index) == '\'') {
|
while (Character.isWhitespace(content.charAt(position))) {
|
||||||
index = addLink(index, "'", content, linksToAdd);
|
position++;
|
||||||
}
|
}
|
||||||
else if (content.charAt(index) == '"') {
|
if (content.charAt(position) == '\'') {
|
||||||
index = addLink(index, "\"", content, linksToAdd);
|
position = extractLink(position, "'", content, result);
|
||||||
|
}
|
||||||
|
else if (content.charAt(position) == '"') {
|
||||||
|
position = extractLink(position, "\"", content, result);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
index = extractLink(index, content, linksToAdd);
|
position = extractLink(position, content, result);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (true);
|
|
||||||
return linksToAdd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int skipWhitespace(String content, int index) {
|
protected int extractLink(int index, String endKey, String content, SortedSet<ContentChunkInfo> linksToAdd) {
|
||||||
while (true) {
|
|
||||||
if (Character.isWhitespace(content.charAt(index))) {
|
|
||||||
index++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int addLink(int index, String endKey, String content, Set<Segment> linksToAdd) {
|
|
||||||
int start = index + 1;
|
int start = index + 1;
|
||||||
int end = content.indexOf(endKey, start);
|
int end = content.indexOf(endKey, start);
|
||||||
linksToAdd.add(new Segment(start, end));
|
linksToAdd.add(new ContentChunkInfo(start, end));
|
||||||
return end + endKey.length();
|
return end + endKey.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +179,8 @@ public class CssLinkResourceTransformer extends ResourceTransformerSupport {
|
|||||||
* Invoked after a keyword match, after whitespaces removed, and when
|
* Invoked after a keyword match, after whitespaces removed, and when
|
||||||
* the next char is neither a single nor double quote.
|
* the next char is neither a single nor double quote.
|
||||||
*/
|
*/
|
||||||
protected abstract int extractLink(int index, String content, Set<Segment> linksToAdd);
|
protected abstract int extractLink(int index, String content,
|
||||||
|
SortedSet<ContentChunkInfo> linksToAdd);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +193,7 @@ public class CssLinkResourceTransformer extends ResourceTransformerSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int extractLink(int index, String content, Set<Segment> linksToAdd) {
|
protected int extractLink(int index, String content, SortedSet<ContentChunkInfo> linksToAdd) {
|
||||||
if (content.substring(index, index + 4).equals("url(")) {
|
if (content.substring(index, index + 4).equals("url(")) {
|
||||||
// Ignore, UrlLinkParser will take care
|
// Ignore, UrlLinkParser will take care
|
||||||
}
|
}
|
||||||
@@ -222,20 +213,20 @@ public class CssLinkResourceTransformer extends ResourceTransformerSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int extractLink(int index, String content, Set<Segment> linksToAdd) {
|
protected int extractLink(int index, String content, SortedSet<ContentChunkInfo> linksToAdd) {
|
||||||
// A url() function without unquoted
|
// A url() function without unquoted
|
||||||
return addLink(index - 1, ")", content, linksToAdd);
|
return extractLink(index - 1, ")", content, linksToAdd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class Segment implements Comparable<Segment> {
|
private static class ContentChunkInfo implements Comparable<ContentChunkInfo> {
|
||||||
|
|
||||||
private final int start;
|
private final int start;
|
||||||
|
|
||||||
private final int end;
|
private final int end;
|
||||||
|
|
||||||
public Segment(int start, int end) {
|
ContentChunkInfo(int start, int end) {
|
||||||
this.start = start;
|
this.start = start;
|
||||||
this.end = end;
|
this.end = end;
|
||||||
}
|
}
|
||||||
@@ -249,7 +240,7 @@ public class CssLinkResourceTransformer extends ResourceTransformerSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(Segment other) {
|
public int compareTo(ContentChunkInfo other) {
|
||||||
return (this.start < other.start ? -1 : (this.start == other.start ? 0 : 1));
|
return (this.start < other.start ? -1 : (this.start == other.start ? 0 : 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,8 +249,8 @@ public class CssLinkResourceTransformer extends ResourceTransformerSupport {
|
|||||||
if (this == obj) {
|
if (this == obj) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (obj instanceof Segment) {
|
if (obj instanceof ContentChunkInfo) {
|
||||||
Segment other = (Segment) obj;
|
ContentChunkInfo other = (ContentChunkInfo) obj;
|
||||||
return (this.start == other.start && this.end == other.end);
|
return (this.start == other.start && this.end == other.end);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user