Skip to content

vladfaust/http-multiserver.cr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HTTP::Multiserver

Built with Crystal Build status API Docs Releases Awesome vladfaust.com Patrons count Gitter chat

The requests dispatcher shard for Crystal.

Supporters

Thanks to all my patrons, I can continue working on beautiful Open Source Software! 🙏

Lauri Jutila, Alexander Maslov, Dainel Vera

You can become a patron too in exchange of prioritized support and other perks

Become Patron

About

HTTP::Multiserver dispatches a server request to another vanilla HTTP::Server depending on its path similar to Ruby's Rack::URLMap.

Installation

Add this to your application's shard.yml:

dependencies:
  http-multiserver:
    github: vladfaust/http-multiserver.cr
    version: ~> 0.2.0

This shard follows Semantic Versioning 2.0.0, so see releases and change the version accordingly.

Usage

Basic example

require "http-multiserver"

simple_server = HTTP::Server.new([HTTP::LogHandler.new]) do |context|
  context.response.print("Hello from Simple Server!")
end

# For example purposes
resque = Resque::Server.new

multiserver = HTTP::Multiserver.new({
  "/resque" => resque,
  "/"       => simple_server,
}, [HTTP::ErrorHandler.new(true)]) do |context|
  # This is an optional custom fallback handler; by default returns "404 Not Found"
  context.response.status_code = 418
  context.response.print("#{context.request.path} not found")
end

multiserver.bind_tcp(5000)
multiserver.listen

HTTP::Multiserver extends from a regular HTTP::Server, so it CAN have its own handlers. Same for underlying servers, they obviously CAN have their own handlers too.

Mapping

Mapping relies on either String or Regex keys; when using String as a key, a slash is automatically appended to it.

Assuming that this map is passed to HTTP::Multiserver initializer:

map = {
  "/foo"   => foo_server,
  %r{/bar} => bar_server,
  "/"      => fallback_server
}

multiserver = HTTP::Multiserver.new(port, map)

This is how the request is dispatched under the hood (simplified):

internal_map = {
  %r{^/foo/} => foo_server,
  %r{/bar}   => bar_server,
  %r{^/}     => fallback_server
}

path = request.path.append_slash # "/foo/abc" turns into "foo/abc/"
server = internal_map.find { |regex, _| regex.match(path) }
server ? server.call(context) : not_found

Please see specs for dispatching specifications.

Performance

As mentioned above, HTTP::Multiserver is just a regular HTTP::Server which dispatches the handling to underlying servers based on super-fast Regex.match. A very tiny impact on the performance is expected if any.

Contributing

  1. Fork it ( https://github.com/vladfaust/http-multiserver.cr/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors