org.simpleframework.http.message.BoundaryConsumer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of simple Show documentation
Show all versions of simple Show documentation
Simple is a high performance asynchronous HTTP server for Java
The newest version!
/*
* BoundaryConsumer.java February 2007
*
* Copyright (C) 2007, Niall Gallagher
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.simpleframework.http.message;
import java.io.IOException;
import org.simpleframework.util.buffer.Allocator;
import org.simpleframework.util.buffer.Buffer;
/**
* The BoundaryConsumer
is used to consume a boundary
* for a multipart message. This ensures that the boundary complies
* with the multipart specification in that it ends with a carriage
* return and line feed. This consumer implementation can be used
* multiple times as its internal buffer can be cleared and reset.
*
* @author Niall Gallagher
*/
class BoundaryConsumer extends ArrayConsumer {
/**
* This is the terminal token for a multipart boundary entity.
*/
private static final byte[] LAST = { '-', '-', '\r', '\n', };
/**
* This is the terminal token for a multipart boundary line.
*/
private static final byte[] LINE = { '\r', '\n' };
/**
* This represents the start of the boundary line for the part.
*/
private static final byte[] TOKEN = { '-', '-' };
/**
* This is used to allocate a buffer for for the boundary.
*/
private Allocator allocator;
/**
* This is used to consume the contents of the consumed buffer.
*/
private Buffer buffer;
/**
* This is the actual boundary value that is to be consumed.
*/
private byte[] boundary;
/**
* This counts the number of characters read from the start.
*/
private int seek;
/**
* Constructor for the BoundaryConsumer
object. This
* is used to create a boundary consumer for validating boundaries
* and consuming them from a provided source. This is used to help
* in reading multipart messages by removing boundaries from the
* stream.
*
* @param boundary this is the boundary value to be consumed
*/
public BoundaryConsumer(Allocator allocator, byte[] boundary) {
this.chunk = boundary.length + LAST.length + TOKEN.length;
this.allocator = allocator;
this.boundary = boundary;
}
/**
* This does not perform any processing after the boundary has
* been consumed. Because the boundary consumer is used only as a
* means to remove the boundary from the underlying stream there
* is no need to perform any processing of the value consumed.
*/
@Override
protected void process() throws IOException {
if(count < boundary.length + 4) {
throw new IOException("Invalid boundary processed");
}
}
/**
* This method is used to scan for the terminal token. It searches
* for the token and returns the number of bytes in the buffer
* after the terminal token. Returning the excess bytes allows the
* consumer to reset the bytes within the consumer object.
*
* @return this returns the number of excess bytes consumed
*/
@Override
protected int scan() throws IOException {
int size = boundary.length;
if(count >= 2 && seek < 2) {
if(scan(TOKEN)) {
append(TOKEN);
}
}
if(count >= 2 + size && seek < 2 + size) {
if(scan(boundary)) {
append(boundary);
}
}
if(count >= 4 + size && seek < 4 + size) {
if(array[size + 2] == TOKEN[0]) {
if(scan(TOKEN)) {
append(TOKEN);
}
} else if(array[size + 2] == LINE[0]) {
if(scan(LINE)) {
append(LINE);
}
done = true;
return count - seek;
}
}
if(count >= 6 + size && seek < 6 + size) {
if(scan(LINE)) {
append(LINE);
}
done = true;
return count - seek;
}
return 0;
}
/**
* This is used to append a token to the underlying buffer. Adding
* various tokens ensures that the whole message is reconstructed
* and can be forwarded to any connected service if used as a proxy.
*
* @param token this is the token that is to be appended
*/
private void append(byte[] token) throws IOException {
if(buffer == null) {
buffer = allocator.allocate(chunk);
}
buffer.append(token);
}
/**
* This is used to scan the specified token from the consumed bytes.
* If the data scanned does not match the token provided then this
* will throw an exception to signify a bad boundary. This will
* return true only when the whole boundary has been consumed.
*
* @param data this is the token to scan from the consumed bytes
*
* @return this returns true of the token has been read
*/
private boolean scan(byte[] data) throws IOException {
int size = data.length;
int pos = 0;
while(seek < count) {
if(array[seek++] != data[pos++]) {
throw new IOException("Invalid boundary");
}
if(pos == data.length) {
return true;
}
}
return pos == size;
}
/**
* This is used to determine whether the boundary has been read
* from the underlying stream. This is true only when the very
* last boundary has been read. This will be the boundary value
* that ends with the two -
characters.
*
* @return this returns true with the terminal boundary is read
*/
public boolean isEnd() {
return seek == chunk;
}
/**
* This is used to clear the state of the of boundary consumer
* such that it can be reused. This is required as the multipart
* body may contain many parts, all delimited with the same
* boundary. Clearing allows the next boundary to be consumed.
*/
public void clear() {
done = false;
count = seek = 0;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy