rhino 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 27a587d3f9f4876e2ccefd3b02d69e59c893f3ea
4
- data.tar.gz: 26291889cabbf4f9ada2530871dfbb1bc018ab79
3
+ metadata.gz: dfce0b40449bba07732e53828beb70d8672b978c
4
+ data.tar.gz: 44cf432edeb5f7eb726e5bff942c8a8b83169494
5
5
  SHA512:
6
- metadata.gz: c2868df4a87d7d6d4836d02ce71fa28963521d0e9d9d47dae5a8e420258ad01ef8334921071110fa340bc2e57e0506cd8df9372703092762f324e4e99db79715
7
- data.tar.gz: c7201266c8a0a0d8b1b69ce79417fcaa5f9325143c7b39b3674bc1c083560abad46d0ae75307d6438f672fe4ed0db3fb2b8bc876683e6b7a16c290f882c89956
6
+ metadata.gz: f9faf5b2a776213ccdcf5041ec78b893a1cc70802c8391c01da2c119f0acb88f801757fcf3130ab440032408cacfca0fd6366432d41dfa321c3483f2a52749b9
7
+ data.tar.gz: e91fe4af4a14c1178367450dd4306562fbb1ec4b8ab3baef398029c6cecd532db6a0b27e314fe8712d6df413c1b43a2c515481d463e2a3db6129ff792de849ac
data/bin/rhino CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'rhino'
3
+ require "rhino"
4
4
 
5
5
  cli = Rhino::CLI.new
6
6
  cli.parse
@@ -1,4 +1,8 @@
1
1
  require "rack"
2
+ require "slop"
3
+ require "socket"
4
+ require "time"
5
+ require "uri"
2
6
 
3
7
  require "rhino/cli"
4
8
  require "rhino/config"
@@ -10,10 +14,10 @@ require "rhino/version"
10
14
 
11
15
  module Rhino
12
16
  def self.config
13
- @@config ||= Rhino::Config.new
17
+ @config ||= Rhino::Config.new
14
18
  end
15
19
 
16
20
  def self.logger
17
- @@logger ||= Rhino::Logger.new
21
+ @logger ||= Rhino::Logger.new
18
22
  end
19
23
  end
@@ -1,14 +1,11 @@
1
- require "slop"
2
-
3
1
  module Rhino
4
2
 
5
- # A wrapper for command line interaction that encompasses option parsing, version, help, and execution. This class is
6
- # instantiated from the binary. The class also handles bootstrapping the launcher.
3
+ # A wrapper for command line interaction that encompasses option parsing, version, help, and execution.
7
4
  #
8
5
  # Usage:
9
6
  #
10
7
  # cli = Rhino::CLI.new
11
- # cli.parse()
8
+ # cli.parse
12
9
  #
13
10
  class CLI
14
11
  BANNER = "usage: rhino [options] [./config.ru]".freeze
@@ -17,18 +14,18 @@ module Rhino
17
14
  config = Slop.parse(items) do |options|
18
15
  options.banner = BANNER
19
16
 
20
- options.on "-h", "--help", 'help' do
17
+ options.on "-h", "--help", "help" do
21
18
  return help(options)
22
19
  end
23
20
 
24
- options.on "-v", "--version", 'version' do
21
+ options.on "-v", "--version", "version" do
25
22
  return version
26
23
  end
27
24
 
28
- options.string "-b", "--bind", 'bind (default: 0.0.0.0)', default: "0.0.0.0"
29
- options.integer "-p", "--port", 'port (default: 5000)', default: 5000
30
- options.integer "--backlog", 'backlog (default: 64)', default: 64
31
- options.boolean "--reuseaddr", 'reuseaddr (default: true)', default: true
25
+ options.string "-b", "--bind", "bind (default: 0.0.0.0)", default: "0.0.0.0"
26
+ options.integer "-p", "--port", "port (default: 5000)", default: 5000
27
+ options.integer "--backlog", "backlog (default: 64)", default: 64
28
+ options.boolean "--reuseaddr", "reuseaddr (default: true)", default: true
32
29
  end
33
30
 
34
31
  run(config)
@@ -45,8 +42,8 @@ module Rhino
45
42
  end
46
43
 
47
44
  def run(options)
48
- config, _ = options.arguments
49
- Launcher.new(options[:port], options[:bind], options[:reuseaddr], options[:backlog], config || './config.ru').run
45
+ config, = options.arguments
46
+ Launcher.new(options[:port], options[:bind], options[:reuseaddr], options[:backlog], config || "./config.ru").run
50
47
  end
51
48
 
52
49
  end
@@ -1,7 +1,15 @@
1
1
  module Rhino
2
+
3
+ # Configuration options used internally such as multithread and multiprocess. Can be accessed via the global.
4
+ #
5
+ # Usage:
6
+ #
7
+ # Rhino.config
8
+ #
2
9
  class Config
3
10
  attr_accessor :multithread
4
11
  attr_accessor :multiprocess
5
12
  attr_accessor :run_once
6
13
  end
14
+
7
15
  end
@@ -1,8 +1,12 @@
1
- require "uri"
2
- require "rack"
3
- require "time"
4
-
5
1
  module Rhino
2
+
3
+ # An interface for HTTP. Responsible for reading and writting to the socket via the HTTP protocol.
4
+ #
5
+ # Usage:
6
+ #
7
+ # http = Rhino::HTTP.new(socket, application)
8
+ # http.handle
9
+ #
6
10
  class HTTP
7
11
  RESERVED = /\A(Date|Connection)\Z/i.freeze
8
12
  VERSION = "HTTP/1.1".freeze
@@ -12,9 +16,11 @@ module Rhino
12
16
  end
13
17
 
14
18
  attr_accessor :socket
19
+ attr_accessor :application
15
20
 
16
- def initialize(socket)
21
+ def initialize(socket, application)
17
22
  self.socket = socket
23
+ self.application = application
18
24
  end
19
25
 
20
26
  def parse
@@ -45,13 +51,31 @@ module Rhino
45
51
  "SCRIPT_NAME" => "",
46
52
  }
47
53
 
48
- while matches = /\A(?<key>[^:]+):\s+(?<value>.*)#{CRLF}\Z/.match(line = socket.gets) do
49
-
50
- case matches[:key]
51
- when Rack::CONTENT_TYPE then env["CONTENT_TYPE"] = matches[:value]
52
- when Rack::CONTENT_LENGTH then env["CONTENT_LENGTH"] = Integer(matches[:value])
53
- else env["HTTP_" + matches[:key].tr("-", "_").upcase] ||= matches[:value]
54
+ key = nil
55
+ value = nil
56
+ loop do
57
+ hl = socket.gets
58
+
59
+ if key && value
60
+ matches = /\A\s+(?<fold>.+)#{CRLF}\Z/.match(hl)
61
+ if matches
62
+ value = "#{value} #{matches[:fold].strip}"
63
+ next
64
+ end
65
+
66
+ case key
67
+ when Rack::CONTENT_TYPE then env["CONTENT_TYPE"] = value
68
+ when Rack::CONTENT_LENGTH then env["CONTENT_LENGTH"] = Integer(value)
69
+ else env["HTTP_" + key.tr("-", "_").upcase] ||= value
70
+ end
54
71
  end
72
+
73
+ break if hl.eql?(CRLF)
74
+
75
+ matches = /\A(?<key>[^:]+):\s*(?<value>.+)#{CRLF}\Z/.match(hl)
76
+ raise Exception.new("invalid header line: #{hl.inspect}") unless matches
77
+ key = matches[:key].strip
78
+ value = matches[:value].strip
55
79
  end
56
80
 
57
81
  input = socket.read(env["CONTENT_LENGTH"] || 0)
@@ -61,9 +85,16 @@ module Rhino
61
85
  return env
62
86
  end
63
87
 
64
- def handle(application)
88
+ def handle
65
89
  env = parse
66
- status, headers, body = application.call(env)
90
+
91
+ begin
92
+ status, headers, body = application.call(env)
93
+ rescue ::Exception => exception
94
+ Rhino.logger.log(exception.inspect)
95
+ status, headers, body = 500, {}, []
96
+ end
97
+
67
98
  time = Time.now.httpdate
68
99
 
69
100
  socket.write "#{VERSION} #{status} #{Rack::Utils::HTTP_STATUS_CODES.fetch(status) { 'UNKNOWN' }}#{CRLF}"
@@ -1,4 +1,12 @@
1
1
  module Rhino
2
+
3
+ # Handles the bootstrapping of the application (setting up sockets, building via rack, etc).
4
+ #
5
+ # Usage:
6
+ #
7
+ # launcher = Rhino.Launcher.new(5000, '0.0.0.0', reuseaddr, 64, './config.ru')
8
+ # launcher.run
9
+ #
2
10
  class Launcher
3
11
  attr_accessor :port
4
12
  attr_accessor :bind
@@ -44,4 +52,5 @@ module Rhino
44
52
  end
45
53
 
46
54
  end
55
+
47
56
  end
@@ -1,4 +1,11 @@
1
1
  module Rhino
2
+
3
+ # A generic logger extracting output for testing. Can be accessed via the global.
4
+ #
5
+ # Usage:
6
+ #
7
+ # Rhino.logger.log("...")
8
+ #
2
9
  class Logger
3
10
  attr_accessor :stream
4
11
 
@@ -7,8 +14,9 @@ module Rhino
7
14
  end
8
15
 
9
16
  def log(message)
10
- self.stream.puts "#{message}"
17
+ self.stream.puts message
11
18
  end
12
19
 
13
20
  end
21
+
14
22
  end
@@ -1,5 +1,3 @@
1
- require 'socket'
2
-
3
1
  module Rhino
4
2
  class Server
5
3
  attr_accessor :application
@@ -22,16 +20,19 @@ module Rhino
22
20
  end
23
21
 
24
22
  def monitor
25
- selections, _, _ = IO.select(self.sockets)
26
- io, _ = selections
23
+ selections, = IO.select(self.sockets)
24
+ io, = selections
27
25
 
28
26
  begin
29
- socket, _ = io.accept
30
- http = Rhino::HTTP::new(socket)
31
- http.handle(application)
32
- rescue ::Errno::ECONNRESET , ::Errno::ENOTCONN
33
- rescue::Exception => exception
27
+ socket, = io.accept
28
+ http = Rhino::HTTP::new(socket, application)
29
+ http.handle
30
+ rescue Rhino::HTTP::Exception => exception
34
31
  Rhino.logger.log("EXCEPTION: #{exception.message}")
32
+ rescue ::Errno::ECONNRESET
33
+ rescue ::Errno::ENOTCONN
34
+ rescue ::Errno::EPIPE
35
+ rescue ::Errno::EPROTOTYPE
35
36
  ensure
36
37
  socket.close
37
38
  end
@@ -1,3 +1,3 @@
1
1
  module Rhino
2
- VERSION = '0.0.2'
2
+ VERSION = "0.0.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rhino
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Sylvestre
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-29 00:00:00.000000000 Z
11
+ date: 2016-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: slop
@@ -94,7 +94,7 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
- description: This should probably never be used unless you are feeling lucky.
97
+ description: This should probably never be used.
98
98
  email:
99
99
  - kevin@ksylvest.com
100
100
  executables: