/*
* This file is part of the Wayback archival access software
* (http://archive-access.sourceforge.net/projects/wayback/).
*
* Licensed to the Internet Archive (IA) by one or more individual
* contributors.
*
* The IA licenses this file to You 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.archive.wayback.util.http;
import java.io.IOException;
import java.io.InputStream;
import org.archive.wayback.util.http.BadRequestException;
import org.archive.wayback.util.ByteOp;
/**
*
*
* @author brad
* @version $Date$, $Revision$
*/
public class HttpMessage {
private static int MAX_MESSAGE_SIZE = 4096;
public static byte SPACE = 32;
public static byte CR = 13;
public static byte LF = 10;
public static byte[] readLine(InputStream in, int max)
throws IOException, BadRequestException {
byte[] buffer = new byte[max];
int pos = 0;
boolean found = false;
while(pos < max) {
int next = in.read();
buffer[pos] = (byte) next;
if(next == LF) {
if(pos == 0) {
throw new BadRequestException(
"Message cannot start with LF");
}
if(buffer[pos - 1] == CR) {
found = true;
break;
}
}
pos++;
}
if(!found) {
throw new BadRequestException("Message too long without CRLF");
}
return ByteOp.copy(buffer,0,pos+1);
}
private static int[] findSpaces(byte[] buffer, int max)
throws BadRequestException {
int spaces[] = new int[max];
int found = 0;
int offset = 0;
int end = buffer.length - 2;
while(offset < end) {
if(buffer[offset] == SPACE) {
spaces[found] = offset;
found++;
}
if(found == max - 1) {
break;
}
offset++;
}
if(found != max - 1) {
throw new BadRequestException("Not enough fields(" + found +") " +
"want("+max+") in (" + new String(buffer)+ ")");
}
return spaces;
}
public static byte[][] loadFields(byte[] buffer, int max)
throws BadRequestException {
byte[][] fields = new byte[max][];
int[] offsets = findSpaces(buffer, max);
int start = 0;
for(int i = 0; i < max - 1; i++) {
fields[i] = ByteOp.copy(buffer, start, offsets[i] - start);
start = offsets[i] + 1;
}
fields[max-1] = ByteOp.copy(buffer, start, (buffer.length - 2) - start);
return fields;
}
public byte[] concatBytes(byte[][] fields, boolean addCrLf) {
int length = 1;
for(byte[] field : fields) {
length += field.length + 1;
}
if(!addCrLf) {
length -= 2;
}
byte[] buffer = new byte[length];
int index = 0;
for(byte[] field : fields) {
System.arraycopy(field, 0,
buffer, index, field.length);
index += field.length;
if(index < length) {
buffer[index] = SPACE;
}
index++;
}
if(addCrLf) {
buffer[length - 2] = CR;
buffer[length - 1] = LF;
}
return buffer;
}
public static HttpResponseMessage loadResponse(byte[] buffer)
throws BadRequestException {
byte[][] fields = loadFields(buffer,3);
return new HttpResponseMessage(fields[0],fields[1],fields[2]);
}
public static HttpResponseMessage loadResponse(InputStream in)
throws BadRequestException, IOException {
return loadResponse(readLine(in, MAX_MESSAGE_SIZE));
}
public static HttpRequestMessage loadRequest(byte[] buffer)
throws BadRequestException {
byte[][] fields = loadFields(buffer,3);
return new HttpRequestMessage(fields[0],fields[1],fields[2]);
}
public static HttpRequestMessage loadRequest(InputStream in)
throws BadRequestException, IOException {
return loadRequest(readLine(in, MAX_MESSAGE_SIZE));
}
}