mirror of
https://github.com/corda/corda.git
synced 2025-01-03 19:54:13 +00:00
Added support for HTTP URL connections, and fixed SocketInputStream and BufferedInputStream.
Did some cleanup as proposed by the main developers. - Bigger HTTP Header Buffer - Exception if Header is anyway exceeded. - Linebreaks on HTTP Request fixed to standard. - Only stop header reading on \r\n\r\n and no longer on \n\n\n\n - Simplyfied the code to stop if buffer could not be filled. - Handle special case if buffer has length 0, like specified in the Java API - Socket will no longer fill the buffer completely
This commit is contained in:
parent
0c71ba0763
commit
524f034bac
@ -10,17 +10,111 @@
|
||||
|
||||
package avian.http;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.net.URLConnection;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.Socket;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Handler extends URLStreamHandler {
|
||||
protected URLConnection openConnection(URL url) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public class Handler extends URLStreamHandler
|
||||
{
|
||||
public URLConnection openConnection(URL url) throws IOException
|
||||
{
|
||||
return new HttpURLConnection(url);
|
||||
}
|
||||
|
||||
class HttpURLConnection extends URLConnection
|
||||
{
|
||||
Socket socket;
|
||||
private BufferedWriter writer;
|
||||
private InputStream bin;
|
||||
private Map<String,String> header = new HashMap<String, String>();
|
||||
private int status;
|
||||
|
||||
protected HttpURLConnection(URL url)
|
||||
{
|
||||
super(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() throws IOException
|
||||
{
|
||||
if(socket == null)
|
||||
{
|
||||
URLConnection con = null;
|
||||
String host = url.getHost();
|
||||
int port =url.getPort();
|
||||
if(port < 0) port = 80;
|
||||
socket = new Socket(host, port);
|
||||
OutputStream out = socket.getOutputStream();
|
||||
writer = new BufferedWriter(new OutputStreamWriter(out));
|
||||
writer.write("GET " + url.getPath() + " HTTP/1.1");
|
||||
writer.write("\r\nHost: " + host);
|
||||
writer.write("\r\n\r\n");
|
||||
writer.flush();
|
||||
bin = new BufferedInputStream(socket.getInputStream());
|
||||
readHeader();
|
||||
// System.out.println("Status: " + status);
|
||||
// System.out.println("Headers: " + header);
|
||||
}
|
||||
}
|
||||
|
||||
private void readHeader() throws IOException
|
||||
{
|
||||
byte[] buf = new byte[8192];
|
||||
int b = 0;
|
||||
int index = 0;
|
||||
while(b >= 0)
|
||||
{
|
||||
if(index >= 4 && buf[index-4] == '\r' && buf[index-3] == '\n' && buf[index-2] == '\r' && buf[index-1] == '\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
b = bin.read();
|
||||
buf[index] = (byte) b;
|
||||
index++;
|
||||
if(index >= buf.length)
|
||||
{
|
||||
throw new IOException("Header exceeded maximum size of 8k.");
|
||||
}
|
||||
}
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf, 0, index)));
|
||||
String line = reader.readLine();
|
||||
int x = line.indexOf(' ');
|
||||
status = Integer.parseInt(line.substring(x + 1 , line.indexOf(' ', x+1)));
|
||||
while(line != null)
|
||||
{
|
||||
int i = line.indexOf(':');
|
||||
if(i > 0)
|
||||
{
|
||||
header.put(line.substring(0, i), line.substring(i + 1) .trim());
|
||||
}
|
||||
line = reader.readLine();
|
||||
}
|
||||
reader.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException
|
||||
{
|
||||
connect();
|
||||
return bin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream() throws IOException
|
||||
{
|
||||
throw new UnsupportedOperationException("Can' write to HTTP Connection");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,11 @@
|
||||
|
||||
There is NO WARRANTY for this software. See license.txt for
|
||||
details. */
|
||||
|
||||
package java.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class BufferedInputStream extends InputStream {
|
||||
private final InputStream in;
|
||||
private final byte[] buffer;
|
||||
@ -25,17 +27,16 @@ public class BufferedInputStream extends InputStream {
|
||||
this(in, 4096);
|
||||
}
|
||||
|
||||
private void fill() throws IOException {
|
||||
private int fill() throws IOException {
|
||||
position = 0;
|
||||
limit = in.read(buffer);
|
||||
|
||||
return limit;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
if (position >= limit) {
|
||||
fill();
|
||||
if (limit == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (position >= limit && fill() == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return buffer[position++] & 0xFF;
|
||||
@ -43,7 +44,9 @@ public class BufferedInputStream extends InputStream {
|
||||
|
||||
public int read(byte[] b, int offset, int length) throws IOException {
|
||||
int count = 0;
|
||||
|
||||
if (position >= limit && fill() == -1) {
|
||||
return -1;
|
||||
}
|
||||
if (position < limit) {
|
||||
int remaining = limit - position;
|
||||
if (remaining > length) {
|
||||
@ -57,8 +60,8 @@ public class BufferedInputStream extends InputStream {
|
||||
offset += remaining;
|
||||
length -= remaining;
|
||||
}
|
||||
|
||||
while (length > 0) {
|
||||
while (length > 0 && in.available() > 0)
|
||||
{
|
||||
int c = in.read(b, offset, length);
|
||||
if (c == -1) {
|
||||
if (count == 0) {
|
||||
@ -69,13 +72,8 @@ public class BufferedInputStream extends InputStream {
|
||||
offset += c;
|
||||
count += c;
|
||||
length -= c;
|
||||
|
||||
if (in.available() <= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -87,3 +85,4 @@ public class BufferedInputStream extends InputStream {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,18 +86,16 @@ public class Socket implements Closeable, AutoCloseable {
|
||||
|
||||
@Override
|
||||
public int read(byte[] buffer) throws IOException {
|
||||
if(buffer.length == 0) return 0; //spec says return 0 if buffer length is zero.
|
||||
int fullSize = buffer.length;
|
||||
int index = 0;
|
||||
int size;
|
||||
do {
|
||||
size = recv(sock, buffer, index, Math.min(fullSize, Socket.BUFFER_SIZE));
|
||||
fullSize -= size;
|
||||
index += size;
|
||||
} while (fullSize != 0 && size != 0);
|
||||
return index;
|
||||
size = recv(sock, buffer, 0, Math.min(fullSize, Socket.BUFFER_SIZE));
|
||||
fullSize -= size;
|
||||
//removed loop, because otherwise interactive protocols will not work.
|
||||
if(size < 0) throw new IOException("Error while reading stream"); //as the manpage of recv says, a value below zero indicates an error.
|
||||
if(size == 0) return -1; // if the stream is closed (size == 0), then return -1 to indicate end of stream.
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private class SocketOutputStream extends OutputStream {
|
||||
|
80
test/BufferedInputStreamTest.java
Normal file
80
test/BufferedInputStreamTest.java
Normal file
@ -0,0 +1,80 @@
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.BufferedInputStream;
|
||||
|
||||
/**
|
||||
* Checks that BufferedInputStream does not block if data is available in it's internal buffer.
|
||||
*/
|
||||
public class BufferedInputStreamTest
|
||||
{
|
||||
public static void main(String[] args) throws IOException
|
||||
{
|
||||
MyByteArrayStream in = new MyByteArrayStream(new byte[100]);
|
||||
|
||||
BufferedInputStream bin = new BufferedInputStream(in);
|
||||
//read a single byte to fill the buffer
|
||||
int b = bin.read();
|
||||
byte[] buf = new byte[10];
|
||||
//now try to read 10 bytes. this should a least return the content of the buffer. On OpenJDK this are
|
||||
//4 bytes (the rest of the buffer returned by MyByteArrayStream in the first call).
|
||||
//It should definately NOT block.
|
||||
int count = bin.read(buf);
|
||||
System.out.println("Read bytes: " + count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal Stream used to show the BufferedInputStream behaviour.
|
||||
*/
|
||||
static class MyByteArrayStream extends ByteArrayInputStream
|
||||
{
|
||||
boolean stopReading = false;
|
||||
|
||||
/**
|
||||
* @param buf
|
||||
*/
|
||||
public MyByteArrayStream(byte[] buf)
|
||||
{
|
||||
super(buf);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.io.ByteArrayInputStream#read(byte[], int, int)
|
||||
*/
|
||||
@Override
|
||||
public synchronized int read(byte[] b, int off, int len)
|
||||
{
|
||||
if(stopReading == false)
|
||||
{ //On the first call 5 bytes are returned.
|
||||
stopReading = true;
|
||||
return super.read(b, off, 5);
|
||||
}
|
||||
//on all following calls block. The spec says, that a least one byte is returned, if the
|
||||
//stream is not at EOF.
|
||||
while(available() == 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(100);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.io.ByteArrayInputStream#available()
|
||||
*/
|
||||
@Override
|
||||
public synchronized int available()
|
||||
{
|
||||
if(stopReading)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return super.available();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user