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
@@ -0,0 +1,58 @@
1
+ module Waitress
2
+
3
+ # The LibraryHandler is used to handle requests to the VHost regarding the
4
+ # libraries to be loaded by other Handlers and .wrb files. This will take any
5
+ # requests to /libraries (or whatever the user has set it to) to load libraries
6
+ class LibraryHandler < Handler
7
+
8
+ attr_accessor :priority
9
+
10
+ def initialize libraries, libdir, liburi, vhost
11
+ @priority = 150
12
+ @vhost = vhost
13
+ @libraries, @libdir, @liburi = libraries, File.expand_path(libdir), liburi
14
+ FileUtils.mkdir_p(@libdir) unless File.exist?(@libdir)
15
+
16
+ @libraries.each do |name, lib|
17
+ l = {}
18
+ d = dirType(lib[:bindtype])
19
+ matches = Dir["#{d}/**/*.#{lib[:bindtype].to_s}"].select { |x| (x =~ lib[:pattern]) != nil }
20
+ if matches.length > 0
21
+ l[:file] = matches[0]
22
+ l[:type] = lib[:bindtype]
23
+ else
24
+ l = nil
25
+ end
26
+ @libraries[name] = l
27
+ end
28
+
29
+ [:css, :js].each do |k|
30
+ d = dirType k
31
+ FileUtils.mkdir_p(d) unless File.exist?(d)
32
+
33
+ Dir["#{d}/**/*.#{k.to_s}"].each do |fl|
34
+ @libraries[File.basename(fl).to_sym] = { :file => fl, :type => k }
35
+ end
36
+ end
37
+ end
38
+
39
+ def dirType k
40
+ File.join(@libdir, k.to_s)
41
+ end
42
+
43
+ def respond? request, vhost
44
+ path = request.path
45
+ return false unless path.start_with?("/#{@liburi}/")
46
+ name = path.sub("/#{@liburi}/", "").to_sym
47
+ @libraries.include?(name)
48
+ end
49
+
50
+ def serve request, response, client, vhost
51
+ path = request.path
52
+ name = path.sub("/#{@liburi}/", "").to_sym
53
+ lib = @libraries[name]
54
+ Waitress::Chef.serve_file request, response, client, vhost, lib[:file]
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,182 @@
1
+ # The Kernel Module provides global methods that will provide the 'builtins' for .wrb files
2
+ # and handlers. This is used to prevent verbose access of a namespace like Waitress::Global,
3
+ # and instead provide them here. Because requests are handled in new Processes, these values
4
+ # will change in each request and will not interfere.
5
+ module ::Kernel
6
+
7
+ # The +Waitress::Response+ object being used
8
+ def response_object
9
+ $RESPONSE
10
+ end
11
+
12
+ # The +Waitress::Request+ object being used
13
+ def request_object
14
+ $REQUEST
15
+ end
16
+
17
+ # Prepare the Kernel, by linking global variables
18
+ def kernel_prepare
19
+ $METHOD = get_method
20
+ $HEADERS = get_headers
21
+ $PATH = get_path
22
+ $URI = get_uri
23
+ $BODY = get_body
24
+ end
25
+
26
+ # Automatically load a library header into this file in the form of HTML.
27
+ # This will load a library in the VHost's libs/ folder, or any lib defined in the
28
+ # VHost's config.rb file with the name given. JS libraries will be linked with the
29
+ # <script> tag, whilst css files will be linked with the <link rel="stylesheet">
30
+ # tag. This is the recommended way of handling library loading.
31
+ # Params:
32
+ # +name+:: The name of the lib (the filename), or the name of the library as bound
33
+ # in the config.rb file.
34
+ def lib name
35
+ name = name.to_sym
36
+ type = $VHOST.libraries[name][:type]
37
+ libhome = $VHOST.liburi
38
+ if type == :js
39
+ echo "<script type='text/javascript' src='/#{libhome}/#{name}'></script>"
40
+ elsif type == :css
41
+ echo "<link rel='stylesheet' href='/#{libhome}/#{name}'></link>"
42
+ end
43
+ end
44
+
45
+ # Automatically load a Library Combo into this file. This will consecutively load
46
+ # all the libraries bound to the combination with the given name as defined in the
47
+ # VHost's config.rb file. This will call lib() for each of these libraries.
48
+ # Params:
49
+ # +name+:: The name of the combo to load
50
+ def combo name
51
+ name = name.to_sym
52
+ combo_arr = $VHOST.combos[name]
53
+ combo_arr.each { |n| lib(n) }
54
+ end
55
+
56
+ # Include another .wrb, .rb or any other file in the load path of the VHost into this
57
+ # file. If this file is .wrb or .rb, it will be evaluated. If it is another type of file
58
+ # (e.g. html), it will be directly echoed to the output buffer
59
+ # Params:
60
+ # +filename+:: The name of the file, relative to the loadpath
61
+ def includes filename
62
+ Waitress::Chef.include_file filename
63
+ end
64
+
65
+ # Include another .wrb, .rb or any other file in this file. If this file is
66
+ # .wrb or .rb, it will be evaluated. If it is another type of file
67
+ # (e.g. html), it will be directly echoed to the output buffer
68
+ # Params:
69
+ # +filename+:: The absolute filename of the file to load, anywhere in the filesystem
70
+ def includes_file filename
71
+ Waitress::Chef.include_absfile filename
72
+ end
73
+
74
+ # Returns a Hash of the GET query of the request. This may be an empty array
75
+ # if querystring was present
76
+ def get
77
+ request_object.get_query
78
+ end
79
+
80
+ # Returns a Hash of the POST query of the request. This may be an empty array
81
+ # if the body is not a valid querystring, or an exception raised if there was
82
+ # an error in parsing.
83
+ def post
84
+ request_object.post_query
85
+ end
86
+
87
+ # Get a header from the HTTP Request. This will fetch the header by the given
88
+ # name from the request object. Keep in mind that in requests, Headers are fully
89
+ # capitalized and any hyphens replaced with underscores (e.g. Content-Type becomes
90
+ # CONTENT_TYPE)
91
+ def get_header name
92
+ request_object.headers[name]
93
+ end
94
+
95
+ # Return the full list of headers available in the request object.
96
+ def get_headers
97
+ request_object.headers
98
+ end
99
+
100
+ # Returns the HTTP method that was used to retrieve this page (GET, POST, UPDATE,
101
+ # DELETE, PUT, etc)
102
+ def get_method
103
+ request_object.method
104
+ end
105
+
106
+ # Get the path of this request. This is after a URL rewrite, and does not contain
107
+ # a querystring. Be careful with these, as they start with a "/" and if not joined
108
+ # correctly can cause issues in the root of your filesystem (use File.join) if you
109
+ # plan to use this
110
+ def get_path
111
+ request_object.path
112
+ end
113
+
114
+ # Get the URI of this request. Unlike the path, the URI is not modified after a rewrite,
115
+ # and does contain a querystring. Use this if you want the *original* path and query
116
+ # of the request before it was rewritten
117
+ def get_uri
118
+ request_object.uri
119
+ end
120
+
121
+ # Get the request body. In most cases, this will be blank, but for POST requests it may
122
+ # contain a querystring, and for PUT and UPDATE methods it may contain other data
123
+ def get_body
124
+ request_object.body
125
+ end
126
+
127
+ # Get the querystring object as a string before it is parsed
128
+ def get_querystring
129
+ request_object.querystring
130
+ end
131
+
132
+ # Set a response header. This will be joined when writing the response with the delimiter ": "
133
+ # as in regular HTTP Protocol fashion.
134
+ # Params:
135
+ # +name+:: The name of the header, e.g. "Content-Type"
136
+ # +value+:: The value of the header, e.g. "text/html"
137
+ def set_header name, value
138
+ response_object.header name, value
139
+ end
140
+
141
+ # Set the content-type of the response. This is a shortcut to the Content-Type
142
+ # header and takes the full content-type (not fileextension) as an argument
143
+ # Params:
144
+ # +raw_type+:: The mime type of the content, e.g. "text/html"
145
+ def content_type raw_type
146
+ response_object.mime_raw raw_type
147
+ end
148
+
149
+ # Set the content-type of the response. This is a shortcut to the Content-Type
150
+ # header, and will also lookup the fileextension in the +Waitress::Util+ mime-type
151
+ # lookup.
152
+ # Params:
153
+ # +extension+:: The file extension to map to a mimetype, e.g. ".html"
154
+ def file_ext extension
155
+ response_object.mime extension
156
+ end
157
+
158
+ # Write a string to the output buffer. This will write directly to the body of the
159
+ # response, similar to what 'print()' does for STDOUT. Use this to write data to the
160
+ # output stream
161
+ def echo obj
162
+ str = obj.to_s
163
+ write str
164
+ end
165
+
166
+ # Write a string to the output buffer, followed by a newline. Similar to echo(),
167
+ # this will write to the output buffer, but also adds a "\n". This does to the
168
+ # client output as 'puts()' does to STDOUT. Use this to write data to the output
169
+ # stream
170
+ def println obj
171
+ echo(obj.to_s + "\n")
172
+ end
173
+
174
+ # Write a set of bytes directly to the output stream. Use this if you don't want
175
+ # to cast to a string as echo() and println() do.
176
+ def write bytes
177
+ r = response_object
178
+ r.body "" if r.body_io.nil?
179
+ r.body_io.write bytes
180
+ end
181
+
182
+ end
@@ -0,0 +1,60 @@
1
+ module Waitress
2
+ # A lot of this class uses methods from Rack::QueryParser in order to Parse
3
+ # a given QueryString into a Hash of key/value pairs
4
+ class QueryParser
5
+ require 'uri'
6
+
7
+ DEFAULT_SEP = /[&;] */n
8
+
9
+ # Unescape a HTTP URL to regular text. e.g. %20 becomes a space (" ")
10
+ def self.unescape str, enc=Encoding::UTF_8
11
+ URI.decode_www_form_component(str, enc)
12
+ end
13
+
14
+ # Parse the given QueryString into a hash of key/value pairs
15
+ def self.parse qs
16
+ return {} if qs.nil? || qs.empty?
17
+ results = {}
18
+ (qs || '').split(DEFAULT_SEP).each do |p|
19
+ k, v = p.split('='.freeze, 2).map! { |s| unescape(s) }
20
+
21
+ normalize results, k, v
22
+ end
23
+ results
24
+ end
25
+
26
+ def self.normalize hash, name, v
27
+ name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
28
+ k = $1 || ''
29
+ after = $' || ''
30
+
31
+ return if k.empty?
32
+
33
+ if after == ""
34
+ hash[k] = v
35
+ elsif after == "["
36
+ hash[name] = v
37
+ elsif after == "[]"
38
+ hash[k] ||= []
39
+ raise TypeError, "expected Array (got #{hash[k].class.name}) for param `#{k}'" unless hash[k].is_a?(Array)
40
+ hash[k] << v
41
+ elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
42
+ child_key = $1
43
+ hash[k] ||= []
44
+ raise TypeError, "expected Array (got #{hash[k].class.name}) for param `#{k}'" unless hash[k].is_a?(Array)
45
+ if hash[k].last.is_a?(Hash) && !hash[k].last.key?(child_key)
46
+ normalize(hash[k].last, child_key, v)
47
+ else
48
+ hash[k] << normalize({}, child_key, v)
49
+ end
50
+ else
51
+ hash[k] ||= {}
52
+ raise TypeError, "expected Hash (got #{hash[k].class.name}) for param `#{k}'" unless hash[k].is_a?(Hash)
53
+ hash[k] = normalize_params(hash[k], after, v)
54
+ end
55
+
56
+ hash
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,45 @@
1
+ module Waitress
2
+ # The request class is used to represent a HTTP request by a client. This includes
3
+ # all the headers sent to the server by the client, request URI and those properties
4
+ # parsed by Mongrel, including the Path and QueryString. GET and POST queries are to
5
+ # be parsed on-request by the handler or .wrb file as to not waste CPU resources.
6
+ class Request
7
+
8
+ attr_accessor :method
9
+ attr_accessor :path
10
+ attr_accessor :uri
11
+ attr_accessor :querystring
12
+ attr_accessor :http_version
13
+ attr_accessor :body
14
+ attr_accessor :headers
15
+
16
+ def initialize method, path, uri, query, http_version, body, headers
17
+ @method = method
18
+ @path = Waitress::QueryParser.unescape(path)
19
+ @uri = Waitress::QueryParser.unescape(uri)
20
+ @querystring = query
21
+ @http_version = http_version
22
+ @body = body
23
+ @headers = headers
24
+ @marks = {}
25
+ end
26
+
27
+ # The GET query for the request in the form of a hash. This is parsed on-request
28
+ def get_query
29
+ @get ||= Waitress::QueryParser.parse(@querystring)
30
+ @get
31
+ end
32
+
33
+ # The POST query for the request in the form of a hash. This is parsed on-request
34
+ def post_query
35
+ @post ||= Waitress::QueryParser.parse(@body)
36
+ @post
37
+ end
38
+
39
+ def to_s
40
+ m = lambda { |a,x| x.nil? ? "" : "#{a}=#{x.inspect}" }
41
+ "#<#{self.class} method=#{@method} path=#{@path} #{m.call("query", @query)}>"
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,52 @@
1
+ # This is the configuration for your waitress server, accepting connections on port '2910'
2
+ Waitress.configure!(2910) do |w|
3
+
4
+ # You can run regular Ruby Code in here, too!
5
+ @home = "~/.waitress/www/"
6
+ def fl file
7
+ File.join(@home, file)
8
+ end
9
+
10
+ # This is your main Virtual Host, accepting connections to 'example.mysite.com'
11
+ w.host(/example.mysite.com/) do |host|
12
+ # This is where your public documents and pages are stored
13
+ host.root fl("example/http")
14
+
15
+ # This is where your non-public includes are stored
16
+ host.includes fl("example/rb")
17
+
18
+ # This will show up when a 404 error occurs
19
+ # host.set_404 fl("example/http/404.html")
20
+
21
+ # Want to rewrite a URL? No problem.
22
+ host.rewrite /some_url/, "some_other_url"
23
+ host.rewrite /capture_group_(\d)/, "capture/group\\1"
24
+
25
+ # Bind_Lib will allow you to automatically import lib tags into .wrb files
26
+ # Before they are sent to the client.
27
+ host.bind_lib /jquery.*/, :js, "jquery"
28
+ host.bind_lib /boostrap.*/, :css, "boots"
29
+
30
+ # Use combos to chain together libraries into a collection
31
+ host.combo "all-lib", "jquery", "boots"
32
+
33
+ # Change this to change where you store your libraries
34
+ host.libdir fl("libs")
35
+
36
+ # Change this to choose what URI the libraries are linked
37
+ # to (yoursite.com/libraries/library_name)
38
+ host.liburi "libraries"
39
+ end
40
+
41
+ # This is your other Virtual Host, accepting connections to any domain.
42
+ # The '0' represents the priority, with the default being 50. Higher priority
43
+ # Hosts will be chosen if the request matches multiple Hosts.
44
+ w.host(/.*/, 0) do |host|
45
+ # This is where your public documents and pages are stored
46
+ host.root fl("main/http")
47
+
48
+ # This is where your non-public includes are stored
49
+ host.includes fl("main/rb")
50
+ end
51
+
52
+ end
@@ -0,0 +1,18 @@
1
+ <html>
2
+ <head>
3
+ <title> 404 - Page Not Found </title>
4
+ <link rel="stylesheet" href="/css/hack.css">
5
+ <link rel="stylesheet" href="/css/waitress.css">
6
+ </head>
7
+ <body>
8
+ <div id="maincontainer">
9
+ <div class="textcontainer">
10
+ <h1> 404 </h1>
11
+ <h2> You ordered something that wasn't on the menu </h2>
12
+ </div>
13
+ <div class="imgcontainer">
14
+ <img src="/img/404.png">
15
+ </div>
16
+ </div>
17
+ </body>
18
+ </html>
@@ -0,0 +1,37 @@
1
+ /*!
2
+ * Hack v2.013 - https://sourcefoundry.org/hack/
3
+ * Licenses - Fonts: Hack Open Font License + Bitstream Vera license, CSS: MIT License
4
+ */
5
+ /* FONT PATHS
6
+ * -------------------------- */
7
+ @font-face {
8
+ font-family: 'Hack';
9
+ src: url('../fonts/eot/latin/hack-regular-latin-webfont.eot?v=2.013');
10
+ src: url('../fonts/eot/latin/hack-regular-latin-webfont.eot?#iefix&v=2.013') format('embedded-opentype'), url('../fonts/woff2/latin/hack-regular-latin-webfont.woff2?v=2.013') format('woff2'), url('../fonts/woff/latin/hack-regular-latin-webfont.woff?v=2.013') format('woff'), url('../fonts/web-ttf/latin/hack-regular-latin-webfont.ttf?v=2.013') format('truetype'), url('../fonts/svg/latin/hack-regular-latin-webfont.svg?v=2.013#hackregular') format('svg');
11
+ font-weight: 400;
12
+ font-style: normal;
13
+ }
14
+
15
+ @font-face {
16
+ font-family: 'Hack';
17
+ src: url('../fonts/eot/latin/hack-bold-latin-webfont.eot?v=2.013');
18
+ src: url('../fonts/eot/latin/hack-bold-latin-webfont.eot?#iefix&v=2.013') format('embedded-opentype'), url('../fonts/woff2/latin/hack-bold-latin-webfont.woff2?v=2.013') format('woff2'), url('../fonts/woff/latin/hack-bold-latin-webfont.woff?v=2.013') format('woff'), url('../fonts/web-ttf/latin/hack-bold-latin-webfont.ttf?v=2.013') format('truetype'), url('../fonts/svg/latin/hack-bold-latin-webfont.svg?v=2.013#hackbold') format('svg');
19
+ font-weight: 700;
20
+ font-style: normal;
21
+ }
22
+
23
+ @font-face {
24
+ font-family: 'Hack';
25
+ src: url('../fonts/eot/latin/hack-italic-latin-webfont.eot?v=2.013');
26
+ src: url('../fonts/eot/latin/hack-italic-latin-webfont.eot?#iefix&v=2.013') format('embedded-opentype'), url('../fonts/woff2/latin/hack-italic-latin-webfont.woff2?v=2.013') format('woff2'), url('../fonts/woff/latin/hack-italic-latin-webfont.woff?v=2.013') format('woff'), url('../fonts/web-ttf/latin/hack-italic-latin-webfont.ttf?v=2.013') format('truetype'), url('../fonts/svg/latin/hack-italic-latin-webfont.svg?v=2.013#hackitalic') format('svg');
27
+ font-weight: 400;
28
+ font-style: italic;
29
+ }
30
+
31
+ @font-face {
32
+ font-family: 'Hack';
33
+ src: url('../fonts/eot/latin/hack-bolditalic-latin-webfont.eot?v=2.013');
34
+ src: url('../fonts/eot/latin/hack-bolditalic-latin-webfont.eot?#iefix&v=2.013') format('embedded-opentype'), url('../fonts/woff2/latin/hack-bolditalic-latin-webfont.woff2?v=2.013') format('woff2'), url('../fonts/woff/latin/hack-bolditalic-latin-webfont.woff?v=2.013') format('woff'), url('../fonts/web-ttf/latin/hack-bolditalic-latin-webfont.ttf?v=2.013') format('truetype'), url('../fonts/svg/latin/hack-bolditalic-latin-webfont.svg?v=2.013#hackbolditalic') format('svg');
35
+ font-weight: 700;
36
+ font-style: italic;
37
+ }