GithubHelp home page GithubHelp logo

niohttp's Introduction

NIOHttp

Build Status

Reading and writing HTTP request and response objects from and to java.nio.channels .

⚠️ This project has exploratory character and is in a very early stage of development.

Goals

  • Create a library/toolkit to write and read HTTP requests to and from java.nio.channels (Java's non-blocking IO)
  • Explore java.util.concurrentjava.util.concurrent API
  • Do not use external frameworks, integrate HTTP protocol and java.nio.channels using JDK 1.8+.

Boundary Conditions

  • zero external dependencies beside standard JDK except for unit & integration testing and build automation

Idea

First one need to connect a SocketStream to a URL such as http://www.raumzeitfalle.de/.

 
 URL url = new URL("http://www.raumzeitfalle.de/");
 InetSocketAddress address = new InetSocketAddress(url.getHost(), url.getDefaultPort());
 SocketChannel socketChannel = SocketChannel.open(address);

The server won't respond unless a request is sent (for example a GET request).

  writeGetRequestTo(socketChannel);
  

Even with bad requests server will respond, however, this may take time and response time is different. Here the static HttpResponseReader.fromChannel(...) method provides a FutureTask< Void > which can be executed by an ExecutorService. To collect the result, a Consumer< HttpResponse > must be provided. (https://github.com/Oliver-Loeffler/NIOHttp/blob/master/src/main/java/net/raumzeitfalle/niohttp/playground/FutureDemo.java)

 FutureTask<Void> futureTask = HttpResponseReader
 				.fromChannel(socketChannel,r -> System.out.println(r.responseHeader());
 		
 ExecutorService executor = Executors.newFixedThreadPool(1);
 executor.submit(futureTask);

Furthermore HttpResponseReader.fromChannel(...) returns a Stream of HttpResponse objects (https://github.com/Oliver-Loeffler/NIOHttp/blob/master/src/main/java/net/raumzeitfalle/niohttp/playground/StreamDemo.java)

Stream<HttpResponse> responseStream = HttpResponseReader.fromChannel(socketChannel); 
responseStream.findFirst().ifPresent(consumer);

This would enable (given appropriate HttpResponse capabilities), interesting ways of working with HttpResponses.

HttpResponseReader.fromChannel(socketChannel)
	    .filter( r -> r.isNotBadRequest() )
	    .findFirst().ifPresent(consumer);
	    

The current implementation is not yet fully functional here, as the HttpResponseReader only reads exactly one message from a channel. The response reading process has to be extended for continuous reading so that HttpResponse streaming will work.

Resources

The HTTP/1.1 Protocol

HTTP/2 Protocol

HTTP over TLS (transport layer security)

Java non-blocking IO (NIO and NIO2) and Networking

Other helpful references

niohttp's People

Contributors

hendrikebbers avatar oliver-loeffler avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

guigarage

niohttp's Issues

End of Response

I haven't tested it until know but it looks to me that currently the end of a response in the stream is found by searching for 2 line feeds. I think this is wrong since the payload of a response can contain several line feeds in the data. As far as I know each request / response has a content length field that defines the size of the content / payload (in bytes / characters?). I think this must be checked to find the end of a request / reponse, right?

Response Status Line parsing is error prone

With current implementation in HttpResponseReader in case of invalid messages there would be something like an IllegalArgumentError etc. Here it would be better to possibly return an Optional with a HttpResponse embedded when the response is valid. If response line is invalid, returning an empty Optional would be okay.

Consumers the can be called by:

HttpResponse.fromBytes(byte[] bytes).ifPresent(Consumer<HttpResponse> consumer)

Response status line is defined in http://httpwg.org/specs/rfc7230.html#status.line.

A valid response status line:

  • has no preceding empty lines
  • has no leading spaces
  • follows: status-line = HTTP-version SP status-code SP reason-phrase CRLF
  • with status being a 3 digit integer
  • with reason-phrase being a string followed by a line terminator (carriage return, line feed)

Placing this into separate class / method would make it testable. Here similar approach would be possible for Request Line.

Header Field Parsing Exception

Messages w/o message body (payload) cause an Exception as the HttpResponse.fromBytes() method tries to access message lines which do not exist.

int lineIndex = 1;
	String line = responseLines[lineIndex];
	while (!line.isEmpty()) {
	    HeaderField messageField = HeaderFieldFactory.getInstance().fromString(line);
	    int separation = line.indexOf(SPACE) + 1;
	    responseBuilder.addMessageField(messageField, line.substring(separation, line.length()));
	    line = responseLines[lineIndex++];
	}

The last call of java line = responseLines[lineIndex++]; will cause an exception when lineIndex exceeds length or java responseLines.length .

Response Message Body Parsing

See: http://httpwg.org/specs/rfc7230.html#message.body

Currently message body is considered to be a String and a StingBuilder is used to process all the message body lines if there are some.
As the message body is not defined as a simple String, instead it's a byte sequence with different possible encodings and formats, a separate class might be needed to consider all eventualities in message body parsing.

Minimal criteria for successful message body (payload) parsing:

  • define message body start criterion (http://httpwg.org/specs/rfc7230.html#http.message)
  • according to RFC7230 section 3, message body is separated by an empty line (CRLF + CRLF) from message header
  • message body presence is indicated by presence of a "Content-Length" or "Transfer-Encoding" header field (http://httpwg.org/specs/rfc7230.html#message.body)
  • Not all HTTP messages contain a message body, certain messages types such as (1xx, 204, 304) must not contain a body, whereas all others have a message body optionally of 0 bytes length

Define a class / class structure to process or parse message body depending on header fields.

Header Field Parsing

Implement a generic header field type and corresponding parser following the guide lines as defined in http://httpwg.org/specs/rfc7230.html#field.parsing .

  • field name and value are separated with a colon
  • no whitespace is allowed between the header field-name and colon, clients should not face this;
  • consider removal of bad whitespace
  • Remove preceding and trailing optional whitespace from field values
  • consider field values following the "obs-fold" (obsolete fold) rule
  • replace "obs-fold" by space (SP)
  • consider other encodings than standard US-ASCII, treat other octets in field content (obs‑text) as opaque data

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.