openwfe.org.net.NetUtils Maven / Gradle / Ivy
/*
* Copyright (c) 2001-2006, John Mettraux, OpenWFE.org
* 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 "OpenWFE" 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 OWNER 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.
*
* $Id: NetUtils.java 2713 2006-06-01 14:38:45Z jmettraux $
*/
//
// Utils.java
//
// [email protected]
//
// generated with
// jtmpl 1.0.04 31.10.2002 John Mettraux ([email protected])
//
package openwfe.org.net;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import openwfe.org.Utils;
import openwfe.org.misc.IoUtils;
/**
* Channels and ByteBuffer stuff
*
* CVS Info :
*
$Author: jmettraux $
*
$Date: 2006-06-01 16:38:45 +0200 (Thu, 01 Jun 2006) $
*
$Id: NetUtils.java 2713 2006-06-01 14:38:45Z jmettraux $
*
* @author [email protected]
*/
public abstract class NetUtils
{
private final static org.apache.log4j.Logger log = org.apache.log4j.Logger
.getLogger(NetUtils.class.getName());
/**
* The standard HTTP end of line
*/
public final static String HTTP_EOL
= "\r\n";
public final static String DOUBLE_HTTP_EOL
= HTTP_EOL + HTTP_EOL;
/*
* A small method that sleeps without emitting any InterruptedException
*
public static void sleep (long millis)
{
try
{
Thread.sleep(millis);
}
catch (InterruptedException ie)
{
// ignore
}
}
*
*/
/**
* Simply turning a nio.Channel into a byte array
*/
public static byte[] channelToByteArray
(final ReadableByteChannel readChannel)
throws
java.io.IOException
{
final int zeroReadMax = 2;
final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
final java.io.ByteArrayOutputStream baos =
new java.io.ByteArrayOutputStream();
final WritableByteChannel writeChannel = Channels.newChannel(baos);
int zeroReads = 0;
while (true)
{
final int read = readChannel.read(buffer);
//log.debug("==================== read "+read+" byte(s)");
if (read < 0) break;
if (read == 0)
{
if (++zeroReads >= zeroReadMax) break;
Thread.currentThread().yield();
continue;
}
zeroReads = 0;
buffer.flip();
writeChannel.write(buffer);
buffer.clear();
}
//log.debug("channelToByteArray:\n"+ new String(baos.toByteArray()));
final byte[] result = baos.toByteArray();
//
// some debug output
//
//int length = 14;
//if (result.length < 14) length = result.length;
//final byte[] head = new byte[length];
//String sHead2 = "";
//for (int i=0; i"+sHead1+"<");
//log.debug("channelToByteArray() head : "+sHead2);
return result;
}
/**
* A bit further : turning a channel into an input stream
*/
public static java.io.InputStream channelToInputStream
(final ReadableByteChannel readChannel)
throws
java.io.IOException
{
return new java.io.ByteArrayInputStream
(channelToByteArray(readChannel));
}
/**
* Still further : turning a channel into a reader
*/
public static java.io.Reader channelToReader
(final ReadableByteChannel readChannel)
throws
java.io.IOException
{
return new java.io.InputStreamReader
(channelToInputStream(readChannel));
}
/**
* Reads on a readable channel (a socket) until the second double HTTP eol
* is reached.
*/
public static byte[] readHttpRequest (final ReadableByteChannel readChannel)
throws java.io.IOException
{
int zeroReads = 0; // nb of time zero bytes were read
String requestType = null; // POST or GET or null ?
final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
final java.io.ByteArrayOutputStream baos =
new java.io.ByteArrayOutputStream();
final WritableByteChannel writeChannel =
Channels.newChannel(baos);
while (true)
{
final int read = readChannel.read(buffer);
if (log.isDebugEnabled())
log.debug("readHttpRequest() read "+read+" bytes");
if (read == 0)
{
zeroReads++;
if (zeroReads > 3) break;
Thread.currentThread().yield();
continue;
}
buffer.flip();
writeChannel.write(buffer);
final boolean reachedEol = isEol(buffer);
final String curReqType = determineRequestType(buffer);
if (log.isDebugEnabled())
{
log.debug
("readHttpRequest() [ requestType is "+requestType);
log.debug
("readHttpRequest() reachedEol is "+reachedEol);
log.debug
("readHttpRequest() curReqType is "+curReqType+" ]");
}
if (requestType == null)
{
requestType = curReqType;
if ("GET".equals(requestType) && reachedEol) break;
}
else
{
if (reachedEol) break;
}
zeroReads = 0;
buffer.clear();
}
return baos.toByteArray();
}
private static String determineRequestType (final ByteBuffer buffer)
throws java.io.IOException
{
buffer.rewind();
if (buffer.remaining() < 4) return null;
final byte[] ba = new byte[4];
for (int i=0; i<4; i++)
{
ba[i] = buffer.get();
}
String s = new String(ba, Utils.getEncoding());
s = s.toLowerCase();
if (log.isDebugEnabled())
log.debug("determineRequestType() found >"+s+"<");
if (s.equals("get ")) return "GET";
if (s.equals("post")) return "POST";
return null;
}
private static boolean isEol (final ByteBuffer buffer)
throws java.io.IOException
{
buffer.rewind();
//log.debug("isEol() remaining "+buffer.remaining()+" bytes");
if (buffer.remaining() < 4) return false;
buffer.position(buffer.limit()-4);
//log.debug("isEol() new pos "+buffer.position());
byte[] ba = new byte[4];
for (int i=0; i<4; i++) ba[i] = buffer.get();
final String s = new String(ba, Utils.getEncoding());
//log.debug("isEol() eol is "+asIntSequence(HTTP_EOL+HTTP_EOL));
//log.debug("isEol() for "+asIntSequence(s));
return (s.equals(HTTP_EOL+HTTP_EOL));
}
private static String asIntSequence (final String s)
{
final StringBuffer sb = new StringBuffer();
for (int i=0; i 0)
{
for (int i=0; i= 5)
{
//log.debug("drainInput() too much zero reads.");
break;
}
zeroReads++;
Thread.yield();
continue;
}
count++;
// debugging
//final char c = (char)i;
//String sc = ""+c;
//if (c == '\r') sc="\\r";
//if (c == '\n') sc="\\n";
//log.debug("drainInput() "+count+" read |"+sc+"| ("+i+")");
zeroReads = 0;
}
}
catch (final Throwable t)
{
log.debug("drainInput() read failure", t);
}
if (log.isDebugEnabled())
log.debug("drainInput() found "+count+" bytes.");
}
}