395220 New InputStream extension to allow a mix of EOL styles between headers and content

This commit is contained in:
Greg Wilkins 2012-11-29 13:29:03 +11:00
parent 11cbe274af
commit 249068551f
3 changed files with 336 additions and 0 deletions

View File

@ -0,0 +1,106 @@
package org.eclipse.jetty.util;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ReadLineInputStream extends BufferedInputStream
{
boolean _seenCRLF;
boolean _skipLF;
public ReadLineInputStream(InputStream in)
{
super(in);
}
public ReadLineInputStream(InputStream in, int size)
{
super(in,size);
}
public String readLine() throws IOException
{
mark(buf.length);
while (true)
{
int b=super.read();
if (b==-1)
{
markpos=-1;
return null;
}
if (b=='\r')
{
int p=pos;
// if we have seen CRLF before, hungrily consume LF
if (_seenCRLF && pos<count)
{
if (buf[pos]=='\n')
pos+=1;
}
else
_skipLF=true;
int m=markpos;
markpos=-1;
return new String(buf,m,p-m-1,StringUtil.__UTF8_CHARSET);
}
if (b=='\n')
{
if (_skipLF)
{
_skipLF=false;
_seenCRLF=true;
markpos++;
continue;
}
int m=markpos;
markpos=-1;
return new String(buf,m,pos-m-1,StringUtil.__UTF8_CHARSET);
}
}
}
@Override
public synchronized int read() throws IOException
{
int b = super.read();
if (_skipLF)
{
_skipLF=false;
if (_seenCRLF && b=='\n')
b=super.read();
}
return b;
}
@Override
public synchronized int read(byte[] buf, int off, int len) throws IOException
{
if (_skipLF && len>0)
{
_skipLF=false;
if (_seenCRLF)
{
int b = super.read();
if (b==-1)
return -1;
if (b!='\n')
{
buf[off]=(byte)(0xff&b);
return 1+super.read(buf,off+1,len-1);
}
}
}
return super.read(buf,off,len);
}
}

View File

@ -475,6 +475,7 @@ public class TypeUtil
/* ------------------------------------------------------------ */
@Deprecated
public static byte[] readLine(InputStream in) throws IOException
{
byte[] buf = new byte[256];

View File

@ -0,0 +1,229 @@
package org.eclipse.jetty.util;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class ReadLineInputStreamTest
{
BlockingArrayQueue<String> _queue = new BlockingArrayQueue<>();
PipedInputStream _pin;
volatile PipedOutputStream _pout;
ReadLineInputStream _in;
volatile Thread _writer;
@Before
public void before() throws Exception
{
_queue.clear();
_pin=new PipedInputStream();
_pout=new PipedOutputStream(_pin);
_in=new ReadLineInputStream(_pin);
_writer=new Thread()
{
@Override
public void run()
{
try
{
OutputStream out=_pout;
while (out!=null)
{
String s = _queue.poll(100,TimeUnit.MILLISECONDS);
if (s!=null)
{
if ("__CLOSE__".equals(s))
_pout.close();
else
{
_pout.write(s.getBytes(StringUtil.__UTF8_CHARSET));
Thread.sleep(50);
}
}
out=_pout;
}
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
_writer=null;
}
}
};
_writer.start();
}
@After
public void after() throws Exception
{
_pout=null;
while (_writer!=null)
Thread.sleep(10);
}
@Test
public void testCR() throws Exception
{
_queue.add("\rHello\rWorld\r\r");
_queue.add("__CLOSE__");
Assert.assertEquals("",_in.readLine());
Assert.assertEquals("Hello",_in.readLine());
Assert.assertEquals("World",_in.readLine());
Assert.assertEquals("",_in.readLine());
Assert.assertEquals(null,_in.readLine());
}
@Test
public void testLF() throws Exception
{
_queue.add("\nHello\nWorld\n\n");
_queue.add("__CLOSE__");
Assert.assertEquals("",_in.readLine());
Assert.assertEquals("Hello",_in.readLine());
Assert.assertEquals("World",_in.readLine());
Assert.assertEquals("",_in.readLine());
Assert.assertEquals(null,_in.readLine());
}
@Test
public void testCRLF() throws Exception
{
_queue.add("\r\nHello\r\nWorld\r\n\r\n");
_queue.add("__CLOSE__");
Assert.assertEquals("",_in.readLine());
Assert.assertEquals("Hello",_in.readLine());
Assert.assertEquals("World",_in.readLine());
Assert.assertEquals("",_in.readLine());
Assert.assertEquals(null,_in.readLine());
}
@Test
public void testCRBlocking() throws Exception
{
_queue.add("");
_queue.add("\r");
_queue.add("Hello");
_queue.add("\rWorld\r");
_queue.add("\r");
_queue.add("__CLOSE__");
Assert.assertEquals("",_in.readLine());
Assert.assertEquals("Hello",_in.readLine());
Assert.assertEquals("World",_in.readLine());
Assert.assertEquals("",_in.readLine());
Assert.assertEquals(null,_in.readLine());
}
@Test
public void testLFBlocking() throws Exception
{
_queue.add("");
_queue.add("\n");
_queue.add("Hello");
_queue.add("\nWorld\n");
_queue.add("\n");
_queue.add("__CLOSE__");
Assert.assertEquals("",_in.readLine());
Assert.assertEquals("Hello",_in.readLine());
Assert.assertEquals("World",_in.readLine());
Assert.assertEquals("",_in.readLine());
Assert.assertEquals(null,_in.readLine());
}
@Test
public void testCRLFBlocking() throws Exception
{
_queue.add("\r");
_queue.add("\nHello");
_queue.add("\r\nWorld\r");
_queue.add("\n\r");
_queue.add("\n");
_queue.add("");
_queue.add("__CLOSE__");
Assert.assertEquals("",_in.readLine());
Assert.assertEquals("Hello",_in.readLine());
Assert.assertEquals("World",_in.readLine());
Assert.assertEquals("",_in.readLine());
Assert.assertEquals(null,_in.readLine());
}
@Test
public void testHeaderLFBodyLF() throws Exception
{
_queue.add("Header\n");
_queue.add("\n");
_queue.add("\nBody\n");
_queue.add("\n");
_queue.add("__CLOSE__");
Assert.assertEquals("Header",_in.readLine());
Assert.assertEquals("",_in.readLine());
byte[] body = new byte[6];
_in.read(body);
Assert.assertEquals("\nBody\n",new String(body,0,6,StringUtil.__UTF8));
Assert.assertEquals("",_in.readLine());
Assert.assertEquals(null,_in.readLine());
}
@Test
public void testHeaderCRBodyLF() throws Exception
{
_queue.add("Header\r");
_queue.add("\r");
_queue.add("\nBody\n");
_queue.add("\r");
_queue.add("__CLOSE__");
Assert.assertEquals("Header",_in.readLine());
Assert.assertEquals("",_in.readLine());
byte[] body = new byte[6];
_in.read(body);
Assert.assertEquals("\nBody\n",new String(body,0,6,StringUtil.__UTF8));
Assert.assertEquals("",_in.readLine());
Assert.assertEquals(null,_in.readLine());
}
@Test
public void testHeaderCRLFBodyLF() throws Exception
{
_queue.add("Header\r\n");
_queue.add("\r\n");
_queue.add("\nBody\n");
_queue.add("\r\n");
_queue.add("__CLOSE__");
Assert.assertEquals("Header",_in.readLine());
Assert.assertEquals("",_in.readLine());
byte[] body = new byte[6];
_in.read(body);
Assert.assertEquals("\nBody\n",new String(body,0,6,StringUtil.__UTF8));
Assert.assertEquals("",_in.readLine());
Assert.assertEquals(null,_in.readLine());
}
}