All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.aoindustries.aoserv.client.util.ApacheEscape Maven / Gradle / Ivy

There is a newer version: 1.92.0
Show newest version
/*
 * aoserv-client - Java client for the AOServ Platform.
 * Copyright (C) 2018  AO Industries, Inc.
 *     [email protected]
 *     7262 Bull Pen Cir
 *     Mobile, AL 36695
 *
 * This file is part of aoserv-client.
 *
 * aoserv-client is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * aoserv-client 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with aoserv-client.  If not, see .
 */
package com.aoindustries.aoserv.client.util;

/**
 * Escapes arbitrary values for use in Apache directives.
 *
 * @author  AO Industries, Inc.
 */
public class ApacheEscape {

	public static final String DEFAULT_DOLLAR_VARIABLE = "$";

	/**
	 * Escapes arbitrary text to be used in an Apache directive.
	 * Adds double quotes as-needed.  Please note that '$' is also
	 * escaped when found in form ${variable}, so this might not be
	 * appropriate for ${variable} substitutions.
	 * 

* Please note, the dollar escaping relies on Apache being configured with * Define <dollarVariable> $, as it is performed with a ${dollarVariable} hack. *

* * @see #escape(java.lang.String, java.lang.String, boolean) */ public static String escape(String dollarVariable, String value) { return escape(dollarVariable, value, false); } /** * Escapes arbitrary text to be used in an Apache directive. * Adds double quotes as-needed. Optionally allowing '$' unescaped. *

* Please note, the dollar escaping relies on Apache being configured with * Define $ $, as it is performed with a ${$} hack. * This is set in the aoserv-httpd-config package, in core.inc. *

*

* I am unable to find clear documentation on the full set of rules for escaping Apache directives. * I have experimented with various values and techniques to achieve this implementation. * It seems there is no useful way to encode completely arbitrary values into directives. * Thus, this set of rules may not be optimal (may perform more escaping than necessary) or, * even worse, could be incomplete. *

* * @return the escaped string or the original string when no escaping required * * @see #escape(java.lang.String, java.lang.String) */ public static String escape(String dollarVariable, String value, boolean allowVariables) { int len = value.length(); // Empty string as "" if(len == 0) return "\"\""; StringBuilder sb = null; // Created when first needed boolean quoted = false; for(int i = 0; i < len; i++) { char ch = value.charAt(i); // Characters not ever allowed if(ch == 0) throw new IllegalArgumentException("Null character not allowed in Apache directives"); if(ch == '\b') throw new IllegalArgumentException("Backspace character not allowed in Apache directives"); if(ch == '\f') throw new IllegalArgumentException("Form feed character not allowed in Apache directives"); if(ch == '\n') throw new IllegalArgumentException("Newline character not allowed in Apache directives"); if(ch == '\r') throw new IllegalArgumentException("Carriage return character not allowed in Apache directives"); // Characters allowed, but only inside double-quoted strings if( ch == ' ' || ch == '\t' || ch == '\'' || ch == '<' || ch == '>' ) { if(sb == null) sb = new StringBuilder(len * 2).append(value, 0, i); if(!quoted) { sb.insert(0, '"'); quoted = true; } sb.append(ch); } // Do not allow control characters else if(ch < ' ') { throw new IllegalArgumentException("Control character not allowed in Apache directives: " + (int)ch); } // Escape "$" when dollar escaping enabled and followed by '{' else if( ch == '$' && !allowVariables && i < (len - 1) && value.charAt(i + 1) == '{' ) { // Find name of variable int endPos = value.indexOf('}', i + 2); if( // No closing } found, no escape needed endPos == -1 // Empty variable name, no escape needed || endPos == (i + 2) ) { if(sb != null) sb.append('$'); } else { int colonPos = value.indexOf(':', i + 2); if(colonPos != -1 && colonPos < endPos) { // Colon in name, don't escape variable if(sb != null) sb.append('$'); } else { if(dollarVariable == null) { throw new IllegalArgumentException("Unable to escape \"${\", no dollarVariable: " + value); } if(sb == null) sb = new StringBuilder(len * 2).append(value, 0, i); sb.append("${").append(dollarVariable).append('}'); // Relies on "Define $" set in configuration files. } } } // Backslashes are only escaped when followed by another backslash, a double quote, or // are at the end of the value. Furthermore, when at the end, the value is double-quoted // to avoid possible line continuation else if(ch == '\\') { if(i == (len - 1)) { // Is the last character, double-quote and escape if(sb == null) sb = new StringBuilder(len * 2).append(value, 0, i); if(!quoted) { sb.insert(0, '"'); quoted = true; } sb.append("\\\\"); } else { char next = value.charAt(i + 1); if(next == '\\' || next == '"') { // Followed by \ or ", escape only if(sb == null) sb = new StringBuilder(len * 2).append(value, 0, i); sb.append("\\\\"); } else { // No escape required if(sb != null) sb.append(ch); } } } // Characters that are backslash-escaped, enables double-quoting else if(ch == '"') { if(sb == null) sb = new StringBuilder(len * 2).append(value, 0, i); if(!quoted) { sb.insert(0, '"'); quoted = true; } sb.append('\\').append(ch); } // All other characters unaltered else { if(sb != null) sb.append(ch); } } if(sb == null) { assert !quoted; return value; } else { if(quoted) sb.append('"'); return sb.toString(); } } private ApacheEscape() {} }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy