jruby-http-kit 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +72 -0
- data/Rakefile +1 -0
- data/example/config.ru +9 -0
- data/example/hello_world.rb +17 -0
- data/example/rack.rb +11 -0
- data/example/ring.rb +31 -0
- data/example/sinatra/app.rb +9 -0
- data/example/sinatra/config.ru +8 -0
- data/example/webmachine/Gemfile +4 -0
- data/example/webmachine/Gemfile.lock +16 -0
- data/example/webmachine/app.rb +37 -0
- data/jruby-http-kit.gemspec +25 -0
- data/lib/http_kit/rack_handler.rb +139 -0
- data/lib/http_kit/server.rb +62 -0
- data/lib/http_kit/version.rb +3 -0
- data/lib/http_kit.rb +6 -0
- data/lib/java/clojure-1.5.1.jar +0 -0
- data/lib/java/http-kit.jar +0 -0
- data/lib/rack/handler/http_kit.rb +3 -0
- data/lib/rack/http_kit.rb +3 -0
- data/lib/webmachine/adapters/ring.rb +135 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/support/test_resource.rb +75 -0
- data/spec/webmachine/ring_adapter_spec.rb +127 -0
- data/src/.classpath +7 -0
- data/src/.project +17 -0
- data/src/org/httpkit/BytesInputStream.class +0 -0
- data/src/org/httpkit/BytesInputStream.java +83 -0
- data/src/org/httpkit/DateFormatter.class +0 -0
- data/src/org/httpkit/DynamicBytes.class +0 -0
- data/src/org/httpkit/DynamicBytes.java +76 -0
- data/src/org/httpkit/HTTPException.class +0 -0
- data/src/org/httpkit/HTTPException.java +10 -0
- data/src/org/httpkit/HeaderMap.class +0 -0
- data/src/org/httpkit/HeaderMap.java +98 -0
- data/src/org/httpkit/HttpMethod.class +0 -0
- data/src/org/httpkit/HttpMethod.java +28 -0
- data/src/org/httpkit/HttpStatus.class +0 -0
- data/src/org/httpkit/HttpStatus.java +416 -0
- data/src/org/httpkit/HttpUtils.class +0 -0
- data/src/org/httpkit/HttpUtils.java +484 -0
- data/src/org/httpkit/HttpVersion.class +0 -0
- data/src/org/httpkit/HttpVersion.java +5 -0
- data/src/org/httpkit/LineReader.class +0 -0
- data/src/org/httpkit/LineReader.java +52 -0
- data/src/org/httpkit/LineTooLargeException.class +0 -0
- data/src/org/httpkit/LineTooLargeException.java +13 -0
- data/src/org/httpkit/PrefixThreadFactory.class +0 -0
- data/src/org/httpkit/PrefixThreadFactory.java +20 -0
- data/src/org/httpkit/PriorityQueue.class +0 -0
- data/src/org/httpkit/PriorityQueue.java +235 -0
- data/src/org/httpkit/ProtocolException.class +0 -0
- data/src/org/httpkit/ProtocolException.java +10 -0
- data/src/org/httpkit/RequestTooLargeException.class +0 -0
- data/src/org/httpkit/RequestTooLargeException.java +10 -0
- data/src/org/httpkit/client/AbortException.class +0 -0
- data/src/org/httpkit/client/AbortException.java +13 -0
- data/src/org/httpkit/client/Decoder.class +0 -0
- data/src/org/httpkit/client/Decoder.java +182 -0
- data/src/org/httpkit/client/Handler.class +0 -0
- data/src/org/httpkit/client/HttpClient.class +0 -0
- data/src/org/httpkit/client/HttpClient.java +393 -0
- data/src/org/httpkit/client/HttpsRequest.class +0 -0
- data/src/org/httpkit/client/HttpsRequest.java +141 -0
- data/src/org/httpkit/client/IFilter$1.class +0 -0
- data/src/org/httpkit/client/IFilter$MaxBodyFilter.class +0 -0
- data/src/org/httpkit/client/IFilter.class +0 -0
- data/src/org/httpkit/client/IFilter.java +53 -0
- data/src/org/httpkit/client/IRespListener.class +0 -0
- data/src/org/httpkit/client/IRespListener.java +30 -0
- data/src/org/httpkit/client/IResponseHandler.class +0 -0
- data/src/org/httpkit/client/IResponseHandler.java +18 -0
- data/src/org/httpkit/client/PersistentConn.class +0 -0
- data/src/org/httpkit/client/PersistentConn.java +33 -0
- data/src/org/httpkit/client/Request.class +0 -0
- data/src/org/httpkit/client/Request.java +74 -0
- data/src/org/httpkit/client/RequestConfig.class +0 -0
- data/src/org/httpkit/client/RequestConfig.java +28 -0
- data/src/org/httpkit/client/RespListener.class +0 -0
- data/src/org/httpkit/client/RespListener.java +160 -0
- data/src/org/httpkit/client/SslContextFactory.class +0 -0
- data/src/org/httpkit/client/SslContextFactory.java +79 -0
- data/src/org/httpkit/client/State.class +0 -0
- data/src/org/httpkit/client/TimeoutException.class +0 -0
- data/src/org/httpkit/client/TimeoutException.java +12 -0
- data/src/org/httpkit/client/TrustManagerFactory$1.class +0 -0
- data/src/org/httpkit/client/TrustManagerFactory.class +0 -0
- data/src/org/httpkit/server/AsyncChannel.class +0 -0
- data/src/org/httpkit/server/AsyncChannel.java +286 -0
- data/src/org/httpkit/server/ClojureRing.class +0 -0
- data/src/org/httpkit/server/Frame$BinaryFrame.class +0 -0
- data/src/org/httpkit/server/Frame$CloseFrame.class +0 -0
- data/src/org/httpkit/server/Frame$PingFrame.class +0 -0
- data/src/org/httpkit/server/Frame$TextFrame.class +0 -0
- data/src/org/httpkit/server/Frame.class +0 -0
- data/src/org/httpkit/server/Frame.java +73 -0
- data/src/org/httpkit/server/HttpAtta.class +0 -0
- data/src/org/httpkit/server/HttpAtta.java +10 -0
- data/src/org/httpkit/server/HttpDecoder$State.class +0 -0
- data/src/org/httpkit/server/HttpDecoder.class +0 -0
- data/src/org/httpkit/server/HttpDecoder.java +202 -0
- data/src/org/httpkit/server/HttpHandler.class +0 -0
- data/src/org/httpkit/server/HttpRequest.class +0 -0
- data/src/org/httpkit/server/HttpRequest.java +109 -0
- data/src/org/httpkit/server/HttpServer.class +0 -0
- data/src/org/httpkit/server/HttpServer.java +281 -0
- data/src/org/httpkit/server/IHandler.class +0 -0
- data/src/org/httpkit/server/IHandler.java +12 -0
- data/src/org/httpkit/server/LinkingRunnable.class +0 -0
- data/src/org/httpkit/server/Rack.class +0 -0
- data/src/org/httpkit/server/RackApplication.class +0 -0
- data/src/org/httpkit/server/RackApplication.java +10 -0
- data/src/org/httpkit/server/RackHandler$1.class +0 -0
- data/src/org/httpkit/server/RackHandler.class +0 -0
- data/src/org/httpkit/server/RackHandler.java +259 -0
- data/src/org/httpkit/server/RackHttpHandler.class +0 -0
- data/src/org/httpkit/server/RackHttpHandler.java +20 -0
- data/src/org/httpkit/server/RespCallback.class +0 -0
- data/src/org/httpkit/server/RespCallback.java +19 -0
- data/src/org/httpkit/server/RingHandler$1.class +0 -0
- data/src/org/httpkit/server/RingHandler.class +0 -0
- data/src/org/httpkit/server/RingHandler.java +222 -0
- data/src/org/httpkit/server/ServerAtta.class +0 -0
- data/src/org/httpkit/server/ServerAtta.java +22 -0
- data/src/org/httpkit/server/WSDecoder$State.class +0 -0
- data/src/org/httpkit/server/WSDecoder.class +0 -0
- data/src/org/httpkit/server/WSDecoder.java +181 -0
- data/src/org/httpkit/server/WSHandler.class +0 -0
- data/src/org/httpkit/server/WsAtta.class +0 -0
- data/src/org/httpkit/server/WsAtta.java +11 -0
- data/src/org/httpkit/timer/CancelableFutureTask.class +0 -0
- data/src/org/httpkit/timer/CancelableFutureTask.java +52 -0
- data/src/org/httpkit/timer/TimerService.class +0 -0
- data/src/org/httpkit/timer/TimerService.java +89 -0
- metadata +241 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 56c70ef0759f2822347d81dbe2b63df5943b4b49
|
4
|
+
data.tar.gz: ec17992ca5cce5de410c8e82becb9139892fcd23
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0f003e0b6387208e134bb99f411c501f0313ffe471898b51ee9c69444416e8fbcbc67dfdfaac7dff6fe36e9f710771b6f47042560c91b1b4f359937c4f6b0448
|
7
|
+
data.tar.gz: 61c684208b24f10fcb11ff71b7779f6fc2d87d070b2bf1f0f9d9f4bcbbd9c8a3d13668c69f292f94253a64c977c03cc1a9d20c735df366582877b47175a00a83
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Dmitriy Rozhkov
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
jruby-http-kit
|
2
|
+
==============
|
3
|
+
|
4
|
+
JRuby wrapper for Clojure HTTP Kit library. Just a proof of a concept for now.
|
5
|
+
|
6
|
+
```
|
7
|
+
jruby -s ring_example.rb
|
8
|
+
|
9
|
+
curl -v 0.0.0.0:8089
|
10
|
+
```
|
11
|
+
|
12
|
+
MacBook Pro Retina 13" (2.5 GHz i5, 8GB RAM)
|
13
|
+
|
14
|
+
server runs in irb :)
|
15
|
+
|
16
|
+
```
|
17
|
+
λ ~/ wrk -t4 -c400 -d30 http://0.0.0.0:8089
|
18
|
+
Running 30s test @ http://0.0.0.0:8089
|
19
|
+
4 threads and 400 connections
|
20
|
+
|
21
|
+
Thread Stats Avg Stdev Max +/- Stdev
|
22
|
+
Latency 10.09ms 6.96ms 67.70ms 81.66%
|
23
|
+
Req/Sec 6.84k 1.99k 9.00k 82.93%
|
24
|
+
1000916 requests in 30.00s, 142.48MB read
|
25
|
+
Socket errors: connect 0, read 756, write 0, timeout 67
|
26
|
+
Requests/sec: 33367.54
|
27
|
+
Transfer/sec: 4.75MB
|
28
|
+
```
|
29
|
+
|
30
|
+
## Installation
|
31
|
+
|
32
|
+
Add this line to your application's Gemfile:
|
33
|
+
|
34
|
+
gem 'jruby-http-kit'
|
35
|
+
|
36
|
+
And then execute:
|
37
|
+
|
38
|
+
$ bundle
|
39
|
+
|
40
|
+
Or install it yourself as:
|
41
|
+
|
42
|
+
$ gem install jruby-http-kit
|
43
|
+
|
44
|
+
## Contributing
|
45
|
+
|
46
|
+
1. Fork it
|
47
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
48
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
49
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
50
|
+
5. Create new Pull Request
|
51
|
+
|
52
|
+
|
53
|
+
## License
|
54
|
+
|
55
|
+
### JRuby HTTP Kit wrapper
|
56
|
+
|
57
|
+
Copyright (c) 2013 Dmitriy Rozhkov
|
58
|
+
|
59
|
+
|
60
|
+
### HTTP Kit
|
61
|
+
|
62
|
+
Copyright © 2012-2013 [Feng Shen](http://shenfeng.me/). Distributed under the [Apache License Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html).
|
63
|
+
|
64
|
+
|
65
|
+
### Clojure
|
66
|
+
|
67
|
+
Copyright (c) Rich Hickey. All rights reserved.
|
68
|
+
|
69
|
+
The use and distribution terms for this software are covered by the
|
70
|
+
|
71
|
+
Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
72
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/example/config.ru
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class HelloWorld
|
2
|
+
def call(request)
|
3
|
+
body = "<html><p>Hello!</p></html>"
|
4
|
+
|
5
|
+
# headers = ["Content-Type", "text/html"].to_java(:string)
|
6
|
+
# headers = Java::ClojureLang::PersistentHashMap.create(headers)
|
7
|
+
|
8
|
+
# resp = [
|
9
|
+
# Java::ClojureLang::Keyword.intern("status") , 200,
|
10
|
+
# Java::ClojureLang::Keyword.intern("headers") , headers,
|
11
|
+
# Java::ClojureLang::Keyword.intern("body") , body
|
12
|
+
# ].to_java
|
13
|
+
# return Java::ClojureLang::PersistentHashMap.create(resp)
|
14
|
+
|
15
|
+
return [200, {"Content-Type" => "text/html"}, [body]]
|
16
|
+
end
|
17
|
+
end
|
data/example/rack.rb
ADDED
data/example/ring.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
$LOAD_PATH << '../lib'
|
2
|
+
|
3
|
+
require 'http_kit'
|
4
|
+
|
5
|
+
class HelloWorldHandler
|
6
|
+
include Java::ClojureLang::IFn
|
7
|
+
|
8
|
+
def invoke(request)
|
9
|
+
headers = ["Content-Type", "text/html"].to_java(:string)
|
10
|
+
headers = Java::clojure::lang::PersistentHashMap.create(headers)
|
11
|
+
|
12
|
+
resp = [
|
13
|
+
Java::ClojureLang::Keyword.intern("status") , 200,
|
14
|
+
Java::ClojureLang::Keyword.intern("headers") , headers,
|
15
|
+
Java::ClojureLang::Keyword.intern("body") , "hello HTTP! #{rand}"
|
16
|
+
].to_java
|
17
|
+
|
18
|
+
return Java::clojure::lang::PersistentHashMap.create(resp)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
req_handler = HelloWorldHandler.new()
|
23
|
+
ring_handler = Java::OrgHttpkitServer::RingHandler.new(100, req_handler, "prefix-", 1000)
|
24
|
+
server = Java::OrgHttpkitServer::HttpServer.new("0.0.0.0", 8089, ring_handler, 80000, 4000)
|
25
|
+
|
26
|
+
server.start()
|
27
|
+
|
28
|
+
Signal.trap("TERM") do
|
29
|
+
ring_handler.close()
|
30
|
+
server.stop()
|
31
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
$LOAD_PATH << File.expand_path('../../../lib', __FILE__)
|
2
|
+
|
3
|
+
require 'http_kit'
|
4
|
+
require 'webmachine'
|
5
|
+
require 'webmachine/adapters/ring'
|
6
|
+
|
7
|
+
class TestResource < Webmachine::Resource
|
8
|
+
def allowed_methods
|
9
|
+
%W{ GET HEAD OPTIONS POST PUT }
|
10
|
+
end
|
11
|
+
|
12
|
+
def content_types_provided
|
13
|
+
[['text/html', :render]]
|
14
|
+
end
|
15
|
+
|
16
|
+
def render
|
17
|
+
"Hello!"
|
18
|
+
end
|
19
|
+
|
20
|
+
def process_post
|
21
|
+
true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Service = Webmachine::Application.new do |app|
|
26
|
+
app.routes do
|
27
|
+
add ['*' ], TestResource
|
28
|
+
end
|
29
|
+
|
30
|
+
app.configure do |config|
|
31
|
+
config.ip = "0.0.0.0"
|
32
|
+
config.port = 9292
|
33
|
+
config.adapter = :Ring
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
Service.adapter.run
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'http_kit/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "jruby-http-kit"
|
8
|
+
spec.version = HttpKit::VERSION
|
9
|
+
spec.authors = ["Dmitriy Rozhkov"]
|
10
|
+
spec.email = ["rojkov.dmitry@gmail.com"]
|
11
|
+
spec.description = %q{}
|
12
|
+
spec.summary = %q{JRuby wrapper for Clojure HTTP Kit library.}
|
13
|
+
spec.homepage = "https://github.com/nLight/jruby-http-kit"
|
14
|
+
spec.license = ""
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency "webmachine"
|
25
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'rack/rewindable_input'
|
3
|
+
|
4
|
+
module HttpKit
|
5
|
+
|
6
|
+
java_import java.nio.ByteBuffer
|
7
|
+
|
8
|
+
java_import org.httpkit.HttpUtils
|
9
|
+
java_import org.httpkit.HeaderMap
|
10
|
+
java_import org.httpkit.HttpVersion
|
11
|
+
java_import org.httpkit.DynamicBytes
|
12
|
+
java_import org.httpkit.server.RackHttpHandler
|
13
|
+
java_import org.httpkit.server.RingHandler
|
14
|
+
java_import org.httpkit.server.HttpRequest
|
15
|
+
java_import org.httpkit.server.RespCallback
|
16
|
+
java_import org.httpkit.server.AsyncChannel
|
17
|
+
|
18
|
+
class HttpHandler < RackHttpHandler
|
19
|
+
field_reader :req
|
20
|
+
field_reader :cb
|
21
|
+
field_reader :handler
|
22
|
+
|
23
|
+
def http_request_to_rack(req)
|
24
|
+
env = {}
|
25
|
+
|
26
|
+
body = req.getBody() || Rack::RewindableInput.new(StringIO.new(""))
|
27
|
+
|
28
|
+
env["SERVER_SOFTWARE"] = "HTTP Kit"
|
29
|
+
env["SERVER_NAME"] = req.serverName
|
30
|
+
env["rack.input"] = body
|
31
|
+
env["rack.version"] = [1, 0]
|
32
|
+
env["rack.errors"] = $stderr
|
33
|
+
env["rack.multithread"] = true
|
34
|
+
env["rack.multiprocess"] = false
|
35
|
+
env["rack.run_once"] = false
|
36
|
+
env["REQUEST_METHOD"] = req.method.KEY.to_s.gsub(':', '').upcase
|
37
|
+
env["REQUEST_PATH"] = req.uri
|
38
|
+
env["PATH_INFO"] = req.uri
|
39
|
+
env["REQUEST_URI"] = "http://%s:%s%s" % [req.serverName, req.serverPort.to_s, req.uri]
|
40
|
+
env["HTTP_VERSION"] = "HTTP/1.1"
|
41
|
+
env["HTTP_HOST"] = "%s:%s" % [req.serverName, req.serverPort.to_s]
|
42
|
+
env["HTTP_ACCEPT"] = "*/*"
|
43
|
+
env["SERVER_PORT"] = req.serverPort.to_s
|
44
|
+
env["QUERY_STRING"] = req.queryString || ""
|
45
|
+
env["SERVER_PROTOCOL"] = "HTTP/1.1"
|
46
|
+
env["rack.url_scheme"] = "http" # only http is supported
|
47
|
+
env["REMOTE_ADDR"] = req.getRemoteAddr()
|
48
|
+
|
49
|
+
env["CONTENT_TYPE"] = req.contentType || ""
|
50
|
+
env["CONTENT_LENGTH"] = req.contentLength.to_s
|
51
|
+
|
52
|
+
# // m.put(URI, req.uri);
|
53
|
+
# // m.put(ASYC_CHANNEL, req.channel);
|
54
|
+
# // m.put(WEBSOCKET, req.isWebSocket);
|
55
|
+
|
56
|
+
# // // key is already lower cased, required by ring spec
|
57
|
+
# // m.put(HEADERS, PersistentArrayMap.create(req.headers));
|
58
|
+
# // m.put(CONTENT_TYPE, req.contentType);
|
59
|
+
# // m.put(CONTENT_LENGTH, req.contentLength);
|
60
|
+
# // m.put(CHARACTER_ENCODING, req.charset);
|
61
|
+
# // m.put(BODY, req.getBody());
|
62
|
+
|
63
|
+
env
|
64
|
+
end
|
65
|
+
|
66
|
+
def run
|
67
|
+
begin
|
68
|
+
resp = handler.call(http_request_to_rack(req))
|
69
|
+
if ! resp
|
70
|
+
cb.run(HttpUtils.HttpEncode(404, HeaderMap.new(), nil));
|
71
|
+
else
|
72
|
+
status, headers, body = resp
|
73
|
+
|
74
|
+
if ! body.is_a?(AsyncChannel)
|
75
|
+
b = DynamicBytes.new(512)
|
76
|
+
|
77
|
+
body.each do |chunk|
|
78
|
+
b.append(chunk.to_s)
|
79
|
+
end
|
80
|
+
|
81
|
+
body = ByteBuffer.wrap(b.get(), 0, b.length())
|
82
|
+
|
83
|
+
headers = HeaderMap.camelCase(headers)
|
84
|
+
|
85
|
+
# In HTTP 1.1, all connections are considered persistent unless declared otherwise.
|
86
|
+
if req.version == HttpVersion::HTTP_1_0 && req.isKeepAlive
|
87
|
+
headers.put("Connection", "Keep-Alive")
|
88
|
+
end
|
89
|
+
cb.run(HttpUtils.HttpEncode(status.to_i, headers, body))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
rescue => e
|
93
|
+
cb.run(HttpUtils.HttpEncode(500, HeaderMap.new(), e.message))
|
94
|
+
HttpUtils.printError(req.method + " " + req.uri, e);
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class RackHandler < RingHandler
|
100
|
+
|
101
|
+
field_reader :execs
|
102
|
+
field_reader :handler
|
103
|
+
|
104
|
+
def handle(*args)
|
105
|
+
if args[0].is_a?(HttpRequest) && args[1].is_a?(RespCallback)
|
106
|
+
handle_http(args[0], args[1])
|
107
|
+
else
|
108
|
+
handle_async(args[0], args[1])
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# void handle(HttpRequest request, RespCallback callback)
|
113
|
+
def handle_http(request, callback)
|
114
|
+
begin
|
115
|
+
execs.submit( HttpKit::HttpHandler.new(request, callback, handler) )
|
116
|
+
rescue java.util.concurrent.RejectedExecutionException => e
|
117
|
+
HttpUtils.printError("increase :queue-size if this happens often", e);
|
118
|
+
callback.run(HttpUtils.HttpEncode(503, HeaderMap.new(), "Server is overloaded, please try later"));
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# void handle(AsyncChannel channel, Frame frame)
|
123
|
+
def handle_async(channel, frame)
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
# java_signature %Q{ @override public void clientClose(AsyncChannel channel, int status) }
|
128
|
+
def client_close(channel, status)
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
# java_signature %Q{ @override void close() }
|
134
|
+
def close
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'http_kit/rack_handler'
|
2
|
+
|
3
|
+
module HttpKit
|
4
|
+
class Server
|
5
|
+
|
6
|
+
@lock ||= Mutex.new
|
7
|
+
|
8
|
+
def Server.run(app, options = {})
|
9
|
+
@lock.synchronize do
|
10
|
+
return if @server
|
11
|
+
@server = new
|
12
|
+
@server.run(app, options)
|
13
|
+
|
14
|
+
@server
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def Server.stop
|
19
|
+
@lock.synchronize do
|
20
|
+
return unless @server
|
21
|
+
|
22
|
+
@server.stop
|
23
|
+
@handler = nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def run(app, options={})
|
28
|
+
options = {
|
29
|
+
:host => "0.0.0.0",
|
30
|
+
:port => 9292,
|
31
|
+
:threads => 50,
|
32
|
+
:queue => 1000,
|
33
|
+
}.merge(options)
|
34
|
+
|
35
|
+
@handler = HttpKit::RackHandler.new(options[:threads], app, "prefix-", options[:queue])
|
36
|
+
@http_kit = Java::OrgHttpkitServer::HttpServer.new(options[:host], options[:port], @handler, 80000, 4000)
|
37
|
+
|
38
|
+
@http_kit.start
|
39
|
+
|
40
|
+
$stdout.printf("HTTP Kit is listening on %s:%s\n", options[:host], options[:port])
|
41
|
+
|
42
|
+
trap("SIGINT") {
|
43
|
+
@http_kit.stop
|
44
|
+
exit
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def start
|
49
|
+
@http_kit.start
|
50
|
+
end
|
51
|
+
|
52
|
+
def stop
|
53
|
+
return unless @http_kit
|
54
|
+
$stdout.print "Stopping Http kit..." unless @options[:quiet]
|
55
|
+
@http_kit.stop
|
56
|
+
$stdout.puts "done." unless @options[:quiet]
|
57
|
+
end
|
58
|
+
|
59
|
+
alias_method :shutdown, :stop
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
data/lib/http_kit.rb
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module Webmachine
|
2
|
+
module Adapters
|
3
|
+
class Ring < Webmachine::Adapter
|
4
|
+
|
5
|
+
DEFAULT_OPTIONS = {
|
6
|
+
:port => 9292,
|
7
|
+
:host => "0.0.0.0",
|
8
|
+
:threads => 50,
|
9
|
+
:queue_size => 1000,
|
10
|
+
:worker_prefix => "wm-",
|
11
|
+
:max_body_size => 8388608,
|
12
|
+
:max_http_line => 4096
|
13
|
+
}
|
14
|
+
|
15
|
+
# Start the Rack adapter
|
16
|
+
def run
|
17
|
+
options = DEFAULT_OPTIONS.merge({
|
18
|
+
:port => configuration.port,
|
19
|
+
:host => configuration.ip
|
20
|
+
}).merge(configuration.adapter_options)
|
21
|
+
|
22
|
+
req_handler = Handler.new(dispatcher)
|
23
|
+
|
24
|
+
@ring_handler = Java::OrgHttpkitServer::RingHandler.new(options[:threads],
|
25
|
+
req_handler,
|
26
|
+
options[:worker_prefix],
|
27
|
+
options[:queue_size])
|
28
|
+
|
29
|
+
@server = Java::OrgHttpkitServer::HttpServer.new(options[:host],
|
30
|
+
options[:port].to_i,
|
31
|
+
@ring_handler,
|
32
|
+
options[:max_body_size],
|
33
|
+
options[:max_http_line])
|
34
|
+
|
35
|
+
@server.start()
|
36
|
+
|
37
|
+
$stdout.printf "Webmachine Http kit is listening on %s:%s\n\n",
|
38
|
+
options[:host], options[:port]
|
39
|
+
|
40
|
+
Signal.trap("INT") { shutdown }
|
41
|
+
end
|
42
|
+
|
43
|
+
def shutdown
|
44
|
+
@ring_handler.close()
|
45
|
+
@server.stop()
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
class Handler
|
50
|
+
include Java::ClojureLang::IFn
|
51
|
+
|
52
|
+
attr_reader :dispatcher
|
53
|
+
|
54
|
+
def initialize(dispatcher)
|
55
|
+
@dispatcher = dispatcher
|
56
|
+
end
|
57
|
+
|
58
|
+
def invoke(request)
|
59
|
+
ring_request = Ring::RingRequest.new(request)
|
60
|
+
|
61
|
+
request = Webmachine::Request.new(ring_request.method,
|
62
|
+
ring_request.url,
|
63
|
+
ring_request.headers,
|
64
|
+
ring_request.body)
|
65
|
+
|
66
|
+
response = Webmachine::Response.new
|
67
|
+
|
68
|
+
dispatcher.dispatch(request, response)
|
69
|
+
|
70
|
+
headers = Java::JavaUtil::HashMap.new(response.headers)
|
71
|
+
|
72
|
+
Ring::RingResponse.create(response.code, headers, response.body)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class RingRequest
|
77
|
+
def initialize(request)
|
78
|
+
@request = request
|
79
|
+
end
|
80
|
+
|
81
|
+
def headers
|
82
|
+
Webmachine::Headers.from_cgi(@request.get(Java::ClojureLang::Keyword.intern("headers")))
|
83
|
+
end
|
84
|
+
|
85
|
+
def body
|
86
|
+
_body = @request.get( Java::ClojureLang::Keyword.intern("body") )
|
87
|
+
_body = _body.to_io if _body
|
88
|
+
end
|
89
|
+
|
90
|
+
def url
|
91
|
+
uri = @request.get(Java::ClojureLang::Keyword.intern("uri"))
|
92
|
+
query_string = @request.get(Java::ClojureLang::Keyword.intern("query-string"))
|
93
|
+
|
94
|
+
URI.parse("#{uri}?#{query_string}")
|
95
|
+
end
|
96
|
+
|
97
|
+
def method
|
98
|
+
@request.get(Java::ClojureLang::Keyword.intern("request-method")).to_s.delete(':').upcase
|
99
|
+
end
|
100
|
+
|
101
|
+
# Map<Object, Object> m = new TreeMap<Object, Object>();
|
102
|
+
# m.put(SERVER_PORT, req.serverPort);
|
103
|
+
# m.put(SERVER_NAME, req.serverName);
|
104
|
+
# m.put(REMOTE_ADDR, req.getRemoteAddr());
|
105
|
+
# m.put(URI, req.uri);
|
106
|
+
# m.put(SCHEME, HTTP); // only http is supported
|
107
|
+
# m.put(ASYC_CHANNEL, req.channel);
|
108
|
+
# m.put(WEBSOCKET, req.isWebSocket);
|
109
|
+
# m.put(REQUEST_METHOD, req.method.KEY);
|
110
|
+
|
111
|
+
# // key is already lower cased, required by ring spec
|
112
|
+
# m.put(HEADERS, PersistentArrayMap.create(req.headers));
|
113
|
+
# m.put(CONTENT_TYPE, req.contentType);
|
114
|
+
# m.put(CONTENT_LENGTH, req.contentLength);
|
115
|
+
# m.put(CHARACTER_ENCODING, req.charset);
|
116
|
+
# m.put(BODY, req.getBody());
|
117
|
+
# return PersistentArrayMap.create(m);
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
class RingResponse
|
122
|
+
def self.create(code, headers, body)
|
123
|
+
ring_response = [
|
124
|
+
Java::ClojureLang::Keyword.intern("status") , code,
|
125
|
+
Java::ClojureLang::Keyword.intern("headers") , headers,
|
126
|
+
Java::ClojureLang::Keyword.intern("body") , body
|
127
|
+
]
|
128
|
+
|
129
|
+
return Java::clojure::lang::PersistentHashMap.create(ring_response.to_java)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|