waitress-core 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -4
- data/LICENSE +21 -21
- data/Rakefile +13 -13
- data/bin/waitress +22 -22
- data/ext/Thanks.md +1 -1
- data/ext/waitress_http11/ext_help.h +15 -15
- data/ext/waitress_http11/extconf.rb +6 -6
- data/ext/waitress_http11/http11.c +532 -532
- data/ext/waitress_http11/http11_parser.c +1216 -1216
- data/ext/waitress_http11/http11_parser.h +49 -49
- data/ext/waitress_http11/http11_parser.java.rl +171 -171
- data/ext/waitress_http11/http11_parser.rl +165 -165
- data/ext/waitress_http11/http11_parser_common.rl +55 -55
- data/ext/waitress_http11/http11_wrb_parser.h +91 -91
- data/lib/waitress/chef.rb +113 -113
- data/lib/waitress/configure.rb +121 -121
- data/lib/waitress/evalbind.rb +9 -9
- data/lib/waitress/handlers/dirhandler.rb +39 -39
- data/lib/waitress/handlers/handler.rb +57 -57
- data/lib/waitress/handlers/handler404.rb +25 -25
- data/lib/waitress/handlers/libhandler.rb +58 -58
- data/lib/waitress/kernel.rb +182 -182
- data/lib/waitress/parse/query.rb +60 -60
- data/lib/waitress/request.rb +45 -45
- data/lib/waitress/resources/default_config.rb +52 -52
- data/lib/waitress/resources/http/404.html +18 -18
- data/lib/waitress/resources/http/css/hack.css +37 -37
- data/lib/waitress/resources/http/css/waitress.css +57 -57
- data/lib/waitress/resources/http/fonts/svg/latin/hack-bold-latin-webfont.svg +240 -240
- data/lib/waitress/resources/http/fonts/svg/latin/hack-bolditalic-latin-webfont.svg +240 -240
- data/lib/waitress/resources/http/fonts/svg/latin/hack-italic-latin-webfont.svg +240 -240
- data/lib/waitress/resources/http/fonts/svg/latin/hack-regular-latin-webfont.svg +240 -240
- data/lib/waitress/resources/http/index.html +15 -15
- data/lib/waitress/response.rb +105 -105
- data/lib/waitress/server.rb +160 -161
- data/lib/waitress/util.rb +707 -707
- data/lib/waitress/version.rb +3 -3
- data/lib/waitress/vhost.rb +217 -217
- data/lib/waitress.rb +99 -106
- data/lib/waitress_http11.bundle +0 -0
- data/waitress-core.gemspec +29 -29
- metadata +4 -4
- data/lib/waitress_http11.so +0 -0
@@ -1,15 +1,15 @@
|
|
1
|
-
<html>
|
2
|
-
<head>
|
3
|
-
<title> Welcome to Waitress </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="titlecontainer">
|
10
|
-
<h1> Waitress </h1>
|
11
|
-
<h2> Please take a seat and let me take your order </h2>
|
12
|
-
</div>
|
13
|
-
</div>
|
14
|
-
</body>
|
15
|
-
</html>
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title> Welcome to Waitress </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="titlecontainer">
|
10
|
+
<h1> Waitress </h1>
|
11
|
+
<h2> Please take a seat and let me take your order </h2>
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
</body>
|
15
|
+
</html>
|
data/lib/waitress/response.rb
CHANGED
@@ -1,105 +1,105 @@
|
|
1
|
-
module Waitress
|
2
|
-
# The response class is used to cook responses to be served to the client.
|
3
|
-
# This class contains things like response headers, status codes and the response
|
4
|
-
# body itself
|
5
|
-
class Response
|
6
|
-
|
7
|
-
def initialize
|
8
|
-
@headers = {}
|
9
|
-
status 200
|
10
|
-
default_headers
|
11
|
-
@isdone = false
|
12
|
-
end
|
13
|
-
|
14
|
-
# Returns true if the response has already been sent to the client
|
15
|
-
def done?
|
16
|
-
@isdone
|
17
|
-
end
|
18
|
-
|
19
|
-
# Mark the response as done (already sent to the client)
|
20
|
-
def done state=true
|
21
|
-
@isdone = state
|
22
|
-
end
|
23
|
-
|
24
|
-
# Apply the default headers to this response
|
25
|
-
def default_headers
|
26
|
-
header "Server", "Waitress #{Waitress::VERSION} (#{RUBY_PLATFORM})"
|
27
|
-
end
|
28
|
-
|
29
|
-
# Apply the given Status code to the response, such as 200, 404, 500 or
|
30
|
-
# any other code listed in the HTTP protocol specification
|
31
|
-
def status status_code
|
32
|
-
@status = status_code
|
33
|
-
@status_msg = Waitress::Util.status @status
|
34
|
-
header "Status", "#{@status} #{@status_msg}"
|
35
|
-
end
|
36
|
-
|
37
|
-
# Set the mimetype (Content-Type header) of this response to the one matching
|
38
|
-
# the given file extension as matched by the +Waitress::Util+ class
|
39
|
-
# +filext+:: The file extension to match, e.g. .html, .css, .js
|
40
|
-
def mime filext
|
41
|
-
m = Waitress::Util.mime filext
|
42
|
-
header "Content-Type", m
|
43
|
-
end
|
44
|
-
|
45
|
-
# Set the mimetype (Content-Type header) of this response to the one given.
|
46
|
-
# +type+:: The mime type to use, e.g. application/json, text/html,
|
47
|
-
# application/scon
|
48
|
-
def mime_raw type
|
49
|
-
header "Content-Type", type
|
50
|
-
end
|
51
|
-
|
52
|
-
# Set a header for the response. This header will be encoded to the http
|
53
|
-
# response
|
54
|
-
# Params:
|
55
|
-
# +header+:: The name of the header. e.g. "Content-Type"
|
56
|
-
# +data+:: The data to be encoded into the header. e.g. "text/html"
|
57
|
-
def header header, data
|
58
|
-
@headers[header] = data
|
59
|
-
end
|
60
|
-
|
61
|
-
# Set the Body IO object for the response. This IO object will be read from
|
62
|
-
# when the webpage is served, so usually this is a File reference or a StringIO
|
63
|
-
# +io+:: The io object to use. Not required if you just want to get the IO object
|
64
|
-
def body_io io=:get
|
65
|
-
@io = io unless io == :get
|
66
|
-
@io
|
67
|
-
end
|
68
|
-
|
69
|
-
# Append something to the Body IO. If the Body IO is a StringIO, this will usually be
|
70
|
-
# a String. This is mostly used for the 'echo' function
|
71
|
-
def append obj
|
72
|
-
@io.write obj
|
73
|
-
end
|
74
|
-
|
75
|
-
# Set the body to be a String. This will replace the BodyIO with a StringIO
|
76
|
-
# containing the string
|
77
|
-
# +str+:: The new string to replace the BodyIO with
|
78
|
-
def body str
|
79
|
-
body_io StringIO.new(str)
|
80
|
-
end
|
81
|
-
|
82
|
-
# Serve the response to the given socket. This will write the Headers, Response
|
83
|
-
# Code and Body.
|
84
|
-
def serve sock
|
85
|
-
unless done?
|
86
|
-
sock.write "HTTP/1.1 #{@status} #{@status_msg}\r\n"
|
87
|
-
@headers.each do |k, v|
|
88
|
-
sock.write "#{k}: #{v}\r\n"
|
89
|
-
end
|
90
|
-
sock.write "\r\n"
|
91
|
-
unless @io.nil?
|
92
|
-
@io.pos = 0
|
93
|
-
until @io.eof?
|
94
|
-
s = @io.read(4096)
|
95
|
-
sock.write s
|
96
|
-
end
|
97
|
-
end
|
98
|
-
done
|
99
|
-
sock.close rescue nil
|
100
|
-
@io.close rescue nil
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
end
|
105
|
-
end
|
1
|
+
module Waitress
|
2
|
+
# The response class is used to cook responses to be served to the client.
|
3
|
+
# This class contains things like response headers, status codes and the response
|
4
|
+
# body itself
|
5
|
+
class Response
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@headers = {}
|
9
|
+
status 200
|
10
|
+
default_headers
|
11
|
+
@isdone = false
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns true if the response has already been sent to the client
|
15
|
+
def done?
|
16
|
+
@isdone
|
17
|
+
end
|
18
|
+
|
19
|
+
# Mark the response as done (already sent to the client)
|
20
|
+
def done state=true
|
21
|
+
@isdone = state
|
22
|
+
end
|
23
|
+
|
24
|
+
# Apply the default headers to this response
|
25
|
+
def default_headers
|
26
|
+
header "Server", "Waitress #{Waitress::VERSION} (#{RUBY_PLATFORM})"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Apply the given Status code to the response, such as 200, 404, 500 or
|
30
|
+
# any other code listed in the HTTP protocol specification
|
31
|
+
def status status_code
|
32
|
+
@status = status_code
|
33
|
+
@status_msg = Waitress::Util.status @status
|
34
|
+
header "Status", "#{@status} #{@status_msg}"
|
35
|
+
end
|
36
|
+
|
37
|
+
# Set the mimetype (Content-Type header) of this response to the one matching
|
38
|
+
# the given file extension as matched by the +Waitress::Util+ class
|
39
|
+
# +filext+:: The file extension to match, e.g. .html, .css, .js
|
40
|
+
def mime filext
|
41
|
+
m = Waitress::Util.mime filext
|
42
|
+
header "Content-Type", m
|
43
|
+
end
|
44
|
+
|
45
|
+
# Set the mimetype (Content-Type header) of this response to the one given.
|
46
|
+
# +type+:: The mime type to use, e.g. application/json, text/html,
|
47
|
+
# application/scon
|
48
|
+
def mime_raw type
|
49
|
+
header "Content-Type", type
|
50
|
+
end
|
51
|
+
|
52
|
+
# Set a header for the response. This header will be encoded to the http
|
53
|
+
# response
|
54
|
+
# Params:
|
55
|
+
# +header+:: The name of the header. e.g. "Content-Type"
|
56
|
+
# +data+:: The data to be encoded into the header. e.g. "text/html"
|
57
|
+
def header header, data
|
58
|
+
@headers[header] = data
|
59
|
+
end
|
60
|
+
|
61
|
+
# Set the Body IO object for the response. This IO object will be read from
|
62
|
+
# when the webpage is served, so usually this is a File reference or a StringIO
|
63
|
+
# +io+:: The io object to use. Not required if you just want to get the IO object
|
64
|
+
def body_io io=:get
|
65
|
+
@io = io unless io == :get
|
66
|
+
@io
|
67
|
+
end
|
68
|
+
|
69
|
+
# Append something to the Body IO. If the Body IO is a StringIO, this will usually be
|
70
|
+
# a String. This is mostly used for the 'echo' function
|
71
|
+
def append obj
|
72
|
+
@io.write obj
|
73
|
+
end
|
74
|
+
|
75
|
+
# Set the body to be a String. This will replace the BodyIO with a StringIO
|
76
|
+
# containing the string
|
77
|
+
# +str+:: The new string to replace the BodyIO with
|
78
|
+
def body str
|
79
|
+
body_io StringIO.new(str)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Serve the response to the given socket. This will write the Headers, Response
|
83
|
+
# Code and Body.
|
84
|
+
def serve sock
|
85
|
+
unless done?
|
86
|
+
sock.write "HTTP/1.1 #{@status} #{@status_msg}\r\n"
|
87
|
+
@headers.each do |k, v|
|
88
|
+
sock.write "#{k}: #{v}\r\n"
|
89
|
+
end
|
90
|
+
sock.write "\r\n"
|
91
|
+
unless @io.nil?
|
92
|
+
@io.pos = 0
|
93
|
+
until @io.eof?
|
94
|
+
s = @io.read(4096)
|
95
|
+
sock.write s
|
96
|
+
end
|
97
|
+
end
|
98
|
+
done
|
99
|
+
sock.close rescue nil
|
100
|
+
@io.close rescue nil
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
data/lib/waitress/server.rb
CHANGED
@@ -1,161 +1,160 @@
|
|
1
|
-
require 'socket'
|
2
|
-
require 'thread'
|
3
|
-
|
4
|
-
module Waitress
|
5
|
-
|
6
|
-
# The Waitress HTTPServer. This class is responsible for handling traffic from
|
7
|
-
# clients and delegating it to the correct Virtual Host to further handle.
|
8
|
-
# New threads and Processes are spawned for each connection to the server
|
9
|
-
class HttpServer < Array
|
10
|
-
|
11
|
-
class HttpParams < Hash
|
12
|
-
attr_accessor :http_body
|
13
|
-
end
|
14
|
-
|
15
|
-
attr_accessor :processes
|
16
|
-
|
17
|
-
# Create a new Server instance with the given ports. If no ports are given,
|
18
|
-
# port 80 will be used as a default
|
19
|
-
def initialize(*ports)
|
20
|
-
|
21
|
-
ports
|
22
|
-
@
|
23
|
-
@processes =
|
24
|
-
@
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
#
|
34
|
-
#
|
35
|
-
|
36
|
-
|
37
|
-
@ports
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
#
|
42
|
-
#
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
#
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
processes
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
puts
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
ch
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
puts
|
125
|
-
|
126
|
-
end
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
headers["
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
end
|
1
|
+
require 'socket'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module Waitress
|
5
|
+
|
6
|
+
# The Waitress HTTPServer. This class is responsible for handling traffic from
|
7
|
+
# clients and delegating it to the correct Virtual Host to further handle.
|
8
|
+
# New threads and Processes are spawned for each connection to the server
|
9
|
+
class HttpServer < Array
|
10
|
+
|
11
|
+
class HttpParams < Hash
|
12
|
+
attr_accessor :http_body
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_accessor :processes
|
16
|
+
|
17
|
+
# Create a new Server instance with the given ports. If no ports are given,
|
18
|
+
# port 80 will be used as a default
|
19
|
+
def initialize(*ports)
|
20
|
+
ports << 80 if ports.length == 0
|
21
|
+
@ports = ports
|
22
|
+
@processes = 5
|
23
|
+
@processes = ENV["WAITRESS_PROCESSES"].to_i if ENV.include? "WAITRESS_PROCESSES"
|
24
|
+
@running_processes = []
|
25
|
+
end
|
26
|
+
|
27
|
+
# Set the amount of concurrent Waitress Processes to run on this Server, per Port
|
28
|
+
def set_processes count
|
29
|
+
@processes = count
|
30
|
+
end
|
31
|
+
|
32
|
+
# Set or Get the ports for this server. If arguments are provided, the ports
|
33
|
+
# for this server will be replaced with the ones listed. If no arguments are provided,
|
34
|
+
# this method simply returns the ports
|
35
|
+
def ports *ports
|
36
|
+
@ports = *ports unless ports.length == 0
|
37
|
+
@ports
|
38
|
+
end
|
39
|
+
|
40
|
+
# Start the server. If arguments are provided, it will run with the ports
|
41
|
+
# declared in the arguments, otherwise, it will use the ports it already has
|
42
|
+
# set (or 80 for the default)
|
43
|
+
def run *ports
|
44
|
+
@ports = ports unless ports.length == 0
|
45
|
+
self.each do |vhost|
|
46
|
+
vhost.on_server_start self
|
47
|
+
end
|
48
|
+
|
49
|
+
@running_processes = @ports.map do |port|
|
50
|
+
launch_port(port)
|
51
|
+
end
|
52
|
+
@running_processes.flatten!
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
# Killall running processes
|
57
|
+
def killall
|
58
|
+
@running_processes.each { |x| x.kill rescue nil }
|
59
|
+
end
|
60
|
+
|
61
|
+
# Join the server, blocking the current thread in order to keep the server alive.
|
62
|
+
def join
|
63
|
+
@running_processes.each { |x| x.wait }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Handle a client based on an IO stream, if you plan to serve on a non-socket
|
67
|
+
# connection
|
68
|
+
def read_io io
|
69
|
+
handle_client io
|
70
|
+
end
|
71
|
+
|
72
|
+
:private
|
73
|
+
def launch_port port
|
74
|
+
serv = TCPServer.new port
|
75
|
+
processes = []
|
76
|
+
@processes.times do
|
77
|
+
processes << gofork {
|
78
|
+
while true
|
79
|
+
begin
|
80
|
+
client = serv.accept
|
81
|
+
gofork do # Makes sure requires etc don't get triggered across requests
|
82
|
+
handle_client client
|
83
|
+
end.wait
|
84
|
+
client.close rescue nil
|
85
|
+
rescue => e
|
86
|
+
puts "Server Error: #{e} (Fix This!)"
|
87
|
+
puts e.backtrace
|
88
|
+
client.close rescue nil
|
89
|
+
end
|
90
|
+
end
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
processes.each do |pr|
|
95
|
+
Process.detach(pr.pid)
|
96
|
+
end
|
97
|
+
processes
|
98
|
+
end
|
99
|
+
|
100
|
+
def handle_client client_socket
|
101
|
+
# pro = gofork do
|
102
|
+
begin
|
103
|
+
data = client_socket.readpartial(8192)
|
104
|
+
nparsed = 0
|
105
|
+
|
106
|
+
parser = Waitress::HttpParser.new
|
107
|
+
params = HttpParams.new
|
108
|
+
|
109
|
+
while nparsed < data.length
|
110
|
+
nparsed = parser.execute(params, data, nparsed)
|
111
|
+
if parser.finished?
|
112
|
+
build_request params, client_socket
|
113
|
+
else
|
114
|
+
ch = client.readpartial(8192)
|
115
|
+
break if !ch or ch.length == 0
|
116
|
+
|
117
|
+
data << ch
|
118
|
+
end
|
119
|
+
end
|
120
|
+
rescue EOFError, Errno::ECONNRESET, Errno::EPIPE, Errno::EINVAL, Errno::EBADF
|
121
|
+
client_socket.close rescue nil
|
122
|
+
rescue => e
|
123
|
+
puts "Client Error: #{e}"
|
124
|
+
puts e.backtrace
|
125
|
+
end
|
126
|
+
# end
|
127
|
+
client_socket.close rescue nil
|
128
|
+
# pro.wait
|
129
|
+
end
|
130
|
+
|
131
|
+
def build_request headers, client_socket
|
132
|
+
request_headers = {}
|
133
|
+
headers.each do |k,v|
|
134
|
+
if k.start_with? "HTTP_HEAD_"
|
135
|
+
request_headers[k.sub(/HTTP_HEAD_/, "")] = v
|
136
|
+
end
|
137
|
+
end
|
138
|
+
request = Waitress::Request.new(
|
139
|
+
headers["REQUEST_METHOD"], headers["REQUEST_PATH"], headers["REQUEST_URI"],
|
140
|
+
headers["QUERY_STRING"], headers["HTTP_VERSION"], headers.http_body, request_headers
|
141
|
+
)
|
142
|
+
handle_request request, client_socket
|
143
|
+
end
|
144
|
+
|
145
|
+
def handle_request request, client
|
146
|
+
match, pri = self[0], nil
|
147
|
+
self.each do |vhost|
|
148
|
+
if (request.headers['Host'].to_s =~ vhost.domain) != nil
|
149
|
+
match = vhost if pri.nil? || vhost.priority > pri
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
if match.nil?
|
154
|
+
# Subdomain not found (or default)
|
155
|
+
else
|
156
|
+
match.handle_request request, client
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|