miniserver 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9ad70987c27eba35d73e421e04b626e8cd0bd6a5
4
+ data.tar.gz: f974f8e519e04bf356e9f24497600e561fa2d0a8
5
+ SHA512:
6
+ metadata.gz: b5fefa23eb21d64ee6473e25712b6153fde6bc674ac0081c12d4f4b3e7c5b9e34aa73c54bab6062aa077ea6aaa4e916650cb67598f13e3bb718a6d4c6082168f
7
+ data.tar.gz: 57e62a7cf011f9e4d78aedaec76248dd8d76af9e528c4799eed8edc0af28ec6d2ac2749296e756c8167cf70ca72ce0e2d5d35c61d1caa889f58bc5b4acdd79ab
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.swp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in miniserver.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 zhouguangming
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.
@@ -0,0 +1,25 @@
1
+ # Miniserver
2
+
3
+ Miniserver is a simple fast HTTP 1.1 server for Ruby/Rack applications.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'miniserver'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install miniserver
18
+
19
+ ## Contributing
20
+
21
+ 1. Fork it
22
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
23
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
24
+ 4. Push to the branch (`git push origin my-new-feature`)
25
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,5 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'miniserver'
4
+
5
+ Miniserver::Command.new(ARGV).run!
@@ -0,0 +1,26 @@
1
+ require 'miniserver/version'
2
+ require 'miniserver/server'
3
+ require 'miniserver/const'
4
+ require 'miniserver/command'
5
+ require 'rack/handler/miniserver'
6
+
7
+ module Process
8
+ def running?(pid)
9
+ Process.getpgid(pid) != -1
10
+ rescue Errno::EPERM
11
+ true
12
+ rescue Errno::ESRCH
13
+ false
14
+ end
15
+ module_function :running?
16
+ end
17
+
18
+ module Miniserver
19
+ def self.logger=(logger)
20
+ @logger=logger
21
+ end
22
+
23
+ def self.logger
24
+ @logger
25
+ end
26
+ end
@@ -0,0 +1,106 @@
1
+ require 'miniserver/runner'
2
+ require 'open3'
3
+ require 'optparse'
4
+
5
+ module Miniserver
6
+ class Command
7
+ COMMANDS = %w(start stop restart status)
8
+
9
+ def initialize(argv)
10
+ @options = {
11
+ daemonize: false,
12
+ host: '0.0.0.0',
13
+ port: 8080,
14
+ rackup: ::File.expand_path('config.ru'),
15
+ log: ::File.expand_path('log/miniserver.log'),
16
+ pid: ::File.expand_path('tmp/pids/miniserver.pid'),
17
+ environment: 'development'
18
+ }
19
+
20
+ parser.parse!(argv)
21
+
22
+ @command = argv.pop || 'start'
23
+ end
24
+
25
+ def run!
26
+ if COMMANDS.include?(@command)
27
+ Runner.new(@options).send(@command)
28
+ else
29
+ puts @parser
30
+ end
31
+ end
32
+
33
+ def parser
34
+ @parser ||= OptionParser.new do |o|
35
+ o.banner = "Miniserver #{Miniserver::VERSION}\nUsage: miniserver <options> #{COMMANDS.join('|')}"
36
+ o.separator ""
37
+
38
+ o.on "-p", "--port PORT", "Define the TCP port to bind (default: #{@options[:port]})" do |arg|
39
+ @options[:port] = arg
40
+ end
41
+
42
+ o.on "-o", "--host HOST", "Bind to HOST address (default: #{@options[:host]})" do |arg|
43
+ @options[:host] = arg
44
+ end
45
+
46
+ o.on "-l", "--log FILE", "File to redirect output (default: log/miniserver.log)" do |arg|
47
+ @options[:log] = arg
48
+ end
49
+
50
+ o.on "-P", "--pid FILE", "File to store PID (default: tmp/pids/miniserver.pid)" do |arg|
51
+ @options[:pid] = arg
52
+ end
53
+
54
+ o.on "-d", "--daemonize", "Run daemonized in the background(default: false)" do |arg|
55
+ @options[:daemonize] = arg
56
+ end
57
+
58
+ o.on "-e", "--environment ENVIRONMENT", "The environment to run the Rack app on (default development)" do |arg|
59
+ @options[:environment] = arg
60
+ end
61
+
62
+ o.on "-R", "--rackup FILE", "Load a Rack config file (default: #{@options[:rackup]})" do |arg|
63
+ @options[:rackup] = arg
64
+ end
65
+
66
+ o.on_tail "-h", "--help", "Show help" do
67
+ puts @parser
68
+ exit
69
+ end
70
+
71
+ o.on_tail("-v", "--version", "Show version") do
72
+ puts "Miniserver #{Miniserver::VERSION}"
73
+ exit
74
+ end
75
+ end
76
+ end
77
+
78
+ def self.restart(script, options)
79
+ File.delete(options[:pid]) if File.exist?(options[:pid])
80
+
81
+ shellified_options = options.inject([]) do |args, (name, value)|
82
+ option_name = name.to_s.tr("_", "-")
83
+ case value
84
+ when NilClass, TrueClass
85
+ args << "--#{option_name}"
86
+ when FalseClass
87
+ when Array
88
+ value.each { |v| args << "--#{option_name}=#{v}" }
89
+ else
90
+ args << "--#{option_name}=#{value}"
91
+ end
92
+
93
+ args
94
+ end
95
+
96
+ cmd = "#{script} #{shellified_options.compact.join(' ')} start"
97
+
98
+ Open3.popen3(cmd) do |stdin, stdout, stderr|
99
+ puts stdout.gets until stdout.eof?
100
+ puts stderr.gets until stderr.eof?
101
+ end
102
+
103
+ exit
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,78 @@
1
+ require 'miniserver/request'
2
+ require 'miniserver/response'
3
+ require 'http/parser'
4
+ require 'time'
5
+
6
+ module Miniserver
7
+ class Connection < EM::Connection
8
+ attr_accessor :app
9
+
10
+ def post_init
11
+ @request = Request.new
12
+ @response = Response.new
13
+ @parser = Http::Parser.new(self)
14
+ end
15
+
16
+ def on_headers_complete(headers)
17
+ @request.headers = headers
18
+ @request.parse_header(@parser, self)
19
+ end
20
+
21
+ def on_body(chunk)
22
+ @request.body << chunk
23
+ end
24
+
25
+ def on_message_complete
26
+ begin
27
+ Rack::Handler::Miniserver.new(app).process(@request, @response)
28
+ send_response!
29
+ rescue
30
+ Miniserver.logger.error("!! Unexpected error while processing request: #{$!.message}")
31
+ ensure
32
+ close_connection_after_writing
33
+ end
34
+ end
35
+
36
+ def receive_data(data)
37
+ @parser << data
38
+ end
39
+
40
+ def send_response!
41
+ send_status_line
42
+ send_headers
43
+ send_data(BLANK_LINE)
44
+ send_body
45
+ end
46
+
47
+ def send_status_line
48
+ send_data("#{HTTP_VERSION} #{@response.status} #{HTTP_CODE[@response.status]}#{BLANK_LINE}")
49
+ end
50
+
51
+ def send_headers
52
+ headers = String.new
53
+
54
+ @response.headers[SERVER] = MINISERVER
55
+ @response.headers[DATE] = Time.now.httpdate
56
+
57
+ @response.headers.each do |name, value|
58
+ if value.is_a?(String)
59
+ value.split(NEWLINE).each do |v|
60
+ headers.concat("#{name}#{COLON} #{v}#{BLANK_LINE}")
61
+ end
62
+ else
63
+ headers.concat("#{name}#{COLON} #{value}#{BLANK_LINE}")
64
+ end
65
+ end
66
+
67
+ send_data(headers)
68
+ end
69
+
70
+ def send_body
71
+ begin
72
+ @response.body.each { |chunk| send_data(chunk) }
73
+ ensure
74
+ @response.body.close if @response.body.respond_to?(:close)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,96 @@
1
+ module Miniserver
2
+ HTTP_VERSION = 'HTTP/1.1'
3
+ NEWLINE = "\n"
4
+ BLANK_LINE = "\r\n"
5
+ SERVER = 'Server'
6
+ MINISERVER = "Miniserver #{Miniserver::VERSION}"
7
+ CONTENT_LENGTH = 'Content-Length'
8
+ CONTENT_TYPE = 'Content-Type'
9
+ COLON = ':'
10
+ HTTP_PREFIX = 'HTTP_'
11
+ HTTP = 'http'
12
+ HTTPS = 'https'
13
+ EMPTY_STRING = ''
14
+ MINUS = '-'
15
+ UNDERLINE = '_'
16
+ DATE = 'Date'
17
+ CONNECTION = 'Connection'
18
+ KEEP_ALIVE = 'keep-alive'
19
+ CLOSE = 'close'
20
+ HOST = 'Host'
21
+ PORT_80 = '80'
22
+ PATH_INFO = 'PATH_INFO'
23
+ REQUEST_METHOD = 'REQUEST_METHOD'
24
+ REQUEST_PATH = 'REQUEST_PATH'
25
+ SCRIPT_NAME = 'SCRIPT_NAME'
26
+ FRAGMENT = 'FRAGMENT'
27
+ QUERY_STRING = 'QUERY_STRING'
28
+ REMOTE_ADDR = 'REMOTE_ADDR'
29
+ SERVER_NAME = 'SERVER_NAME'
30
+ SERVER_PORT = 'SERVER_PORT'
31
+
32
+ HTTP_CODE = {
33
+ 100 => 'Continue',
34
+ 101 => 'Switching Protocols',
35
+ 102 => 'Processing',
36
+ 200 => 'OK',
37
+ 201 => 'Created',
38
+ 202 => 'Accepted',
39
+ 203 => 'Non-Authoritative Information',
40
+ 204 => 'No Content',
41
+ 205 => 'Reset Content',
42
+ 206 => 'Partial Content',
43
+ 207 => 'Multi-Status',
44
+ 208 => 'Already Reported',
45
+ 226 => 'IM Used',
46
+ 300 => 'Multiple Choices',
47
+ 301 => 'Moved Permanently',
48
+ 302 => 'Found',
49
+ 303 => 'See Other',
50
+ 304 => 'Not Modified',
51
+ 305 => 'Use Proxy',
52
+ 306 => 'Reserved',
53
+ 307 => 'Temporary Redirect',
54
+ 308 => 'Permanent Redirect',
55
+ 400 => 'Bad Request',
56
+ 401 => 'Unauthorized',
57
+ 402 => 'Payment Required',
58
+ 403 => 'Forbidden',
59
+ 404 => 'Not Found',
60
+ 405 => 'Method Not Allowed',
61
+ 406 => 'Not Acceptable',
62
+ 407 => 'Proxy Authentication Required',
63
+ 408 => 'Request Timeout',
64
+ 409 => 'Conflict',
65
+ 410 => 'Gone',
66
+ 411 => 'Length Required',
67
+ 412 => 'Precondition Failed',
68
+ 413 => 'Request Entity Too Large',
69
+ 414 => 'Request-URI Too Long',
70
+ 415 => 'Unsupported Media Type',
71
+ 416 => 'Requested Range Not Satisfiable',
72
+ 417 => 'Expectation Failed',
73
+ 422 => 'Unprocessable Entity',
74
+ 423 => 'Locked',
75
+ 424 => 'Failed Dependency',
76
+ 425 => 'Reserved for WebDAV advanced collections expired proposal',
77
+ 426 => 'Upgrade Required',
78
+ 427 => 'Unassigned',
79
+ 428 => 'Precondition Required',
80
+ 429 => 'Too Many Requests',
81
+ 430 => 'Unassigned',
82
+ 431 => 'Request Header Fields Too Large',
83
+ 500 => 'Internal Server Error',
84
+ 501 => 'Not Implemented',
85
+ 502 => 'Bad Gateway',
86
+ 503 => 'Service Unavailable',
87
+ 504 => 'Gateway Timeout',
88
+ 505 => 'HTTP Version Not Supported',
89
+ 506 => 'Variant Also Negotiates (Experimental)',
90
+ 507 => 'Insufficient Storage',
91
+ 508 => 'Loop Detected',
92
+ 509 => 'Unassigned',
93
+ 510 => 'Not Extended',
94
+ 511 => 'Network Authentication Required'
95
+ }
96
+ end
@@ -0,0 +1,12 @@
1
+ require 'logger'
2
+
3
+ module Miniserver
4
+ class Logger < Logger
5
+ def initialize(*args)
6
+ super
7
+ @formatter = Proc.new do |severity, timestamp, progname, msg|
8
+ "#{String === msg ? msg : msg.inspect}\n"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,30 @@
1
+ module Miniserver
2
+ class Request
3
+ attr_accessor :headers
4
+ attr_accessor :body
5
+ attr_reader :request_path
6
+ attr_reader :http_method
7
+ attr_reader :query_string
8
+ attr_reader :keep_alive
9
+ attr_reader :remote_addr
10
+ attr_reader :server_name
11
+ attr_reader :server_port
12
+ attr_reader :request_url
13
+
14
+ def initialize
15
+ @body = String.new
16
+ @headers = Hash.new
17
+ end
18
+
19
+ def parse_header(parser, socket)
20
+ @request_url = parser.request_url
21
+ @query_string = parser.query_string
22
+ @request_path = parser.request_path
23
+ @http_method = parser.http_method
24
+ @keep_alive = parser.keep_alive?
25
+ @remote_addr = Socket.unpack_sockaddr_in(socket.get_peername)[1]
26
+ @server_name, @server_port = @headers[HOST].split(COLON)
27
+ @server_port ||= PORT_80
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,11 @@
1
+ module Miniserver
2
+ class Response
3
+ attr_reader :status, :headers, :body
4
+
5
+ def parse(status, headers, body)
6
+ @status = status
7
+ @headers = headers
8
+ @body = body
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,64 @@
1
+ module Miniserver
2
+ class Runner
3
+ attr_reader :app, :options
4
+
5
+ def initialize(options)
6
+ @options = options
7
+ end
8
+
9
+ def status
10
+ status = if File.exist?(options[:pid])
11
+ pid = File.open(options[:pid], 'r').read.to_i
12
+
13
+ if Process.running?(pid)
14
+ :Started
15
+ else
16
+ :Stopped
17
+ end
18
+ else
19
+ :Stopped
20
+ end
21
+
22
+ puts status
23
+ end
24
+
25
+ def start
26
+ if File.exist?(options[:pid])
27
+ pid = File.open(options[:pid], 'r').read.to_i
28
+
29
+ if Process.running?(pid)
30
+ raise "Miniserver has started in pid #{pid}."
31
+ else
32
+ File.delete(options[:pid])
33
+ end
34
+ end
35
+
36
+ require 'rack/builder'
37
+
38
+ ENV["RACK_ENV"] = options[:environment]
39
+
40
+ @app = Rack::Builder.new_from_string(File.read(options[:rackup]))
41
+
42
+ Server.new(app, options).start
43
+ end
44
+
45
+ def stop
46
+ if File.exist?(options[:pid])
47
+ pid = File.open(options[:pid], 'r').read.to_i
48
+ Process.kill(:INT, pid)
49
+ File.delete(options[:pid])
50
+ else
51
+ raise 'Miniserver is not running.'
52
+ end
53
+ end
54
+
55
+ def restart
56
+ if File.exist?(options[:pid])
57
+ pid = File.open(options[:pid], 'r').read.to_i
58
+ Process.kill(:HUP, pid)
59
+ else
60
+ raise 'Miniserver is not running.'
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,65 @@
1
+ require 'eventmachine'
2
+ require 'miniserver/connection'
3
+ require 'miniserver/logger'
4
+ require 'fileutils'
5
+
6
+ module Miniserver
7
+ class Server
8
+ attr_reader :app, :options, :script
9
+
10
+ def initialize(app, options={})
11
+ @app = app
12
+ @options = options
13
+ @script = $PROGRAM_NAME
14
+
15
+ FileUtils.mkdir_p(File.dirname(options[:log]))
16
+ Miniserver.logger = Logger.new(options[:log])
17
+ end
18
+
19
+ def start
20
+ Miniserver.logger.info "=> #{Time.now.asctime}"
21
+ Miniserver.logger.info "=> Starting Miniserver #{Miniserver::VERSION}"
22
+ Miniserver.logger.info "=> Listening on #{options[:host]}:#{options[:port]}"
23
+
24
+ if options[:daemonize]
25
+ daemonize_app
26
+ else
27
+ puts "=> Miniserver #{Miniserver::VERSION}"
28
+ puts "=> Listening on #{options[:host]}:#{options[:port]}"
29
+ puts "=> CTRL+C to stop"
30
+ end
31
+
32
+ trap(:INT) { stop }
33
+ trap(:TERM) { stop }
34
+ trap(:HUP) { restart }
35
+
36
+ EM.run do
37
+ EM.start_server(options[:host], options[:port], Connection) do |connection|
38
+ connection.app = app
39
+ end
40
+ end
41
+ end
42
+
43
+ def daemonize_app
44
+ Process.daemon(true)
45
+
46
+ $0 = "Miniserver #{Miniserver::VERSION} (#{options[:host]}:#{options[:port]})"
47
+
48
+ FileUtils.mkdir_p(File.dirname(options[:pid]))
49
+
50
+ File.open(options[:pid], "w") do |f|
51
+ f.puts(Process.pid)
52
+ end
53
+ end
54
+
55
+ def stop
56
+ EM.stop
57
+ end
58
+
59
+ def restart
60
+ stop
61
+
62
+ Command.restart(script, options)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,3 @@
1
+ module Miniserver
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,93 @@
1
+ require 'rack/handler'
2
+ require 'stringio'
3
+
4
+ module Rack
5
+ module Handler
6
+ class Miniserver
7
+ RACK_ERRORS = "rack.errors"
8
+ RACK_INPUT = "rack.input"
9
+ RACK_VERSION = 'rack.version'
10
+ RACK_MULTITHREAD = 'rack.multithread'
11
+ RACK_MULTIPROCESS = 'rack.multiprocess'
12
+ RACK_RUN_ONCE = 'rack.run_once'
13
+ RACK_URL_SCHEME = 'rack.url_scheme'
14
+
15
+ DEFAULT_OPTIONS = {
16
+ daemonize: false,
17
+ Host: '0.0.0.0',
18
+ Port: 8080,
19
+ rackup: ::File.expand_path('config.ru'),
20
+ log: ::File.expand_path('log/miniserver.log'),
21
+ environment: 'development'
22
+ }
23
+
24
+ class << self
25
+ def run(app, options={})
26
+ options = DEFAULT_OPTIONS.merge(options)
27
+
28
+ options[:host] = options.delete(:Host)
29
+ options[:port] = options.delete(:Port)
30
+ options[:daemonize] = false
31
+
32
+ server = ::Miniserver::Server.new(app, options)
33
+
34
+ yield(server) if block_given?
35
+
36
+ server.start
37
+ end
38
+
39
+ def valid_options
40
+ {
41
+ "Host=HOST" => "Hostname to listen on (default: 0.0.0.0)",
42
+ "Port=PORT" => "Port to listen on (default: 8080)",
43
+ }
44
+ end
45
+ end
46
+
47
+ def initialize(app)
48
+ @app = app
49
+ end
50
+
51
+ def process(request, response)
52
+ env = Hash.new
53
+
54
+ request.headers.each_pair do |name, value|
55
+ name = "#{::Miniserver::HTTP_PREFIX}#{name.upcase.tr(::Miniserver::MINUS, ::Miniserver::UNDERLINE)}"
56
+ env[name] = value
57
+ end
58
+
59
+ %w(CONTENT_TYPE CONTENT_LENGTH).each do |name|
60
+ env[name] = env.delete("HTTP_#{name}") if env["HTTP_#{name}"]
61
+ end
62
+
63
+ uri = URI(request.request_url)
64
+
65
+ env[::Miniserver::REQUEST_METHOD] = request.http_method
66
+ env[::Miniserver::REMOTE_ADDR] = request.remote_addr
67
+ env[::Miniserver::SERVER_NAME] = request.server_name
68
+ env[::Miniserver::SERVER_PORT] = request.server_port
69
+ env[::Miniserver::QUERY_STRING] = request.query_string
70
+ env[::Miniserver::REQUEST_PATH] = uri.path
71
+ env[::Miniserver::PATH_INFO] = uri.path
72
+ env[::Miniserver::SCRIPT_NAME] = ::Miniserver::EMPTY_STRING
73
+ env[::Miniserver::FRAGMENT] = uri.fragment || ::Miniserver::EMPTY_STRING
74
+
75
+ env[RACK_ERRORS] = STDERR
76
+ env[RACK_INPUT] = StringIO.new(request.body)
77
+ env[RACK_VERSION] = Rack::VERSION
78
+ env[RACK_MULTITHREAD] = false
79
+ env[RACK_MULTIPROCESS] = false
80
+ env[RACK_RUN_ONCE] = false
81
+ env[RACK_URL_SCHEME] = ::Miniserver::HTTP
82
+
83
+ begin
84
+ response.parse(*@app.call(env))
85
+ ensure
86
+ request.body.clear
87
+ end
88
+ end
89
+ end
90
+
91
+ register :miniserver, Miniserver
92
+ end
93
+ end
@@ -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 'miniserver/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "miniserver"
8
+ spec.version = Miniserver::VERSION
9
+ spec.authors = ["zhouguangming"]
10
+ spec.email = ["zhouguangming1989@gmail.com"]
11
+ spec.description = %q{Miniserver is a simple fast HTTP 1.1 server for Ruby/Rack applications.}
12
+ spec.summary = %q{Miniserver is a simple fast HTTP 1.1 server for Ruby/Rack applications.}
13
+ spec.homepage = "https://github.com/zhouguangming/miniserver"
14
+ spec.license = "MIT"
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_dependency 'http_parser.rb'
24
+ spec.add_dependency 'eventmachine'
25
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: miniserver
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - zhouguangming
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-11-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: http_parser.rb
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: eventmachine
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Miniserver is a simple fast HTTP 1.1 server for Ruby/Rack applications.
70
+ email:
71
+ - zhouguangming1989@gmail.com
72
+ executables:
73
+ - miniserver
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .gitignore
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - bin/miniserver
83
+ - lib/miniserver.rb
84
+ - lib/miniserver/command.rb
85
+ - lib/miniserver/connection.rb
86
+ - lib/miniserver/const.rb
87
+ - lib/miniserver/logger.rb
88
+ - lib/miniserver/request.rb
89
+ - lib/miniserver/response.rb
90
+ - lib/miniserver/runner.rb
91
+ - lib/miniserver/server.rb
92
+ - lib/miniserver/version.rb
93
+ - lib/rack/handler/miniserver.rb
94
+ - miniserver.gemspec
95
+ homepage: https://github.com/zhouguangming/miniserver
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.0.3
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Miniserver is a simple fast HTTP 1.1 server for Ruby/Rack applications.
119
+ test_files: []