![JAR search and dependency download from the Maven repository](/logo.png)
org.owasp.encoder.EncodedWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of encoder Show documentation
Show all versions of encoder Show documentation
The OWASP Encoders package is a collection of high-performance low-overhead
contextual encoders, that when utilized correctly, is an effective tool in
preventing Web Application security vulnerabilities such as Cross-Site
Scripting.
// Copyright (c) 2012 Jeff Ichnowski
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above
// copyright notice, this list of conditions and the following
// disclaimer.
//
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials
// provided with the distribution.
//
// * Neither the name of the OWASP nor the names of its
// contributors may be used to endorse or promote products
// derived from this software without specific prior written
// permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.
package org.owasp.encoder;
import java.io.IOException;
import java.io.Writer;
import java.nio.CharBuffer;
import java.nio.charset.CoderResult;
/**
* EncodedWriter -- A writer the encodes all input for a specific context and writes the encoded output to another writer.
*
* @author Jeff Ichnowski
*/
public class EncodedWriter extends Writer {
/**
* Buffer size to allocate.
*
*/
static final int BUFFER_SIZE = 1024;
/**
* Buffer to use for handling characters remaining in the input buffer after an encode. The value is set high enough to handle
* the lookaheads of all the encoders in the package.
*/
static final int LEFT_OVER_BUFFER = 16;
/**
* The wrapped writer.
*/
private Writer _out;
/**
* The encoder used to encode input to the output writer.
*/
private Encoder _encoder;
/**
* Where encoded output is buffered before sending on to the output writer.
*/
private CharBuffer _buffer = CharBuffer.allocate(BUFFER_SIZE);
/**
* Some encoders require more input or an explicit end-of-input flag before they will process the remaining characters of an
* input buffer. Because the writer API cannot pass this information on to the caller (e.g. by returning how many bytes were
* actually written), this writer implementation must buffer up the remaining characters between calls. The
* _hasLeftOver
boolean is a flag used to indicate that there are left over characters in the buffer.
*/
private boolean _hasLeftOver;
/**
* See comment on _hasLeftOver. This buffer is created on-demand once. Whether it has anything to flush is determined by the
* _hasLeftOver flag.
*/
private CharBuffer _leftOverBuffer;
/**
* Creates an EncodedWriter that uses the specified encoder to encode all input before sending it to the wrapped writer.
*
* @param out the target for all writes
* @param encoder the encoder to use
*/
public EncodedWriter(Writer out, Encoder encoder) {
super(out);
// Reduntant null check, super(out) checks for null and throws NPE.
// if (out == null) {
// throw new NullPointerException("writer must not be null");
// }
if (encoder == null) {
throw new NullPointerException("encoder must not be null");
}
_out = out;
_encoder = encoder;
}
/**
* Creates an EncodedWriter that uses the specified encoder to encode all input before sending it to the wrapped writer. This
* method is equivalent to calling:
*
* new EncodedWriter(out, Encoders.forName(contextName));
*
*
* @param out the target for all writes
* @param contextName the encoding context name.
* @throws UnsupportedContextException if the contextName is unrecognized or not supported.
*/
public EncodedWriter(Writer out, String contextName) throws UnsupportedContextException {
this(out, Encoders.forName(contextName));
}
@Override
public void write(char[] cbuf, int off, int len) throws IOException {
synchronized (lock) {
CharBuffer input = CharBuffer.wrap(cbuf);
input.limit(off + len).position(off);
flushLeftOver(input);
for (;;) {
CoderResult cr = _encoder.encode(input, _buffer, false);
if (cr.isUnderflow()) {
if (input.hasRemaining()) {
if (_leftOverBuffer == null) {
_leftOverBuffer = CharBuffer.allocate(LEFT_OVER_BUFFER);
}
_leftOverBuffer.put(input);
_hasLeftOver = true;
}
return;
}
if (cr.isOverflow()) {
flushBufferToWriter();
}
}
}
}
/**
* Flushes the contents of the buffer to the writer and resets the buffer to make room for more input.
*
* @throws IOException thrown by the wrapped output.
*/
private void flushBufferToWriter() throws IOException {
_out.write(_buffer.array(), 0, _buffer.position());
_buffer.clear();
}
/**
* Flushes the left-over buffer. Characters from the input buffer are used to add more data to the _leftOverBuffer in order to
* make the flush happen.
*
* @param input the next input to encode, or null if at end of file.
* @throws IOException from the underlying writer.
*/
private void flushLeftOver(CharBuffer input) throws IOException {
if (!_hasLeftOver) {
return;
}
for (;;) {
if (input != null && input.hasRemaining()) {
_leftOverBuffer.put(input.get());
}
_leftOverBuffer.flip();
CoderResult cr = _encoder.encode(_leftOverBuffer, _buffer, input == null);
if (cr.isUnderflow()) {
if (_leftOverBuffer.hasRemaining()) {
_leftOverBuffer.compact();
} else {
break;
}
}
if (cr.isOverflow()) {
flushBufferToWriter();
}
}
_hasLeftOver = false;
_leftOverBuffer.clear();
}
@Override
public void flush() throws IOException {
synchronized (lock) {
flushBufferToWriter();
_out.flush();
}
}
@Override
public void close() throws IOException {
synchronized (lock) {
flushLeftOver(null);
flushBufferToWriter();
_out.close();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy