jruby-http-kit 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +72 -0
  7. data/Rakefile +1 -0
  8. data/example/config.ru +9 -0
  9. data/example/hello_world.rb +17 -0
  10. data/example/rack.rb +11 -0
  11. data/example/ring.rb +31 -0
  12. data/example/sinatra/app.rb +9 -0
  13. data/example/sinatra/config.ru +8 -0
  14. data/example/webmachine/Gemfile +4 -0
  15. data/example/webmachine/Gemfile.lock +16 -0
  16. data/example/webmachine/app.rb +37 -0
  17. data/jruby-http-kit.gemspec +25 -0
  18. data/lib/http_kit/rack_handler.rb +139 -0
  19. data/lib/http_kit/server.rb +62 -0
  20. data/lib/http_kit/version.rb +3 -0
  21. data/lib/http_kit.rb +6 -0
  22. data/lib/java/clojure-1.5.1.jar +0 -0
  23. data/lib/java/http-kit.jar +0 -0
  24. data/lib/rack/handler/http_kit.rb +3 -0
  25. data/lib/rack/http_kit.rb +3 -0
  26. data/lib/webmachine/adapters/ring.rb +135 -0
  27. data/spec/spec_helper.rb +24 -0
  28. data/spec/support/test_resource.rb +75 -0
  29. data/spec/webmachine/ring_adapter_spec.rb +127 -0
  30. data/src/.classpath +7 -0
  31. data/src/.project +17 -0
  32. data/src/org/httpkit/BytesInputStream.class +0 -0
  33. data/src/org/httpkit/BytesInputStream.java +83 -0
  34. data/src/org/httpkit/DateFormatter.class +0 -0
  35. data/src/org/httpkit/DynamicBytes.class +0 -0
  36. data/src/org/httpkit/DynamicBytes.java +76 -0
  37. data/src/org/httpkit/HTTPException.class +0 -0
  38. data/src/org/httpkit/HTTPException.java +10 -0
  39. data/src/org/httpkit/HeaderMap.class +0 -0
  40. data/src/org/httpkit/HeaderMap.java +98 -0
  41. data/src/org/httpkit/HttpMethod.class +0 -0
  42. data/src/org/httpkit/HttpMethod.java +28 -0
  43. data/src/org/httpkit/HttpStatus.class +0 -0
  44. data/src/org/httpkit/HttpStatus.java +416 -0
  45. data/src/org/httpkit/HttpUtils.class +0 -0
  46. data/src/org/httpkit/HttpUtils.java +484 -0
  47. data/src/org/httpkit/HttpVersion.class +0 -0
  48. data/src/org/httpkit/HttpVersion.java +5 -0
  49. data/src/org/httpkit/LineReader.class +0 -0
  50. data/src/org/httpkit/LineReader.java +52 -0
  51. data/src/org/httpkit/LineTooLargeException.class +0 -0
  52. data/src/org/httpkit/LineTooLargeException.java +13 -0
  53. data/src/org/httpkit/PrefixThreadFactory.class +0 -0
  54. data/src/org/httpkit/PrefixThreadFactory.java +20 -0
  55. data/src/org/httpkit/PriorityQueue.class +0 -0
  56. data/src/org/httpkit/PriorityQueue.java +235 -0
  57. data/src/org/httpkit/ProtocolException.class +0 -0
  58. data/src/org/httpkit/ProtocolException.java +10 -0
  59. data/src/org/httpkit/RequestTooLargeException.class +0 -0
  60. data/src/org/httpkit/RequestTooLargeException.java +10 -0
  61. data/src/org/httpkit/client/AbortException.class +0 -0
  62. data/src/org/httpkit/client/AbortException.java +13 -0
  63. data/src/org/httpkit/client/Decoder.class +0 -0
  64. data/src/org/httpkit/client/Decoder.java +182 -0
  65. data/src/org/httpkit/client/Handler.class +0 -0
  66. data/src/org/httpkit/client/HttpClient.class +0 -0
  67. data/src/org/httpkit/client/HttpClient.java +393 -0
  68. data/src/org/httpkit/client/HttpsRequest.class +0 -0
  69. data/src/org/httpkit/client/HttpsRequest.java +141 -0
  70. data/src/org/httpkit/client/IFilter$1.class +0 -0
  71. data/src/org/httpkit/client/IFilter$MaxBodyFilter.class +0 -0
  72. data/src/org/httpkit/client/IFilter.class +0 -0
  73. data/src/org/httpkit/client/IFilter.java +53 -0
  74. data/src/org/httpkit/client/IRespListener.class +0 -0
  75. data/src/org/httpkit/client/IRespListener.java +30 -0
  76. data/src/org/httpkit/client/IResponseHandler.class +0 -0
  77. data/src/org/httpkit/client/IResponseHandler.java +18 -0
  78. data/src/org/httpkit/client/PersistentConn.class +0 -0
  79. data/src/org/httpkit/client/PersistentConn.java +33 -0
  80. data/src/org/httpkit/client/Request.class +0 -0
  81. data/src/org/httpkit/client/Request.java +74 -0
  82. data/src/org/httpkit/client/RequestConfig.class +0 -0
  83. data/src/org/httpkit/client/RequestConfig.java +28 -0
  84. data/src/org/httpkit/client/RespListener.class +0 -0
  85. data/src/org/httpkit/client/RespListener.java +160 -0
  86. data/src/org/httpkit/client/SslContextFactory.class +0 -0
  87. data/src/org/httpkit/client/SslContextFactory.java +79 -0
  88. data/src/org/httpkit/client/State.class +0 -0
  89. data/src/org/httpkit/client/TimeoutException.class +0 -0
  90. data/src/org/httpkit/client/TimeoutException.java +12 -0
  91. data/src/org/httpkit/client/TrustManagerFactory$1.class +0 -0
  92. data/src/org/httpkit/client/TrustManagerFactory.class +0 -0
  93. data/src/org/httpkit/server/AsyncChannel.class +0 -0
  94. data/src/org/httpkit/server/AsyncChannel.java +286 -0
  95. data/src/org/httpkit/server/ClojureRing.class +0 -0
  96. data/src/org/httpkit/server/Frame$BinaryFrame.class +0 -0
  97. data/src/org/httpkit/server/Frame$CloseFrame.class +0 -0
  98. data/src/org/httpkit/server/Frame$PingFrame.class +0 -0
  99. data/src/org/httpkit/server/Frame$TextFrame.class +0 -0
  100. data/src/org/httpkit/server/Frame.class +0 -0
  101. data/src/org/httpkit/server/Frame.java +73 -0
  102. data/src/org/httpkit/server/HttpAtta.class +0 -0
  103. data/src/org/httpkit/server/HttpAtta.java +10 -0
  104. data/src/org/httpkit/server/HttpDecoder$State.class +0 -0
  105. data/src/org/httpkit/server/HttpDecoder.class +0 -0
  106. data/src/org/httpkit/server/HttpDecoder.java +202 -0
  107. data/src/org/httpkit/server/HttpHandler.class +0 -0
  108. data/src/org/httpkit/server/HttpRequest.class +0 -0
  109. data/src/org/httpkit/server/HttpRequest.java +109 -0
  110. data/src/org/httpkit/server/HttpServer.class +0 -0
  111. data/src/org/httpkit/server/HttpServer.java +281 -0
  112. data/src/org/httpkit/server/IHandler.class +0 -0
  113. data/src/org/httpkit/server/IHandler.java +12 -0
  114. data/src/org/httpkit/server/LinkingRunnable.class +0 -0
  115. data/src/org/httpkit/server/Rack.class +0 -0
  116. data/src/org/httpkit/server/RackApplication.class +0 -0
  117. data/src/org/httpkit/server/RackApplication.java +10 -0
  118. data/src/org/httpkit/server/RackHandler$1.class +0 -0
  119. data/src/org/httpkit/server/RackHandler.class +0 -0
  120. data/src/org/httpkit/server/RackHandler.java +259 -0
  121. data/src/org/httpkit/server/RackHttpHandler.class +0 -0
  122. data/src/org/httpkit/server/RackHttpHandler.java +20 -0
  123. data/src/org/httpkit/server/RespCallback.class +0 -0
  124. data/src/org/httpkit/server/RespCallback.java +19 -0
  125. data/src/org/httpkit/server/RingHandler$1.class +0 -0
  126. data/src/org/httpkit/server/RingHandler.class +0 -0
  127. data/src/org/httpkit/server/RingHandler.java +222 -0
  128. data/src/org/httpkit/server/ServerAtta.class +0 -0
  129. data/src/org/httpkit/server/ServerAtta.java +22 -0
  130. data/src/org/httpkit/server/WSDecoder$State.class +0 -0
  131. data/src/org/httpkit/server/WSDecoder.class +0 -0
  132. data/src/org/httpkit/server/WSDecoder.java +181 -0
  133. data/src/org/httpkit/server/WSHandler.class +0 -0
  134. data/src/org/httpkit/server/WsAtta.class +0 -0
  135. data/src/org/httpkit/server/WsAtta.java +11 -0
  136. data/src/org/httpkit/timer/CancelableFutureTask.class +0 -0
  137. data/src/org/httpkit/timer/CancelableFutureTask.java +52 -0
  138. data/src/org/httpkit/timer/TimerService.class +0 -0
  139. data/src/org/httpkit/timer/TimerService.java +89 -0
  140. 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
@@ -0,0 +1,19 @@
1
+ *.sublime-project
2
+ *.sublime-workspace
3
+ *.gem
4
+ *.rbc
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in jruby-http-kit.gemspec
4
+ gemspec
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,9 @@
1
+ $LOAD_PATH << File.expand_path('../../lib', __FILE__)
2
+
3
+ require 'rubygems'
4
+ require 'rack'
5
+ require 'http_kit'
6
+ require 'http_kit/server'
7
+ require 'hello_world'
8
+
9
+ run HelloWorld.new
@@ -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
@@ -0,0 +1,11 @@
1
+ $LOAD_PATH << '../lib'
2
+
3
+ require 'http_kit'
4
+ require 'http_kit/server'
5
+ require 'example/hello_world'
6
+
7
+ server = HttpKit::Server.run(HelloWorld.new)
8
+
9
+ Signal.trap("TERM") do
10
+ server.stop()
11
+ end
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,9 @@
1
+ require 'sinatra'
2
+
3
+ get '/' do
4
+ 'Hello world!'
5
+ end
6
+
7
+ get '/me' do
8
+ 'Hello http kit!'
9
+ end
@@ -0,0 +1,8 @@
1
+ $LOAD_PATH << File.expand_path('../../../lib', __FILE__)
2
+
3
+ require 'rubygems'
4
+ require 'rack'
5
+ require 'http_kit'
6
+ require 'app'
7
+
8
+ run Sinatra::Application
@@ -0,0 +1,4 @@
1
+ # A sample Gemfile
2
+ source "https://rubygems.org"
3
+
4
+ gem 'webmachine'
@@ -0,0 +1,16 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ as-notifications (1.0.1)
5
+ i18n (0.6.5)
6
+ multi_json (1.8.0)
7
+ webmachine (1.2.0)
8
+ as-notifications (~> 1.0)
9
+ i18n (>= 0.4.0)
10
+ multi_json
11
+
12
+ PLATFORMS
13
+ java
14
+
15
+ DEPENDENCIES
16
+ webmachine
@@ -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
@@ -0,0 +1,3 @@
1
+ module HttpKit
2
+ VERSION = "0.0.1"
3
+ end
data/lib/http_kit.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'java'
2
+
3
+ module HttpKit
4
+ require 'java/clojure-1.5.1'
5
+ require 'java/http-kit'
6
+ end
Binary file
Binary file
@@ -0,0 +1,3 @@
1
+ require 'http_kit/server'
2
+
3
+ Rack::Handler.register 'http_kit', 'HttpKit::Server'
@@ -0,0 +1,3 @@
1
+ require 'http_kit/server'
2
+
3
+ Rack::Handler.register 'http_kit', 'HttpKit::Server'
@@ -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