waitress-core 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.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +21 -0
  4. data/Rakefile +4 -0
  5. data/bin/waitress +22 -0
  6. data/ext/Thanks.md +1 -0
  7. data/ext/waitress_http11/ext_help.h +15 -0
  8. data/ext/waitress_http11/extconf.rb +6 -0
  9. data/ext/waitress_http11/http11.c +532 -0
  10. data/ext/waitress_http11/http11_parser.c +1216 -0
  11. data/ext/waitress_http11/http11_parser.h +49 -0
  12. data/ext/waitress_http11/http11_parser.java.rl +171 -0
  13. data/ext/waitress_http11/http11_parser.rl +165 -0
  14. data/ext/waitress_http11/http11_parser_common.rl +55 -0
  15. data/ext/waitress_http11/http11_wrb_parser.h +83 -0
  16. data/lib/waitress.rb +98 -0
  17. data/lib/waitress/chef.rb +110 -0
  18. data/lib/waitress/configure.rb +116 -0
  19. data/lib/waitress/handlers/dirhandler.rb +39 -0
  20. data/lib/waitress/handlers/handler.rb +57 -0
  21. data/lib/waitress/handlers/handler404.rb +25 -0
  22. data/lib/waitress/handlers/libhandler.rb +58 -0
  23. data/lib/waitress/kernel.rb +182 -0
  24. data/lib/waitress/parse/query.rb +60 -0
  25. data/lib/waitress/request.rb +45 -0
  26. data/lib/waitress/resources/default_config.rb +52 -0
  27. data/lib/waitress/resources/http/404.html +18 -0
  28. data/lib/waitress/resources/http/css/hack.css +37 -0
  29. data/lib/waitress/resources/http/css/waitress.css +57 -0
  30. data/lib/waitress/resources/http/fonts/eot/latin/hack-bold-latin-webfont.eot +0 -0
  31. data/lib/waitress/resources/http/fonts/eot/latin/hack-bolditalic-latin-webfont.eot +0 -0
  32. data/lib/waitress/resources/http/fonts/eot/latin/hack-italic-latin-webfont.eot +0 -0
  33. data/lib/waitress/resources/http/fonts/eot/latin/hack-regular-latin-webfont.eot +0 -0
  34. data/lib/waitress/resources/http/fonts/svg/latin/hack-bold-latin-webfont.svg +241 -0
  35. data/lib/waitress/resources/http/fonts/svg/latin/hack-bolditalic-latin-webfont.svg +241 -0
  36. data/lib/waitress/resources/http/fonts/svg/latin/hack-italic-latin-webfont.svg +241 -0
  37. data/lib/waitress/resources/http/fonts/svg/latin/hack-regular-latin-webfont.svg +241 -0
  38. data/lib/waitress/resources/http/fonts/web-ttf/latin/hack-bold-latin-webfont.ttf +0 -0
  39. data/lib/waitress/resources/http/fonts/web-ttf/latin/hack-bolditalic-latin-webfont.ttf +0 -0
  40. data/lib/waitress/resources/http/fonts/web-ttf/latin/hack-italic-latin-webfont.ttf +0 -0
  41. data/lib/waitress/resources/http/fonts/web-ttf/latin/hack-regular-latin-webfont.ttf +0 -0
  42. data/lib/waitress/resources/http/fonts/woff/latin/hack-bold-latin-webfont.woff +0 -0
  43. data/lib/waitress/resources/http/fonts/woff/latin/hack-bolditalic-latin-webfont.woff +0 -0
  44. data/lib/waitress/resources/http/fonts/woff/latin/hack-italic-latin-webfont.woff +0 -0
  45. data/lib/waitress/resources/http/fonts/woff/latin/hack-regular-latin-webfont.woff +0 -0
  46. data/lib/waitress/resources/http/fonts/woff2/latin/hack-bold-latin-webfont.woff2 +0 -0
  47. data/lib/waitress/resources/http/fonts/woff2/latin/hack-bolditalic-latin-webfont.woff2 +0 -0
  48. data/lib/waitress/resources/http/fonts/woff2/latin/hack-italic-latin-webfont.woff2 +0 -0
  49. data/lib/waitress/resources/http/fonts/woff2/latin/hack-regular-latin-webfont.woff2 +0 -0
  50. data/lib/waitress/resources/http/img/404.png +0 -0
  51. data/lib/waitress/resources/http/index.html +15 -0
  52. data/lib/waitress/response.rb +104 -0
  53. data/lib/waitress/server.rb +115 -0
  54. data/lib/waitress/util.rb +713 -0
  55. data/lib/waitress/version.rb +3 -0
  56. data/lib/waitress/vhost.rb +217 -0
  57. data/lib/waitress_http11.so +0 -0
  58. data/waitress-core.gemspec +27 -0
  59. metadata +187 -0
data/lib/waitress.rb ADDED
@@ -0,0 +1,98 @@
1
+ require 'waitress/version'
2
+ require 'waitress/util'
3
+ require 'waitress/kernel'
4
+ require 'waitress/configure'
5
+ require 'waitress/parse/query'
6
+
7
+ require 'waitress/server'
8
+ require 'waitress/request'
9
+ require 'waitress/response'
10
+
11
+ require 'waitress/vhost'
12
+ require 'waitress/handlers/handler'
13
+ require 'waitress/handlers/dirhandler'
14
+ require 'waitress/handlers/handler404'
15
+ require 'waitress/handlers/libhandler'
16
+ require 'waitress/chef'
17
+
18
+ require 'waitress_http11'
19
+
20
+ require 'go'
21
+ require 'configfile'
22
+ require 'fileutils'
23
+
24
+ # The Base module for the Waitress Web Server, containing all the required
25
+ # classes and utilities created by Waitress
26
+ module Waitress
27
+
28
+ # Create a new Waitress Server, or, in case of the Filesystem, create a Configuration
29
+ # for a set of Servers
30
+ # Params:
31
+ # +filesystem+:: True if waitress should be loaded from the Filesystem. Default: false
32
+ # +rootdir+:: The root directory to load waitress from, defaults to ~/.waitress
33
+ def self.serve! filesystem=false, rootdir=:default
34
+ waitress = Waitress.new
35
+ waitress.serve! filesystem, rootdir
36
+ end
37
+
38
+ # Create a configuration for a single Waitress Server instance. This should be called
39
+ # from the config.rb file and nowhere else.
40
+ # Params:
41
+ # +args+:: The arguments to configure with. This should be a variable amount of arguments
42
+ # representing what ports to run the server on. If no args are provided, port 80 will
43
+ # be used as a default
44
+ # +block+:: The block to call once the configuration has been created. Setup should be
45
+ # done in here
46
+ def self.configure! *args, &block
47
+ Waitress::Configure.configure! *args, &block
48
+ end
49
+
50
+ # Create a new Launch Instance, used to serve a simple Waitress Server from either the
51
+ # filesystem, or embedded.
52
+ def self.new *args
53
+ Waitress::Launcher.new *args
54
+ end
55
+
56
+ class Launcher
57
+
58
+ # Create a new launcher. This is responsible for creating Waitress server instances
59
+ # from either the Filesystem, or being embedded in an application
60
+ def initialize waitress_root="~/.waitress"
61
+ @waitress_root = File.expand_path waitress_root
62
+ end
63
+
64
+ # Serve a Waitress server from either the Filesystem or embedded in an application
65
+ def serve! filesystem=false, rootdir=:default
66
+ if filesystem
67
+ serve_filesystem rootdir
68
+ else
69
+ serve
70
+ end
71
+ end
72
+
73
+ :private
74
+ def config
75
+ ConfigFile.new File.join(@waitress_root, "config.yml"),
76
+ {"server_root" => File.join(@waitress_root, "www")}, :yaml
77
+ end
78
+
79
+ def serve_filesystem rootdir
80
+ if rootdir == :default
81
+ FileUtils.mkdir_p @waitress_root unless File.exist? @waitress_root
82
+ cfg = config
83
+ cfg.load
84
+ @root = File.expand_path cfg["server_root"]
85
+ else
86
+ @root = rootdir
87
+ end
88
+ # s = serve
89
+ # Waitress::Configure.new s, @root
90
+ # s
91
+ Waitress::Configure.new @root
92
+ end
93
+
94
+ def serve
95
+ Waitress::HttpServer.new
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,110 @@
1
+ module Waitress
2
+
3
+ # The chef class handles the cooking of responses, by serving errors and files
4
+ # from the Filesystem, as well as providing a system for including files within
5
+ # handlers and .wrb files. This class handles most loading from Filesystems
6
+ # and serving of the body of a response.
7
+ class Chef
8
+
9
+ HANDLERS = {
10
+ 404 => Handler404.new
11
+ }
12
+
13
+ # Get the waitress resources directory, containing templates and the default
14
+ # http assets of waitress
15
+ def self.resources
16
+ File.expand_path "../resources", __FILE__
17
+ end
18
+
19
+ # Get the waitress HTTP assets directory, containing the default index, 404
20
+ # and styles resources.
21
+ def self.resources_http
22
+ File.join(resources, "http")
23
+ end
24
+
25
+ # Set the response to use an error page with the given error code (usually 404)
26
+ def self.error code, request, response, client, vhost
27
+ HANDLERS[code].serve!(request, response, client, vhost)
28
+ end
29
+
30
+ # Serve a file from the Filesystem, automatically handling based on whether the
31
+ # file is dynamic or static. This will set the body io and any required
32
+ # headers on the reponse object.
33
+ def self.serve_file request, response, client, vhost, file
34
+ if File.extname(file) == ".wrb" || File.extname(file) == ".rb"
35
+ response.mime ".html"
36
+ include_absfile File.expand_path(file)
37
+ else
38
+ response.mime File.extname(file)
39
+ response.body_io File.open(file, "r")
40
+ end
41
+ end
42
+
43
+ # Include a file from the VHost loadpath in the current running instance.
44
+ # Params:
45
+ # +filename+:: The filename of the file, relative to the load path of the VHost.
46
+ def self.include_file filename
47
+ lp = $VHOST.load_path
48
+ target = nil
49
+ lp.each do |path|
50
+ fl = File.join(path, filename)
51
+ ext = ["", ".rb", ".wrb"]
52
+ ext.each do |e|
53
+ flnew = "#{fl}#{e}"
54
+ target = flnew if File.exist?(flnew)
55
+ end
56
+ end
57
+
58
+ raise LoadError.new("Include does not exist in Load Path: #{target}") if target.nil?
59
+ include_absfile target
60
+ end
61
+
62
+ # Include a file from anywhere in the filesystem (absolute) in the current running
63
+ # instance. This will load the file's content and, if dynamic, evaluate it to the
64
+ # current response.
65
+ # Params:
66
+ # +target+:: The target file, given in absolute path form.
67
+ def self.include_absfile target
68
+ ext = File.extname target
69
+ if ext == ".wrb"
70
+ Waitress::WRBParser.parse! File.read(target), $RESPONSE.body_io
71
+ elsif ext == ".rb"
72
+ require target
73
+ else
74
+ echo File.read(target)
75
+ end
76
+ end
77
+
78
+ # Find a file to serve. This is used by the DirHandler
79
+ # to automatically include an index file if it exists under the
80
+ # requested directory, automatically add the .wrb or .html file extension
81
+ # for paths without the extension, etc. A hash containing the result (ok / notfound)
82
+ # and the new filepath will be given.
83
+ def self.find_file abspath
84
+ ret = {}
85
+ if File.exist?(abspath)
86
+ if File.directory?(abspath)
87
+ wrb = File.join(abspath, "index.wrb")
88
+ html = File.join(abspath, "index.html")
89
+ if File.exist?(wrb)
90
+ ret = { :result => :ok, :file => wrb }
91
+ elsif File.exist?(html)
92
+ ret = { :result => :ok, :file => html }
93
+ else
94
+ ret = { :result => :dir, :file => abspath }
95
+ end
96
+ else
97
+ ret = { :result => :ok, :file => abspath }
98
+ end
99
+ elsif File.exist?("#{abspath}.html")
100
+ ret = { :result => :ok, :file => "#{abspath}.html" }
101
+ elsif File.exist?("#{abspath}.wrb")
102
+ ret = { :result => :ok, :file => "#{abspath}.wrb" }
103
+ else
104
+ ret = { :result => :notfound }
105
+ end
106
+ ret
107
+ end
108
+
109
+ end
110
+ end
@@ -0,0 +1,116 @@
1
+ module Waitress
2
+
3
+ # The Configure Class is used to load Waitress configurations from the filesystem,
4
+ # usually used in the config.rb file.
5
+ class Configure
6
+
7
+ # Endpoint for Waitress.configure!
8
+ def self.configure! *args, &block
9
+ raise "Using 'configure!' outside of file target" if @@configure_target.nil?
10
+ @@configure_target.read_configure *args, &block
11
+ end
12
+
13
+ def self.config_target o
14
+ @@configure_target = o
15
+ end
16
+
17
+ attr_accessor :servers
18
+ attr_accessor :root
19
+
20
+ def initialize root
21
+ @root = root
22
+ @configurations = []
23
+ generate_configs
24
+
25
+ load_cfg
26
+
27
+ @servers = @configurations.map do |conf|
28
+ s = Waitress::HttpServer.new
29
+ conf.hosts.each { |h| s << h }
30
+ s.ports *conf.ports
31
+ s
32
+ end
33
+ puts "Waitress Configuration Complete"
34
+ puts "Servers Started on Ports: "
35
+ @servers.each do |x|
36
+ puts "\t#{x.ports.join ", "}"
37
+ end
38
+ end
39
+
40
+ # Run all servers in this configuration
41
+ def run
42
+ @servers.each { |s| s.run }
43
+ end
44
+
45
+ # Join all the server threads in this configuration
46
+ def join
47
+ @servers.each { |s| s.join }
48
+ end
49
+
50
+ # Read the configuration object
51
+ def read_configure *args, &block
52
+ config = Configuration.new self, *args
53
+ block.call(config)
54
+ @configurations << config
55
+ end
56
+
57
+ # Generate the configuration file if it doesn't already exist.
58
+ def generate_configs
59
+ FileUtils.mkdir_p(@root) unless File.exist?(@root)
60
+ raise "File #{@root} is not a directory!" unless File.directory?(@root)
61
+ @config = File.join(@root, "config.rb")
62
+ unless File.exist?(@config)
63
+ c = File.read(File.join(Waitress::Chef.resources, "default_config.rb"))
64
+ File.write(@config, c)
65
+ end
66
+ end
67
+
68
+ # Load the config.rb file
69
+ def load_cfg
70
+ Waitress::Configure.config_target self
71
+ path = File.absolute_path(@config)
72
+ require path
73
+ Waitress::Configure.config_target nil
74
+ end
75
+
76
+ end
77
+
78
+ # The Configuration Class is the object that contains a configuration
79
+ # of a single server instance, hosting all the methods provided by
80
+ # Waitress.configure!
81
+ class Configuration
82
+
83
+ attr_accessor :hosts
84
+ attr_accessor :ports
85
+
86
+ def initialize configure, *ports
87
+ @ports = *ports
88
+ @hosts = []
89
+ @configure = configure
90
+ end
91
+
92
+ # Create a new VirtualHost with the given regex, priority, and configure it
93
+ # inside of its own block.
94
+ def host regex, priority=50, &block
95
+ host = Waitress::Vhost.new regex, priority
96
+ host.set_configure @configure
97
+ block.call(host)
98
+ @hosts << host
99
+ host
100
+ end
101
+
102
+ # Over all the registered VHosts, call this method. Use this to configure
103
+ # a similar setting for all vhosts at once instead of duplicating code
104
+ # across all of them.
105
+ def all_hosts &block
106
+ @hosts.each { |h| block.call(h) }
107
+ end
108
+
109
+ def to_s
110
+ m = lambda { |a,x| x.nil? ? "" : "\r\n#{a}=#{x.inspect}" }
111
+ "#<#{self.class} #{m.call('ports', @ports)} #{m.call('hosts', @hosts)}>"
112
+ end
113
+
114
+ end
115
+
116
+ end
@@ -0,0 +1,39 @@
1
+ module Waitress
2
+
3
+ # The DirHandler class is an instance of +Waitress::Handler+ that is responsible
4
+ # for loading files from the filesystem and serving them if they exist in the VHost's
5
+ # root. It automatically handles mimetypes, evaluation and almost everything about
6
+ # the serving process for files in the FileSystem.
7
+ class DirHandler < Handler
8
+
9
+ attr_accessor :priority
10
+ attr_accessor :directory
11
+
12
+ # Get the instance of DirHandler that will load Waitress' resources
13
+ # such as the default 404 and index pages, as well as CSS and JS
14
+ def self.resources_handler
15
+ @@resources_handler ||= Waitress::DirHandler.new(Waitress::Chef.resources_http, -1000)
16
+ @@resources_handler
17
+ end
18
+
19
+ # Create a new DirHandler, with the given FileSystem directory as a root
20
+ # and priority.
21
+ def initialize directory, priority=50
22
+ @directory = File.absolute_path(directory)
23
+ @priority = priority
24
+ end
25
+
26
+ def respond? request, vhost
27
+ path = File.expand_path File.join("#{directory}", request.path)
28
+ res = Waitress::Chef.find_file(path)[:result]
29
+ path.include?(directory) && (res == :ok)
30
+ end
31
+
32
+ def serve request, response, client, vhost
33
+ path = File.expand_path File.join("#{directory}", request.path)
34
+ file = Waitress::Chef.find_file(path)[:file]
35
+ Waitress::Chef.serve_file request, response, client, vhost, file
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,57 @@
1
+ module Waitress
2
+
3
+ # The Handler class is responsible for handling incoming HTTP requests for a
4
+ # given URL Path. This default class works by matching a regular expression to
5
+ # the request path, however subclasses may choose to use their own matching
6
+ # methods (see +Waitress::DirHandler+).
7
+ #
8
+ # Each Handler acts off of a priority system, where if multiple handlers
9
+ # can respond to the request, the one with the highest priority will be chosen.
10
+ class Handler
11
+
12
+ attr_accessor :priority
13
+
14
+ # Create a new Regex-Based Handler
15
+ # Params:
16
+ # +regex+:: The regex pattern to match against the request path
17
+ # +priority+:: Priority of the handler. Default: 50
18
+ # +action+:: The block to call when a match is reached. Should take args
19
+ # request, response, client and vhost.
20
+ def initialize regex=nil, priority=50, &action
21
+ @regex = regex
22
+ @action = action
23
+ @priority = priority
24
+ end
25
+
26
+ # Returns true if this handler is valid for the given request
27
+ def respond? request, vhost
28
+ (request.path =~ @regex) != nil
29
+ end
30
+
31
+ # Don't touch this -- this adds Kernel bindings
32
+ def serve! request, response, client, vhost
33
+ kernel_prepare
34
+ serve request, response, client, vhost
35
+ end
36
+
37
+ # If we can respond to the request, this method is called to
38
+ # serve a response based on this handler. Do your response logic here.
39
+ # Params:
40
+ # +request+:: The +Waitress::Request+ object
41
+ # +response+:: The +Waitress::Response+ object
42
+ # +client+:: The client socket
43
+ # +vhost+:: The Virtual Host responsible for the connection
44
+ def serve request, response, client, vhost
45
+ @action.call(request, response, client, vhost) unless @action.nil?
46
+ end
47
+
48
+ end
49
+
50
+ # The ErrorHandler has the lowest priority, as it shouldn't be triggered
51
+ # unless there is an error (i.e. 404, 500)
52
+ class ErrorHandler < Handler
53
+ def initialize
54
+ @priority = -65536
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,25 @@
1
+ module Waitress
2
+
3
+ # The 404 Handler is a simple "Catch-All" handler which will be triggered if
4
+ # a valid handler is not found for the page, and will show an error page
5
+ # telling the user the page cannot be found
6
+ class Handler404 < ErrorHandler
7
+
8
+ def serve request, response, client, vhost
9
+ response.status 404
10
+ e404page = vhost.get_404
11
+ if !e404page.nil? && (Waitress::Chef.find_file(e404page)[:result]==:ok)
12
+ Waitress::Chef.serve_file request, response, client, vhost, e404page
13
+ else
14
+ if vhost.resources?
15
+ h = File.join Waitress::Chef.resources_http, "404.html"
16
+ Waitress::Chef.serve_file request, response, client, vhost, h
17
+ else
18
+ response.mime ".html"
19
+ response.body "<h1> 404 - Not Found </h1> <p> The page you have requested is not here </p>"
20
+ end
21
+ end
22
+ end
23
+
24
+ end
25
+ end