You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
190 lines
5.7 KiB
190 lines
5.7 KiB
/*
|
|
This file is part of Airsonic.
|
|
|
|
Airsonic is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Airsonic is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Airsonic. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Copyright 2016 (C) Airsonic Authors
|
|
Based upon Subsonic, Copyright 2009 (C) Sindre Mehus
|
|
*/
|
|
package org.airsonic.player.taglib;
|
|
|
|
import org.airsonic.player.filter.ParameterDecodingFilter;
|
|
import org.airsonic.player.util.StringUtil;
|
|
import org.apache.commons.lang.CharUtils;
|
|
import org.apache.commons.lang3.tuple.Pair;
|
|
import org.apache.taglibs.standard.tag.common.core.UrlSupport;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import javax.servlet.jsp.JspException;
|
|
import javax.servlet.jsp.JspTagException;
|
|
import javax.servlet.jsp.PageContext;
|
|
import javax.servlet.jsp.tagext.BodyTagSupport;
|
|
|
|
import java.io.IOException;
|
|
import java.io.UnsupportedEncodingException;
|
|
import java.net.URLEncoder;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
/**
|
|
* Creates a URL with optional query parameters. Similar to 'c:url', but
|
|
* you may specify which character encoding to use for the URL query
|
|
* parameters. If no encoding is specified, the following steps are performed:
|
|
* <ul>
|
|
* <li>Parameter values are encoded as the hexadecimal representation of the UTF-8 bytes of the original string.</li>
|
|
* <li>Parameter names are prepended with the suffix "Utf8Hex"</li>
|
|
* <li>Note: Nothing is done with the parameter name or value if the value only contains ASCII alphanumeric characters.</li>
|
|
* </ul>
|
|
* <p/>
|
|
* (The problem with c:url is that is uses the same encoding as the http response,
|
|
* but most(?) servlet container assumes that ISO-8859-1 is used.)
|
|
*
|
|
* @author Sindre Mehus
|
|
*/
|
|
public class UrlTag extends BodyTagSupport {
|
|
|
|
private String DEFAULT_ENCODING = "Utf8Hex";
|
|
private static final Logger LOG = LoggerFactory.getLogger(UrlTag.class);
|
|
|
|
private String var;
|
|
private String value;
|
|
private String encoding = DEFAULT_ENCODING;
|
|
private List<Pair<String, String>> parameters = new ArrayList<>();
|
|
|
|
public int doStartTag() {
|
|
parameters.clear();
|
|
return EVAL_BODY_BUFFERED;
|
|
}
|
|
|
|
public int doEndTag() throws JspException {
|
|
|
|
// Rewrite and encode the url.
|
|
String result = formatUrl();
|
|
|
|
// Store or print the output
|
|
if (var != null)
|
|
pageContext.setAttribute(var, result, PageContext.PAGE_SCOPE);
|
|
else {
|
|
try {
|
|
pageContext.getOut().print(result);
|
|
} catch (IOException x) {
|
|
throw new JspTagException(x);
|
|
}
|
|
}
|
|
return EVAL_PAGE;
|
|
}
|
|
|
|
private String formatUrl() throws JspException {
|
|
String baseUrl = UrlSupport.resolveUrl(value, null, pageContext);
|
|
|
|
StringBuilder result = new StringBuilder();
|
|
result.append(baseUrl);
|
|
if (!parameters.isEmpty()) {
|
|
result.append('?');
|
|
|
|
for (int i = 0; i < parameters.size(); i++) {
|
|
Pair<String, String> parameter = parameters.get(i);
|
|
try {
|
|
result.append(parameter.getLeft());
|
|
if (isUtf8Hex() && !isAsciiAlphaNumeric(parameter.getRight())) {
|
|
result.append(ParameterDecodingFilter.PARAM_SUFFIX);
|
|
}
|
|
|
|
result.append('=');
|
|
if (parameter.getRight() != null) {
|
|
result.append(encode(parameter.getRight()));
|
|
}
|
|
if (i < parameters.size() - 1) {
|
|
result.append("&");
|
|
}
|
|
|
|
} catch (UnsupportedEncodingException x) {
|
|
throw new JspTagException(x);
|
|
}
|
|
}
|
|
}
|
|
return result.toString();
|
|
}
|
|
|
|
private String encode(String s) throws UnsupportedEncodingException {
|
|
if (isUtf8Hex()) {
|
|
if (isAsciiAlphaNumeric(s)) {
|
|
return s;
|
|
}
|
|
|
|
try {
|
|
return StringUtil.utf8HexEncode(s);
|
|
} catch (Exception x) {
|
|
LOG.error("Failed to utf8hex-encode the string '" + s + "'.", x);
|
|
return s;
|
|
}
|
|
}
|
|
|
|
return URLEncoder.encode(s, encoding);
|
|
}
|
|
|
|
private boolean isUtf8Hex() {
|
|
return DEFAULT_ENCODING.equals(encoding);
|
|
}
|
|
|
|
static private boolean isAsciiAlphaNumeric(String s) {
|
|
if (s == null) {
|
|
return true;
|
|
}
|
|
|
|
for (int i = 0; i < s.length(); i++) {
|
|
if (!CharUtils.isAsciiAlphanumeric(s.charAt(i))) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public void release() {
|
|
var = null;
|
|
value = null;
|
|
encoding = DEFAULT_ENCODING;
|
|
parameters.clear();
|
|
super.release();
|
|
}
|
|
|
|
public void addParameter(String name, String value) {
|
|
parameters.add(Pair.of(name, value));
|
|
}
|
|
|
|
public String getVar() {
|
|
return var;
|
|
}
|
|
|
|
public void setVar(String var) {
|
|
this.var = var;
|
|
}
|
|
|
|
public String getValue() {
|
|
return value;
|
|
}
|
|
|
|
public void setValue(String value) {
|
|
this.value = value;
|
|
}
|
|
|
|
public String getEncoding() {
|
|
return encoding;
|
|
}
|
|
|
|
public void setEncoding(String encoding) {
|
|
this.encoding = encoding;
|
|
}
|
|
}
|
|
|