simple-httpd 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e3943911c33876d60f023ec58fab2d875eb9e2b0b23c3649f0d7601e8b1f304c
4
+ data.tar.gz: 7ff0ef4341bb717ed1b6fafc7339335aa738a660638df64d1b5eba5ec6174a2c
5
+ SHA512:
6
+ metadata.gz: ca193f4c704a1d94f2cc193f953c259c97164dcc28eae9a75347b72e18b31447cf1222df51c36109c129827e09e65e9ad0d3c098fb63a41597052c86cbf08277
7
+ data.tar.gz: 27045e31517c41301ad6ce9e43c8bad59b90e4e099b64c115a9061ba6eed6b28d238e1a117a65efe85fa3fd0d1d3131a369ffd98cf1beff4b98ceabf94854aa6
@@ -0,0 +1,12 @@
1
+ coverage
2
+ rdoc
3
+ pkg
4
+ log/test.log
5
+ .rspec.data
6
+ Gemfile.lock
7
+ .rake_t_cache
8
+ .rspec.status
9
+ .DS_Store
10
+ tmp
11
+ .byebug_history
12
+ .bundle/config
@@ -0,0 +1,80 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
3
+ Exclude:
4
+ - 'spec/**/*'
5
+ - 'test/**/*'
6
+ - 'bin/**/*'
7
+ - 'tasks/release.rake'
8
+ - '*.gemspec'
9
+ - 'Gemfile'
10
+ - 'Rakefile'
11
+
12
+ Metrics/LineLength:
13
+ Max: 140
14
+
15
+ Metrics/MethodLength:
16
+ Max: 20
17
+
18
+ Style/SpecialGlobalVars:
19
+ Enabled: false
20
+
21
+ Style/StringLiterals:
22
+ EnforcedStyle: double_quotes
23
+ ConsistentQuotesInMultiline: false
24
+
25
+ Style/ClassAndModuleChildren:
26
+ Enabled: false
27
+
28
+ Style/ModuleFunction:
29
+ Enabled: false
30
+
31
+ Style/FrozenStringLiteralComment:
32
+ Enabled: false
33
+
34
+ Style/Documentation:
35
+ Enabled: false
36
+
37
+ Style/MutableConstant:
38
+ Enabled: false
39
+
40
+ Style/FormatStringToken:
41
+ Enabled: false
42
+
43
+ Style/Lambda:
44
+ Enabled: false
45
+
46
+ Style/SymbolArray:
47
+ Enabled: false
48
+
49
+ Style/FormatString:
50
+ Enabled: false
51
+
52
+ Style/PercentLiteralDelimiters:
53
+ Enabled: false
54
+
55
+ Lint/MissingCopEnableDirective:
56
+ Enabled: false
57
+
58
+ Style/NumericPredicate:
59
+ Enabled: false
60
+
61
+ Style/RegexpLiteral:
62
+ Enabled: false
63
+
64
+ Style/ClassVars:
65
+ Enabled: false
66
+
67
+ Style/ConditionalAssignment:
68
+ Enabled: false
69
+
70
+ Style/IfUnlessModifier:
71
+ Enabled: false
72
+
73
+ Style/PerlBackrefs:
74
+ Enabled: false
75
+
76
+ Style/TrailingUnderscoreVariable:
77
+ Enabled: false
78
+
79
+ Style/StderrPuts:
80
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'byebug'
4
+ # Specify your gem's dependencies in {gemname}.gemspec
5
+ gemspec
@@ -0,0 +1,3 @@
1
+ # simple-httpd
2
+
3
+ [TODO]
@@ -0,0 +1 @@
1
+ Dir.glob("tasks/*.rake").each { |r| import r }
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'bundle' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "rubygems"
12
+
13
+ m = Module.new do
14
+ module_function
15
+
16
+ def invoked_as_script?
17
+ File.expand_path($0) == File.expand_path(__FILE__)
18
+ end
19
+
20
+ def env_var_version
21
+ ENV["BUNDLER_VERSION"]
22
+ end
23
+
24
+ def cli_arg_version
25
+ return unless invoked_as_script? # don't want to hijack other binstubs
26
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27
+ bundler_version = nil
28
+ update_index = nil
29
+ ARGV.each_with_index do |a, i|
30
+ if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31
+ bundler_version = a
32
+ end
33
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34
+ bundler_version = $1 || ">= 0.a"
35
+ update_index = i
36
+ end
37
+ bundler_version
38
+ end
39
+
40
+ def gemfile
41
+ gemfile = ENV["BUNDLE_GEMFILE"]
42
+ return gemfile if gemfile && !gemfile.empty?
43
+
44
+ File.expand_path("../../Gemfile", __FILE__)
45
+ end
46
+
47
+ def lockfile
48
+ lockfile =
49
+ case File.basename(gemfile)
50
+ when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
51
+ else "#{gemfile}.lock"
52
+ end
53
+ File.expand_path(lockfile)
54
+ end
55
+
56
+ def lockfile_version
57
+ return unless File.file?(lockfile)
58
+ lockfile_contents = File.read(lockfile)
59
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60
+ Regexp.last_match(1)
61
+ end
62
+
63
+ def bundler_version
64
+ @bundler_version ||= begin
65
+ env_var_version || cli_arg_version ||
66
+ lockfile_version || "#{Gem::Requirement.default}.a"
67
+ end
68
+ end
69
+
70
+ def load_bundler!
71
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
72
+
73
+ # must dup string for RG < 1.8 compatibility
74
+ activate_bundler(bundler_version.dup)
75
+ end
76
+
77
+ def activate_bundler(bundler_version)
78
+ if Gem::Version.correct?(bundler_version) && Gem::Version.new(bundler_version).release < Gem::Version.new("2.0")
79
+ bundler_version = "< 2"
80
+ end
81
+ gem_error = activation_error_handling do
82
+ gem "bundler", bundler_version
83
+ end
84
+ return if gem_error.nil?
85
+ require_error = activation_error_handling do
86
+ require "bundler/version"
87
+ end
88
+ return if require_error.nil? && Gem::Requirement.new(bundler_version).satisfied_by?(Gem::Version.new(Bundler::VERSION))
89
+ warn "Activating bundler (#{bundler_version}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_version}'`"
90
+ exit 42
91
+ end
92
+
93
+ def activation_error_handling
94
+ yield
95
+ nil
96
+ rescue StandardError, LoadError => e
97
+ e
98
+ end
99
+ end
100
+
101
+ m.load_bundler!
102
+
103
+ if m.invoked_as_script?
104
+ load Gem.bin_path("bundler", "bundle")
105
+ end
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ Bundler.require
5
+ require "simple-httpd"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rake' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rake", "rake")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rspec' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rspec-core", "rspec")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rubocop' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rubocop", "rubocop")
@@ -0,0 +1,3 @@
1
+ # rubocop:disable Naming/FileName
2
+
3
+ require "simple/httpd"
@@ -0,0 +1,2 @@
1
+ module Simple
2
+ end
@@ -0,0 +1,43 @@
1
+ module Simple
2
+ end
3
+
4
+ module Simple::Httpd
5
+ end
6
+
7
+ require "simple/httpd/version"
8
+ require "simple/httpd/app"
9
+ require "simple/httpd/base_controller"
10
+
11
+ module Simple::Httpd
12
+ extend self
13
+
14
+ def build_rack(base_controller, logger:)
15
+ App.new(base_controller, logger: logger)
16
+ end
17
+
18
+ def listen!(app, environment:, port:)
19
+ expect! port => 80..60_000
20
+
21
+ logger = app.logger
22
+ logger.info "Starting httpd server on http://0.0.0.0:#{port}/"
23
+
24
+ app = Rack::Lint.new(app) if environment != "production"
25
+
26
+ # re/AccessLog: the AccessLog setting points WEBrick's access logging to the
27
+ # NullLogger object.
28
+ #
29
+ # Instead we'll use a combination of Rack::CommonLogger (see Simple::Httpd.app),
30
+ # and sinatra's logger (see Simple::Httpd::BaseController).
31
+ Rack::Server.start app: app,
32
+ Port: port,
33
+ environment: environment,
34
+ Logger: logger,
35
+ AccessLog: [[NullLogger, ""]]
36
+ end
37
+
38
+ module NullLogger # :nodoc:
39
+ extend self
40
+
41
+ def <<(msg); end
42
+ end
43
+ end
@@ -0,0 +1,84 @@
1
+ class Simple::Httpd::App
2
+ end
3
+
4
+ require_relative "app/file_server"
5
+
6
+ # The Simple::Httpd::App implements a Rack compatible app, which serves
7
+ # HTTP requests via a set of controllers inherited from a base controller
8
+ # class.
9
+ #
10
+ # The individual routes are determined from the controller class names:
11
+ # assuming we have a controller class Foo::Bar::BazController inheriting
12
+ # from Foo::BaseController will serve the /bar/baz routes.
13
+ #
14
+ # Additional static routes can be configured by calling "mount_directory!!"
15
+ # on the app object.
16
+ class Simple::Httpd::App
17
+ extend Forwardable
18
+ delegate call: :@app
19
+
20
+ attr_reader :logger
21
+
22
+ #
23
+ # Builds a App object
24
+ def initialize(base_controller, logger:)
25
+ raise unless logger
26
+
27
+ @base_controller = base_controller
28
+ @logger = logger
29
+ @file_mounts = []
30
+
31
+ @app = Rack::URLMap.new(controllers_url_map)
32
+ end
33
+
34
+ def mount_directory!(url:, path:)
35
+ @logger.debug "#{path}: mount directory #{path}"
36
+ @app = FileServer.new(@app, url_prefix: url, root: path)
37
+ end
38
+
39
+ private
40
+
41
+ # Find all controllers inheriting off base_controller and return
42
+ # a URL map, based on the names of the controllers.
43
+ def controllers_url_map
44
+ controller_by_mountpoint = ObjectSpace
45
+ .each_object(Class)
46
+ .select { |klass| klass < @base_controller }
47
+ .map { |controller| [mountpoint(controller), controller] }
48
+ .reject { |mountpoint, _controller| mountpoint.nil? }
49
+
50
+ controller_by_mountpoint
51
+ .sort_by { |path, _controller| path }
52
+ .each { |path, controller| logger.debug "#{path}: mount #{controller}" }
53
+
54
+ Hash[controller_by_mountpoint]
55
+ end
56
+
57
+ def mountpoint(controller)
58
+ return unless controller.name.end_with?("Controller")
59
+
60
+ relative_controller_name = relative_controller_name(controller)
61
+ return "/" if relative_controller_name == "RootController"
62
+
63
+ "/" + relative_controller_name.underscore.gsub(/_controller$/, "")
64
+ end
65
+
66
+ # With a controller of Postjob::FooBarController returns FooBarController
67
+ # (depending on the base_controller)
68
+ def relative_controller_name(controller)
69
+ controller_name = controller.name
70
+ if controller_name.start_with?(base_controller_namespace)
71
+ controller_name[base_controller_namespace.length..-1]
72
+ else
73
+ controller_name
74
+ end
75
+ end
76
+
77
+ # With a base_controller of Postjob::BaseController this returns "Postjob"
78
+ def base_controller_namespace
79
+ @base_controller_namespace ||= begin
80
+ base_controller_name = @base_controller.name
81
+ base_controller_name.gsub(/::BaseController$/, "::")
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,19 @@
1
+ class Simple::Httpd::App::FileServer
2
+ # A simple file server middleware
3
+ def initialize(app, url_prefix:, root:)
4
+ @app = app
5
+ @url_prefix = File.join("/", url_prefix, "/")
6
+ @file_server = Rack::File.new(root)
7
+ end
8
+
9
+ def call(env)
10
+ request_path = env["PATH_INFO"]
11
+ if request_path.start_with?(@url_prefix)
12
+ file_path = request_path[@url_prefix.length..-1]
13
+ env["PATH_INFO"] = file_path
14
+ @file_server.call(env)
15
+ else
16
+ @app.call(env)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ # Note that all components in base_controller/*.rb are loaded automatically, from
2
+ # config/routes.rb, **after** this file is loaded. See the end of this file.
3
+
4
+ require "sinatra/base"
5
+
6
+ class Simple::Httpd::BaseController < Sinatra::Base
7
+ set :logging, true
8
+
9
+ # --- Sinatra::Reloader -----------------------------------------------------
10
+
11
+ # Note that Sinatra::Reloader is less thorough than, say, shotgun or the
12
+ # Rails development mode, but on the other hand it is much faster, and
13
+ # probably useful 90% of the time.
14
+ configure :development do
15
+ require "sinatra/reloader"
16
+ register Sinatra::Reloader
17
+ end
18
+ end
19
+
20
+ Dir.chdir __dir__ do
21
+ Dir.glob("base_controller/*.rb").sort.each do |file|
22
+ require_relative file
23
+ end
24
+ end
@@ -0,0 +1,37 @@
1
+ require "cgi"
2
+
3
+ class Simple::Httpd::BaseController
4
+ helpers do
5
+ def base_url
6
+ @base_url ||= request.base_url
7
+ end
8
+
9
+ def full_url(path, opts = {})
10
+ build_url(base_url, path, opts)
11
+ end
12
+
13
+ def url(path, opts = {})
14
+ build_url(path, opts)
15
+ end
16
+
17
+ def build_url(base, *args)
18
+ option_args, string_args = args.partition { |arg| arg.is_a?(Hash) }
19
+ options = option_args.inject({}) { |hsh, option| hsh.update option }
20
+
21
+ url = File.join([base] + string_args)
22
+
23
+ query = build_url_query(options)
24
+ url += url.index("?") ? "&#{query}" : "?#{query}" if query
25
+ url
26
+ end
27
+
28
+ private
29
+
30
+ def build_url_query(params)
31
+ params = params.reject { |_k, v| v.nil? || v.empty? }
32
+ return nil if params.empty?
33
+
34
+ params.map { |k, value| "#{k}=#{escape(value.to_s)}" }.join("&")
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,21 @@
1
+ class Simple::Httpd::BaseController
2
+ CORS_HEADERS = {
3
+ "access-control-allow-credentials" => "true",
4
+ "access-control-allow-headers" => "Origin,X-Requested-With,Content-Type,Accept,Session-Id",
5
+ "access-control-allow-methods" => "*",
6
+ "access-control-allow-origin" => "*",
7
+ # "access-control-expose-headers" => "X-Total-Entries,X-Total-Pages,X-Page,X-Per-Page",
8
+ # "access-control-max-age" => "-1",
9
+ "access-control-max-age" => "600",
10
+ "access-control-request-headers" => "Content-Type",
11
+ "access-control-request-method" => "GET,POST,PATCH,PUT,DELETE,OPTIONS"
12
+ }
13
+
14
+ options "*" do
15
+ 200
16
+ end
17
+
18
+ after do
19
+ headers CORS_HEADERS
20
+ end
21
+ end
@@ -0,0 +1,8 @@
1
+ class Simple::Httpd::BaseController
2
+ helpers do
3
+ def debug(data)
4
+ content_type "text/plain"
5
+ halt data.pretty_inspect
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,20 @@
1
+ require "erb"
2
+
3
+ class Simple::Httpd::BaseController
4
+ # A simple ERB renderer
5
+ helpers do
6
+ module ERB::Helpers
7
+ def self.json(data)
8
+ JSON.pretty_generate(data)
9
+ end
10
+ end
11
+
12
+ def erb(template, data)
13
+ content_type "text/html"
14
+
15
+ erb = template.is_a?(ERB) ? template : ERB.new(template)
16
+ data[:helpers] = ERB::Helpers
17
+ erb.result_with_hash(data)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,147 @@
1
+ require_relative "./json"
2
+
3
+ class Simple::Httpd::BaseController
4
+ set :show_exceptions, false
5
+ set :dump_errors, false
6
+ set :raise_errors, false
7
+
8
+ set :raise_errors, true if ENV["RACK_ENV"] == "test"
9
+
10
+ private
11
+
12
+ def stringify_hash(hsh)
13
+ return unless hsh
14
+
15
+ hsh.inject({}) do |r, (k, v)|
16
+ k = k.to_s if k.is_a?(Symbol)
17
+ r.update k => v
18
+ end
19
+ end
20
+
21
+ public
22
+
23
+ def render_error(exc, options)
24
+ expect! options => {
25
+ status: Integer,
26
+ title: String,
27
+ description: [String, nil]
28
+ }
29
+
30
+ status options[:status]
31
+
32
+ options = stringify_hash(options)
33
+ options["description"] ||= options["title"]
34
+ options["@type"] = error_type(exc)
35
+ options["@now"] = Time.now.to_f
36
+
37
+ json options
38
+ end
39
+
40
+ if defined?(Expectation)
41
+
42
+ error(Expectation::Matcher::Mismatch) do |exc|
43
+ render_error exc, status: 400,
44
+ title: "Invalid input",
45
+ description: error_description(exc)
46
+ end
47
+
48
+ end
49
+
50
+ # class InvalidRequest < RuntimeError
51
+ # end
52
+ #
53
+ # error(InvalidRequest) do |e|
54
+ # render_error e, status: 400,
55
+ # title: "Invalid input",
56
+ # description: error_description(e)
57
+ # end
58
+
59
+ error(ArgumentError) do |exc|
60
+ STDERR.puts "Caught ArgumentError: #{exc}, from\n\t#{exc.backtrace[0, 5].join("\n\t")}"
61
+
62
+ render_error exc, status: 422,
63
+ title: "Invalid input #{exc.inspect}",
64
+ description: error_description(exc)
65
+ end
66
+
67
+ # class NotAuthorizedError < RuntimeError
68
+ # end
69
+ #
70
+ # error(NotAuthorizedError) do
71
+ # render_error e, status: 403,
72
+ # title: "Not authorized",
73
+ # description: "You don't have necessary powers to access this page."
74
+ # end
75
+
76
+ # class LoginRequiredError < RuntimeError
77
+ # end
78
+ #
79
+ # error(LoginRequiredError) do
80
+ # render_error e, status: 404,
81
+ # title: "Not found",
82
+ # description: "The server failed to recognize affiliation. Please provide a valid Session-Id."
83
+ # end
84
+
85
+ class NotFoundError < RuntimeError
86
+ end
87
+
88
+ error(NotFoundError) do |exc|
89
+ render_error exc, status: 404,
90
+ title: "Not found",
91
+ description: error_description(exc)
92
+ end
93
+
94
+ error(Errno::ENOENT) do |exc|
95
+ render_error exc, status: 404,
96
+ title: "Not found",
97
+ description: "The requested record was not found."
98
+ end
99
+
100
+ # -- print unspecified errors.
101
+
102
+ error do |exc|
103
+ message = <<~MSG
104
+ === #{exc.class.name} =====================
105
+ #{exc.message.chomp}
106
+
107
+ #{filtered_backtrace(exc)}
108
+ ==================================================================
109
+ MSG
110
+
111
+ STDERR.puts message
112
+ status 500
113
+ "\n#{message}\n"
114
+ end
115
+
116
+ private
117
+
118
+ def error_type(exc)
119
+ "error/#{exc.class.name.underscore}".gsub(/\/error$/, "")
120
+ end
121
+
122
+ def error_description(exc)
123
+ exc.message
124
+ # "#{exc.message}, from #{exc.backtrace.join("\n\t")}"
125
+ end
126
+
127
+ def remove_wd(str)
128
+ @wd ||= Dir.getwd
129
+
130
+ if str.start_with?(@wd)
131
+ str[(@wd.length + 1)..-1]
132
+ else
133
+ str
134
+ end
135
+ end
136
+
137
+ def filtered_backtrace(exc, count: 20)
138
+ lines = exc.backtrace.map do |line|
139
+ next "...\n" if line =~ /\.rvm\b/
140
+
141
+ "#{remove_wd(line)}\n"
142
+ end
143
+
144
+ s = lines[0, count].join("")
145
+ s.gsub(/(\.\.\.\n)+/, " ... (lines removed) ...\n")
146
+ end
147
+ end
@@ -0,0 +1,46 @@
1
+ class Simple::Httpd::BaseController
2
+ def json(result)
3
+ content_type :json
4
+ generate_json(result)
5
+ end
6
+
7
+ private
8
+
9
+ def generate_json(result)
10
+ JSON.generate(result)
11
+ end
12
+
13
+ configure :development, :test do
14
+ begin
15
+ @@neatjson = true
16
+ require "neatjson"
17
+ rescue LoadError
18
+ @@neatjson = false
19
+ end
20
+
21
+ def generate_json(result)
22
+ if @@neatjson
23
+ JSON.neat_generate(result)
24
+ else
25
+ JSON.pretty_generate(result)
26
+ end
27
+ end
28
+ end
29
+
30
+ public
31
+
32
+ def parsed_json_body
33
+ @parsed_json_body ||= parse_json_body
34
+ end
35
+
36
+ private
37
+
38
+ def parse_json_body
39
+ unless request.content_type =~ /application\/json/
40
+ raise "Cannot parse non-JSON request body w/content_type #{request.content_type.inspect}"
41
+ end
42
+
43
+ request.body.rewind
44
+ JSON.parse(request.body.read)
45
+ end
46
+ end
@@ -0,0 +1,11 @@
1
+ # Simple::SQL connection handling
2
+ class Simple::Httpd::BaseController
3
+ before do
4
+ @processing_started_at = Time.now
5
+ end
6
+
7
+ after do
8
+ runtime = Time.now - @processing_started_at
9
+ headers "X-Processing" => runtime.to_s
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ module Simple::Httpd
2
+ module GemHelper
3
+ extend self
4
+
5
+ def version(name)
6
+ spec = Gem.loaded_specs[name]
7
+ version = spec ? spec.version.to_s : "0.0.0"
8
+ version += "+unreleased" if !spec || unreleased?(spec)
9
+ version
10
+ end
11
+
12
+ private
13
+
14
+ def unreleased?(spec)
15
+ return false unless defined?(Bundler::Source::Gemspec)
16
+ return true if spec.source.is_a?(::Bundler::Source::Gemspec)
17
+ return true if spec.source.is_a?(::Bundler::Source::Path)
18
+
19
+ false
20
+ end
21
+ end
22
+
23
+ VERSION = GemHelper.version "postjob"
24
+ end
File without changes
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+
3
+ cloc $(find lib/ -name *rb) | grep -E 'Language|Ruby' | sed 's-Language- -'
4
+ printf "\n"
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ watchr lib,spec rspec $@
@@ -0,0 +1,41 @@
1
+ # This file is part of the sinatra-sse ruby gem.
2
+ #
3
+ # Copyright (c) 2016, 2017 @radiospiel, mediapeers Gem
4
+ # Distributed under the terms of the modified BSD license, see LICENSE.BSD
5
+
6
+ lib = File.expand_path('../lib', __FILE__)
7
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
8
+
9
+ Gem::Specification.new do |gem|
10
+ gem.name = "simple-httpd"
11
+ gem.version = File.read("VERSION")
12
+
13
+ gem.authors = [ "radiospiel" ]
14
+ gem.email = "eno@radiospiel.org"
15
+ gem.homepage = "http://github.com/radiospiel/simple-httpd"
16
+ gem.summary = "Super-simple HTTPD server"
17
+
18
+ gem.description = "Super-simple HTTPD server - sinatra w/gimmiks"
19
+
20
+ gem.files = `git ls-files`.split($/)
21
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
22
+ gem.require_paths = %w(lib)
23
+
24
+ # executables are used for development purposes only
25
+ gem.executables = []
26
+
27
+ gem.required_ruby_version = '~> 2.5'
28
+
29
+ # -- dependencies for postjob httpd
30
+ gem.add_runtime_dependency "neatjson", "~> 0.8.4"
31
+ gem.add_runtime_dependency "sinatra", "~> 2"
32
+ gem.add_runtime_dependency "sinatra-reloader", "~> 1"
33
+
34
+ # development gems
35
+ gem.add_development_dependency "rspec-httpd", "~> 0.0.14"
36
+ gem.add_development_dependency 'rake', '~> 11'
37
+ gem.add_development_dependency 'rspec', '~> 3.7'
38
+ gem.add_development_dependency 'rubocop', '~> 0.61.1'
39
+ gem.add_development_dependency 'simplecov', '~> 0'
40
+ gem.add_development_dependency 'awesome_print', '~> 0'
41
+ end
@@ -0,0 +1,10 @@
1
+ require "spec_helper"
2
+
3
+ describe Simple::Httpd do
4
+ describe "VERSION" do
5
+ it "defines a version string" do
6
+ # Note: this allows for 0.12.34beta
7
+ #expect(Simple::Httpd::VERSION).to match(/^\d+\.\d+\.\d+/)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,30 @@
1
+ %w(auth authentication authorization).each do |library_name|
2
+ path = File.expand_path("../../#{library_name}/lib", __FILE__)
3
+ $LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
4
+ end
5
+
6
+ ENV["RACK_ENV"] = "test"
7
+ ENV["RAILS_ENV"] = "test"
8
+
9
+ require "byebug"
10
+ require "rspec"
11
+ require "awesome_print"
12
+ Dir.glob("./spec/support/**/*.rb").sort.each { |path| load path }
13
+
14
+ require "simple/httpd"
15
+
16
+ RSpec.configure do |config|
17
+ config.run_all_when_everything_filtered = true
18
+ config.filter_run focus: (ENV["CI"] != "true")
19
+ config.expect_with(:rspec) { |c| c.syntax = :expect }
20
+ config.order = "random"
21
+ config.example_status_persistence_file_path = ".rspec.data"
22
+
23
+ config.backtrace_exclusion_patterns << /spec\/support/
24
+ config.backtrace_exclusion_patterns << /spec_helper/
25
+ config.backtrace_exclusion_patterns << /database_cleaner/
26
+
27
+ # config.around(:each) do |example|
28
+ # example.run
29
+ # end
30
+ end
@@ -0,0 +1,22 @@
1
+ require "simplecov"
2
+
3
+ # make sure multiple runs result in multiple result set. SimpleCov will take
4
+ # care of merging these results automatically.
5
+ SimpleCov.command_name "test:#{ENV['USE_ACTIVE_RECORD']}"
6
+
7
+ USE_ACTIVE_RECORD = ENV["USE_ACTIVE_RECORD"] == "1"
8
+
9
+ SimpleCov.start do
10
+ # return true to remove src from coverage
11
+ add_filter do |src|
12
+ next true if src.filename =~ /\/spec\//
13
+ next true if src.filename =~ /\/immutable\.rb/
14
+
15
+ next true if USE_ACTIVE_RECORD && src.filename =~ /\/sql\/connection\/raw_connection\.rb/
16
+ next true if !USE_ACTIVE_RECORD && src.filename =~ /\/sql\/connection\/active_record_connection\.rb/
17
+
18
+ false
19
+ end
20
+
21
+ minimum_coverage 90
22
+ end
@@ -0,0 +1,104 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+
4
+ GEM_ROOT = File.expand_path('../../', __FILE__)
5
+ GEM_SPEC, more = Dir.glob("*.gemspec")
6
+ raise "Cannot determine gemspec" if more || !GEM_SPEC
7
+
8
+ VERSION_FILE_PATH = 'VERSION'
9
+
10
+ class VersionNumberTracker
11
+ class << self
12
+ def update_version_file(new_version_number)
13
+ File.open(VERSION_FILE_PATH, 'w') { |file| file.puts new_version_number }
14
+ new_version_number
15
+ end
16
+
17
+ def auto_version_bump
18
+ old_version_number = File.read("VERSION")
19
+ old = old_version_number.split('.')
20
+ current = old[0..-2] << old[-1].next
21
+ new_version_number = current.join('.')
22
+
23
+ update_version_file(new_version_number)
24
+ end
25
+
26
+ def manual_version_bump
27
+ update_version_file(ENV['VERSION'])
28
+ end
29
+
30
+ def update_version_number
31
+ @version = ENV['VERSION'] ? manual_version_bump : auto_version_bump
32
+ end
33
+
34
+ attr_reader :version
35
+ end
36
+ end
37
+
38
+ namespace :release do
39
+ task :version do
40
+ VersionNumberTracker.update_version_number
41
+ end
42
+
43
+ task :build do
44
+ Dir.chdir(GEM_ROOT) do
45
+ sh("gem build #{GEM_SPEC}")
46
+ end
47
+ end
48
+
49
+ desc "Commit changes"
50
+ task :commit do
51
+ Dir.chdir(GEM_ROOT) do
52
+ version = VersionNumberTracker.version
53
+ sh("git add #{VERSION_FILE_PATH}")
54
+ sh("git commit -m \"bump to v#{version}\"")
55
+ sh("git tag -a v#{version} -m \"Tag\"")
56
+ end
57
+ end
58
+
59
+ desc "Push code and tags"
60
+ task :push do
61
+ sh("git push origin #{$TARGET_BRANCH}")
62
+ sh('git push --tags')
63
+ end
64
+
65
+ desc "Cleanup"
66
+ task :clean do
67
+ Dir.glob(File.join(GEM_ROOT, '*.gem')).each { |f| FileUtils.rm_rf(f) }
68
+ end
69
+
70
+ desc "Push Gem to gemfury"
71
+ task :publish do
72
+ Dir.chdir(GEM_ROOT) { sh("gem push #{Dir.glob('*.gem').first}") }
73
+ end
74
+
75
+ task :target_master do
76
+ $TARGET_BRANCH = 'master'
77
+ end
78
+
79
+ task :target_stable do
80
+ $TARGET_BRANCH = 'stable'
81
+ end
82
+
83
+ task :checkout do
84
+ sh "git status --untracked-files=no --porcelain > /dev/null || (echo '*** working dir not clean' && false)"
85
+ sh "git checkout #{$TARGET_BRANCH}"
86
+ sh "git pull"
87
+ end
88
+
89
+ task default: [
90
+ 'checkout',
91
+ 'version',
92
+ 'clean',
93
+ 'build',
94
+ 'commit',
95
+ 'push',
96
+ 'publish'
97
+ ]
98
+
99
+ task master: %w(target_master default)
100
+ task stable: %w(target_stable default)
101
+ end
102
+
103
+ desc "Clean, build, commit and push"
104
+ task release: 'release:master'
metadata ADDED
@@ -0,0 +1,204 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple-httpd
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - radiospiel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-06-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: neatjson
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.4
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.4
27
+ - !ruby/object:Gem::Dependency
28
+ name: sinatra
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sinatra-reloader
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-httpd
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.14
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.0.14
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '11'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '11'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '3.7'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '3.7'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 0.61.1
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 0.61.1
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: awesome_print
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Super-simple HTTPD server - sinatra w/gimmiks
140
+ email: eno@radiospiel.org
141
+ executables: []
142
+ extensions: []
143
+ extra_rdoc_files: []
144
+ files:
145
+ - ".gitignore"
146
+ - ".rubocop.yml"
147
+ - Gemfile
148
+ - README.md
149
+ - Rakefile
150
+ - VERSION
151
+ - bin/bundle
152
+ - bin/console
153
+ - bin/rake
154
+ - bin/rspec
155
+ - bin/rubocop
156
+ - lib/simple-httpd.rb
157
+ - lib/simple.rb
158
+ - lib/simple/httpd.rb
159
+ - lib/simple/httpd/app.rb
160
+ - lib/simple/httpd/app/file_server.rb
161
+ - lib/simple/httpd/base_controller.rb
162
+ - lib/simple/httpd/base_controller/build_url.rb
163
+ - lib/simple/httpd/base_controller/cors.rb
164
+ - lib/simple/httpd/base_controller/debug.rb
165
+ - lib/simple/httpd/base_controller/erb.rb
166
+ - lib/simple/httpd/base_controller/error_handling.rb
167
+ - lib/simple/httpd/base_controller/json.rb
168
+ - lib/simple/httpd/base_controller/x_processing.rb
169
+ - lib/simple/httpd/version.rb
170
+ - log/.gitkeep
171
+ - scripts/stats
172
+ - scripts/watch
173
+ - simple-httpd.gemspec
174
+ - spec/simple/httpd/version_spec.rb
175
+ - spec/spec_helper.rb
176
+ - spec/support/004_simplecov.rb
177
+ - tasks/release.rake
178
+ homepage: http://github.com/radiospiel/simple-httpd
179
+ licenses: []
180
+ metadata: {}
181
+ post_install_message:
182
+ rdoc_options: []
183
+ require_paths:
184
+ - lib
185
+ required_ruby_version: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - "~>"
188
+ - !ruby/object:Gem::Version
189
+ version: '2.5'
190
+ required_rubygems_version: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - ">="
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ requirements: []
196
+ rubyforge_project:
197
+ rubygems_version: 2.7.6
198
+ signing_key:
199
+ specification_version: 4
200
+ summary: Super-simple HTTPD server
201
+ test_files:
202
+ - spec/simple/httpd/version_spec.rb
203
+ - spec/spec_helper.rb
204
+ - spec/support/004_simplecov.rb