Skip to content

Conversation

@asterite
Copy link
Member

This PR changes the way HTTP::Server and HTTP::Handler work. Instead of having each handler return a Response object that provides the body, headers, etc., now each handler receives a context that has both the request and an initial response, to which you can write. This makes it super simple to stream a response. For example:

require "http/server"

server = HTTP::Server.new("0.0.0.0", 8080) do |context|
  context.response.content_type = "text/plain"
  loop do |i|
    context.response.puts i
    context.response.flush
    sleep 1
  end
end
server.listen

This will print 0, 1, 2... endlessly on the response. Try to do that with the current approach and you'll see it's really hard.

Or, imagine you want to write a JSON object directly to the response (without building it in memory first), or a CSV file. Right now it's really hard, you have to create some sort of IO from which you read the contents.

Another good thing about this change is that HTTP::Server::Context has request and response properties, but you can add more properties to it so handlers down the chain have access to these. For example a handler that sets a session property.

The downside of this change is that response headers must be set before writing the body. There's also the thing that now we have HTTP::Client::Response (returned by an HTTP::Client request) and HTTP::Server::Response, to which you can write the body. But the advantages of this change are much more important than this little downside.

/cc @ysbaddaden @jhass @sdogruyol

@sdogruyol
Copy link
Member

This looks pretty cool! I'll give this try with Kemal middlewares.

Meanwhile how do i port something like this to new one https://github.com/sdogruyol/kemal/blob/master/src/kemal/middleware/http_basic_auth.cr ? Is passing around Context enough?

@alex-fedorov
Copy link

I like the idea! And code looks 👍

@asterite
Copy link
Member Author

@sdogruyol It changes to this: https://gist.github.com/asterite/57f9d71af44573d4c0db. Basically:

  1. Change the request parameter to context, and access it with context.request
  2. Instead of returning an HTTP::Response object, set the response properties with context.response.

@sdogruyol
Copy link
Member

Thanks @asterite . That's great!

This is not related to issue but how can i profile a code with Instrumentation tool on OS X? Because i'm getting performance degradation after Crystal 0.10.0 and i wanna investigate that.

@asterite
Copy link
Member Author

@sdogruyol
Copy link
Member

Thanks 👍

@asterite asterite force-pushed the feature/http-server-refactor branch from b781529 to 9dc0f4f Compare January 12, 2016 17:36
@luislavena
Copy link
Contributor

Thank you @asterite for working on this!!! ❤️ ❤️ ❤️

The modification suggested here will open the door to functionality like HTTP/2 Server Push.

There is a rich discussion about this between Ilya Grigorik, Aaron Patterson and others in relation to Ruby's Rack implementation of HTTP/2 spec:

tenderlove/the_metal#5

I believe is worth taking a look since redesign of HTTP::Server interface and request/response cycle will need to accommodate HTTP/2 support in the future.

@asterite asterite merged commit fd4b237 into master Jan 22, 2016
@asterite asterite deleted the feature/http-server-refactor branch January 25, 2016 16:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants