My fork of airsonic with experimental fixes and improvements. See branch "custom"
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

/*
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;
}
}