nyara 0.0.1.pre.5 → 0.0.1.pre.6
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.
- checksums.yaml +4 -4
- data/example/factorial.rb +19 -0
- data/ext/accept.c +2 -2
- data/ext/event.c +48 -23
- data/ext/extconf.rb +2 -0
- data/ext/hashes.c +28 -3
- data/ext/http-parser/http_parser.h +1 -0
- data/ext/nyara.c +20 -3
- data/ext/nyara.h +13 -2
- data/ext/request.c +90 -13
- data/ext/request.h +8 -2
- data/ext/request_parse.c +135 -6
- data/ext/route.cc +7 -10
- data/ext/test_response.c +155 -0
- data/ext/url_encoded.c +0 -5
- data/lib/nyara/config.rb +5 -0
- data/lib/nyara/controller.rb +91 -28
- data/lib/nyara/cookie.rb +7 -0
- data/lib/nyara/flash.rb +23 -0
- data/lib/nyara/hashes/header_hash.rb +2 -0
- data/lib/nyara/nyara.rb +14 -2
- data/lib/nyara/part.rb +156 -0
- data/lib/nyara/patches/array.rb +5 -0
- data/lib/nyara/patches/blank.rb +128 -0
- data/lib/nyara/patches/json.rb +15 -0
- data/lib/nyara/patches/mini_support.rb +6 -0
- data/lib/nyara/patches/string.rb +21 -0
- data/lib/nyara/patches/to_query.rb +113 -0
- data/lib/nyara/request.rb +13 -15
- data/lib/nyara/route.rb +15 -80
- data/lib/nyara/route_entry.rb +69 -2
- data/lib/nyara/session.rb +66 -21
- data/lib/nyara/test.rb +170 -0
- data/lib/nyara/view.rb +5 -6
- data/lib/nyara.rb +7 -6
- data/nyara.gemspec +2 -2
- data/rakefile +34 -4
- data/readme.md +8 -1
- data/spec/config_spec.rb +28 -0
- data/spec/cpu_counter_spec.rb +9 -0
- data/spec/evented_io_spec.rb +1 -0
- data/spec/flash_spec.rb +29 -0
- data/spec/hashes_spec.rb +8 -0
- data/spec/mini_support_spec.rb +54 -0
- data/spec/part_spec.rb +52 -0
- data/spec/path_helper_spec.rb +22 -14
- data/spec/request_delegate_spec.rb +19 -11
- data/spec/route_entry_spec.rb +55 -0
- data/spec/session_spec.rb +69 -7
- data/spec/spec_helper.rb +3 -0
- data/spec/test_spec.rb +58 -0
- data/tools/hello.rb +11 -3
- data/tools/memcheck.rb +33 -0
- data/tools/s.rb +11 -0
- metadata +23 -7
- data/example/design.rb +0 -62
- data/example/fib.rb +0 -15
- data/spec/route_spec.rb +0 -84
- /data/ext/inc/{status_codes.inc → status_codes.h} +0 -0
data/lib/nyara/route.rb
CHANGED
@@ -12,52 +12,46 @@ module Nyara
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def compile
|
15
|
-
global_path_templates = {} # "name#id" => path
|
16
|
-
|
15
|
+
@global_path_templates = {} # "name#id" => path
|
16
|
+
mapped_controllers = {}
|
17
17
|
|
18
|
-
|
18
|
+
route_entries = @controllers.flat_map do |scope, c|
|
19
19
|
if c.is_a?(String)
|
20
20
|
c = name2const c
|
21
21
|
end
|
22
22
|
name = c.controller_name || const2name(c)
|
23
23
|
raise "#{c.inspect} is not a Nyara::Controller" unless Controller > c
|
24
24
|
|
25
|
-
if
|
25
|
+
if mapped_controllers[c]
|
26
26
|
raise "controller #{c.inspect} was already mapped"
|
27
27
|
end
|
28
|
+
mapped_controllers[c] = true
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
route_entries.each do |e|
|
32
|
-
id = e.id.to_s
|
33
|
-
path = File.join scope, e.path
|
34
|
-
global_path_templates[name + id] = path
|
35
|
-
@path_templates[c][id] = path
|
30
|
+
c.compile_route_entries(scope).each do |e|
|
31
|
+
@global_path_templates[name + e.id] = e.path_template
|
36
32
|
end
|
37
|
-
|
38
|
-
[scope, c, route_entries]
|
39
33
|
end
|
34
|
+
route_entries.sort_by! &:prefix
|
35
|
+
route_entries.reverse!
|
40
36
|
|
41
|
-
|
42
|
-
|
37
|
+
mapped_controllers.each do |c, _|
|
38
|
+
c.path_templates = @global_path_templates.merge c.path_templates
|
43
39
|
end
|
44
40
|
|
45
41
|
Ext.clear_route
|
46
|
-
|
47
|
-
|
48
|
-
Ext.register_route entry
|
42
|
+
route_entries.each do |e|
|
43
|
+
Ext.register_route e
|
49
44
|
end
|
50
45
|
end
|
51
46
|
|
52
|
-
def
|
53
|
-
@
|
47
|
+
def global_path_template id
|
48
|
+
@global_path_templates[id]
|
54
49
|
end
|
55
50
|
|
56
51
|
def clear
|
57
52
|
# gc mark fail if wrong order?
|
58
53
|
Ext.clear_route
|
59
54
|
@controllers = {}
|
60
|
-
@path_templates = {}
|
61
55
|
end
|
62
56
|
|
63
57
|
# private
|
@@ -75,64 +69,5 @@ module Nyara
|
|
75
69
|
name << 'Controller'
|
76
70
|
Module.const_get name
|
77
71
|
end
|
78
|
-
|
79
|
-
def process preprocessed
|
80
|
-
entries = []
|
81
|
-
preprocessed.each do |(scope, controller, route_entries)|
|
82
|
-
route_entries.each do |e|
|
83
|
-
e = e.dup # in case there is controller used in more than 1 maps
|
84
|
-
path = scope.sub /\/?$/, e.path
|
85
|
-
if path.empty?
|
86
|
-
path = '/'
|
87
|
-
end
|
88
|
-
e.prefix, suffix = analyse_path path
|
89
|
-
e.suffix, e.conv = compile_re suffix
|
90
|
-
e.scope = scope
|
91
|
-
e.controller = controller
|
92
|
-
entries << e
|
93
|
-
end
|
94
|
-
end
|
95
|
-
entries.sort_by! &:prefix
|
96
|
-
entries.reverse!
|
97
|
-
entries
|
98
|
-
end
|
99
|
-
|
100
|
-
# returns [str_re, conv]
|
101
|
-
def compile_re suffix
|
102
|
-
return ['', []] unless suffix
|
103
|
-
conv = []
|
104
|
-
re_segs = suffix.split(/(?<=%[dfsux])|(?=%[dfsux])/).map do |s|
|
105
|
-
case s
|
106
|
-
when '%d'
|
107
|
-
conv << :to_i
|
108
|
-
'(-?[0-9]+)'
|
109
|
-
when '%f'
|
110
|
-
conv << :to_f
|
111
|
-
# just copied from scanf
|
112
|
-
'([-+]?(?:0[xX](?:\.\h+|\h+(?:\.\h*)?)[pP][-+]\d+|\d+(?![\d.])|\d*\.\d*(?:[eE][-+]?\d+)?))'
|
113
|
-
when '%u'
|
114
|
-
conv << :to_i
|
115
|
-
'([0-9]+)'
|
116
|
-
when '%x'
|
117
|
-
conv << :hex
|
118
|
-
'(\h+)'
|
119
|
-
when '%s'
|
120
|
-
conv << :to_s
|
121
|
-
'([^/]+)'
|
122
|
-
else
|
123
|
-
Regexp.quote s
|
124
|
-
end
|
125
|
-
end
|
126
|
-
["^#{re_segs.join}$", conv]
|
127
|
-
end
|
128
|
-
|
129
|
-
# split the path into parts
|
130
|
-
def analyse_path path
|
131
|
-
raise 'path must contain no new line' if path.index "\n"
|
132
|
-
raise 'path must start with /' unless path.start_with? '/'
|
133
|
-
path = path.sub(/\/$/, '') if path != '/'
|
134
|
-
|
135
|
-
path.split(/(?=%[dfsux])/, 2)
|
136
|
-
end
|
137
72
|
end
|
138
73
|
end
|
data/lib/nyara/route_entry.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
module Nyara
|
2
2
|
class RouteEntry
|
3
3
|
REQUIRED_ATTRS = [:http_method, :scope, :prefix, :suffix, :controller, :id, :conv]
|
4
|
-
|
4
|
+
attr_reader *REQUIRED_ATTRS
|
5
|
+
attr_writer :http_method, :id
|
6
|
+
# stores symbol for C conenience, and returns string for Ruby side goodness
|
7
|
+
def id
|
8
|
+
@id.to_s
|
9
|
+
end
|
5
10
|
|
6
11
|
# optional
|
7
12
|
attr_accessor :accept_exts, :accept_mimes
|
@@ -13,6 +18,25 @@ module Nyara
|
|
13
18
|
instance_eval &p if p
|
14
19
|
end
|
15
20
|
|
21
|
+
def path_template
|
22
|
+
File.join @scope, (@path.gsub '%z', '%s')
|
23
|
+
end
|
24
|
+
|
25
|
+
# compute prefix, suffix, conv
|
26
|
+
# NOTE route_entries may be inherited, so late-setting controller is necessary
|
27
|
+
def compile controller, scope
|
28
|
+
@controller = controller
|
29
|
+
@scope = scope
|
30
|
+
|
31
|
+
path = scope.sub /\/?$/, @path
|
32
|
+
if path.empty?
|
33
|
+
path = '/'
|
34
|
+
end
|
35
|
+
@prefix, suffix = analyse_path path
|
36
|
+
@suffix, @conv = compile_re suffix
|
37
|
+
end
|
38
|
+
|
39
|
+
# compute accept_exts, accept_mimes
|
16
40
|
def set_accept_exts a
|
17
41
|
@accept_exts = {}
|
18
42
|
@accept_mimes = []
|
@@ -37,7 +61,50 @@ module Nyara
|
|
37
61
|
raise ArgumentError, "missing #{attr}"
|
38
62
|
end
|
39
63
|
end
|
40
|
-
raise ArgumentError, "id must be symbol" unless id.is_a?(Symbol)
|
64
|
+
raise ArgumentError, "id must be symbol" unless @id.is_a?(Symbol)
|
65
|
+
end
|
66
|
+
|
67
|
+
# private
|
68
|
+
|
69
|
+
# returns [str_re, conv]
|
70
|
+
def compile_re suffix
|
71
|
+
return ['', []] unless suffix
|
72
|
+
conv = []
|
73
|
+
re_segs = suffix.split(/(?<=%[dfsux])|(?=%[dfsux])/).map do |s|
|
74
|
+
case s
|
75
|
+
when '%d'
|
76
|
+
conv << :to_i
|
77
|
+
'(-?[0-9]+)'
|
78
|
+
when '%f'
|
79
|
+
conv << :to_f
|
80
|
+
# just copied from scanf
|
81
|
+
'([-+]?(?:0[xX](?:\.\h+|\h+(?:\.\h*)?)[pP][-+]\d+|\d+(?![\d.])|\d*\.\d*(?:[eE][-+]?\d+)?))'
|
82
|
+
when '%u'
|
83
|
+
conv << :to_i
|
84
|
+
'([0-9]+)'
|
85
|
+
when '%x'
|
86
|
+
conv << :hex
|
87
|
+
'(\h+)'
|
88
|
+
when '%s'
|
89
|
+
conv << :to_s
|
90
|
+
'([^/]+)'
|
91
|
+
when '%z'
|
92
|
+
conv << :to_s
|
93
|
+
'(.+)'
|
94
|
+
else
|
95
|
+
Regexp.quote s
|
96
|
+
end
|
97
|
+
end
|
98
|
+
["^#{re_segs.join}$", conv]
|
99
|
+
end
|
100
|
+
|
101
|
+
# split the path into parts
|
102
|
+
def analyse_path path
|
103
|
+
raise 'path must contain no new line' if path.index "\n"
|
104
|
+
raise 'path must start with /' unless path.start_with? '/'
|
105
|
+
path = path.sub(/\/$/, '') if path != '/'
|
106
|
+
|
107
|
+
path.split(/(?=%[dfsux])/, 2)
|
41
108
|
end
|
42
109
|
end
|
43
110
|
end
|
data/lib/nyara/session.rb
CHANGED
@@ -1,42 +1,74 @@
|
|
1
1
|
module Nyara
|
2
|
-
# cookie based
|
3
|
-
# usually it's no need to call cache or database data a "session"
|
2
|
+
# helper module for session management, cookie based<br>
|
3
|
+
# (usually it's no need to call cache or database data a "session")<br><br>
|
4
|
+
# session is by default DSA + SHA2/SHA1 signed, sub config options are:
|
5
|
+
#
|
6
|
+
# [name] session entry name in cookie, default is +'spare_me_plz'+
|
7
|
+
# [expire] expire session after seconds. default is +nil+, which means session expires when browser is closed<br>
|
8
|
+
# [expires] same as +expire+
|
9
|
+
# [secure] - +nil+(default): if request is https, add +Secure+ option to it
|
10
|
+
# - +true+: always add +Secure+
|
11
|
+
# - +false+: always no +Secure+
|
12
|
+
# [key] DSA private key string, in der or pem format, use random if not given
|
13
|
+
# [cipher_key] if exist, use aes-256-cbc to cipher the "sig/json"<br>
|
14
|
+
# NOTE: it's no need to set +cipher_key+ if using https
|
15
|
+
#
|
16
|
+
# = example
|
17
|
+
#
|
18
|
+
# configure do
|
19
|
+
# set 'session', 'key', File.read(project_path 'config/session.key')
|
20
|
+
# set 'session', 'expire', 30 * 60
|
21
|
+
# end
|
22
|
+
#
|
4
23
|
module Session
|
5
24
|
extend self
|
6
25
|
|
7
26
|
CIPHER_BLOCK_SIZE = 256/8
|
8
27
|
|
9
|
-
# session is by default DSA + SHA2/SHA1 signed, sub config options are:
|
10
|
-
#
|
11
|
-
# - name (session entry name in cookie, default is 'spare_me_plz')
|
12
|
-
# - key (DSA private key string, in der or pem format, use random if not given)
|
13
|
-
# - cipher_key (if exist, use aes-256-cbc to cipher the "sig&json", the first 256bit is sliced for iv)
|
14
|
-
# (it's no need to set cipher_key if using https)
|
15
|
-
|
16
28
|
# init from config
|
17
29
|
def init
|
18
|
-
c = Config['session']
|
19
|
-
@name = (c
|
30
|
+
c = Config['session'] ? Config['session'].dup : {}
|
31
|
+
@name = (c.delete('name') || 'spare_me_plz').to_s
|
20
32
|
|
21
33
|
if c['key']
|
22
|
-
@dsa = OpenSSL::PKey::DSA.new c
|
34
|
+
@dsa = OpenSSL::PKey::DSA.new c.delete 'key'
|
23
35
|
else
|
24
|
-
@dsa =
|
36
|
+
@dsa = generate_key
|
25
37
|
end
|
26
38
|
|
27
39
|
# DSA can sign on any digest since 1.0.0
|
28
40
|
@dss = OpenSSL::VERSION >= '1.0.0' ? OpenSSL::Digest::SHA256 : OpenSSL::Digest::DSS1
|
29
41
|
|
30
|
-
@cipher_key = pad_256_bit c
|
42
|
+
@cipher_key = pad_256_bit c.delete 'cipher_key'
|
43
|
+
|
44
|
+
@expire = c.delete('expire') || c.delete('expires')
|
45
|
+
@secure = c.delete('secure')
|
46
|
+
|
47
|
+
unless c.empty?
|
48
|
+
raise "unknown options in Nyara::Config[:session]: #{c.inspect}"
|
49
|
+
end
|
31
50
|
end
|
32
51
|
|
33
52
|
attr_reader :name
|
34
53
|
|
35
|
-
|
54
|
+
# encode into a cookie hash, for test environment
|
55
|
+
def encode_to_cookie h, cookie
|
56
|
+
cookie[@name] = encode h
|
57
|
+
end
|
58
|
+
|
59
|
+
# encode to value
|
60
|
+
def encode h
|
36
61
|
str = h.to_json
|
37
62
|
sig = @dsa.syssign @dss.digest str
|
38
|
-
str = "#{
|
39
|
-
|
63
|
+
str = "#{encode64 sig}/#{encode64 str}"
|
64
|
+
@cipher_key ? cipher(str) : str
|
65
|
+
end
|
66
|
+
|
67
|
+
# encode as header line
|
68
|
+
def encode_set_cookie h, secure
|
69
|
+
secure = @secure unless @secure.nil?
|
70
|
+
expire = (Time.now + @expire).gmtime.rfc2822 if @expire
|
71
|
+
"Set-Cookie: #{@name}=#{encode h}; HttpOnly#{'; Secure' if secure}#{"; Expires=#{expire}" if expire}\r\n"
|
40
72
|
end
|
41
73
|
|
42
74
|
def decode cookie
|
@@ -44,11 +76,12 @@ module Nyara
|
|
44
76
|
return empty_hash if str.empty?
|
45
77
|
|
46
78
|
str = decipher(str) if @cipher_key
|
47
|
-
sig, str = str.split '
|
79
|
+
sig, str = str.split '/', 2
|
48
80
|
return empty_hash unless str
|
49
81
|
|
50
82
|
begin
|
51
|
-
sig =
|
83
|
+
sig = decode64 sig
|
84
|
+
str = decode64 str
|
52
85
|
verified = @dsa.sysverify @dss.digest(str), sig
|
53
86
|
if verified
|
54
87
|
h = JSON.parse str, create_additions: false, object_class: ParamHash
|
@@ -64,16 +97,28 @@ module Nyara
|
|
64
97
|
end
|
65
98
|
end
|
66
99
|
|
100
|
+
def generate_key
|
101
|
+
OpenSSL::PKey::DSA.generate 256
|
102
|
+
end
|
103
|
+
|
67
104
|
# private
|
68
105
|
|
106
|
+
def encode64 s
|
107
|
+
[s].pack('m0').tr("+/", "-_")
|
108
|
+
end
|
109
|
+
|
110
|
+
def decode64 s
|
111
|
+
s.tr("-_", "+/").unpack('m0').first
|
112
|
+
end
|
113
|
+
|
69
114
|
def cipher str
|
70
115
|
iv = rand(36**CIPHER_BLOCK_SIZE).to_s(36).ljust CIPHER_BLOCK_SIZE
|
71
116
|
c = new_cipher true, iv
|
72
|
-
|
117
|
+
encode64(iv.dup << c.update(str) << c.final)
|
73
118
|
end
|
74
119
|
|
75
120
|
def decipher str
|
76
|
-
str =
|
121
|
+
str = decode64 str
|
77
122
|
iv = str.byteslice 0...CIPHER_BLOCK_SIZE
|
78
123
|
str = str.byteslice CIPHER_BLOCK_SIZE..-1
|
79
124
|
return '' if !str or str.empty?
|
data/lib/nyara/test.rb
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
module Nyara
|
2
|
+
# test helper
|
3
|
+
module Test
|
4
|
+
class Response
|
5
|
+
# whether request is success
|
6
|
+
def success?
|
7
|
+
status < 400
|
8
|
+
end
|
9
|
+
|
10
|
+
def redirect_location
|
11
|
+
if HTTP_REDIRECT_STATUS.include?(status)
|
12
|
+
header['Location']
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# C-ext methods: header, body, status, initialize(data), set_cookies
|
17
|
+
end
|
18
|
+
|
19
|
+
Env = Struct.new :cookie, :session, :request, :controller, :response, :response_size_limit
|
20
|
+
class Env
|
21
|
+
# :call-seq:
|
22
|
+
#
|
23
|
+
# # change size limit of response data to 100M:
|
24
|
+
# @_env = Env.new 10**8
|
25
|
+
#
|
26
|
+
def initialize response_size_limit=5_000_000
|
27
|
+
self.response_size_limit = response_size_limit
|
28
|
+
self.cookie = ParamHash.new
|
29
|
+
self.session = ParamHash.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def process_request_data data
|
33
|
+
client, server = Socket.pair :UNIX, :STREAM
|
34
|
+
self.request = Ext.request_new
|
35
|
+
Ext.request_set_fd request, server.fileno
|
36
|
+
|
37
|
+
client << data
|
38
|
+
self.controller = Ext.handle_request request
|
39
|
+
response_data = client.read_nonblock response_size_limit
|
40
|
+
self.response = Response.new response_data
|
41
|
+
|
42
|
+
# merge session
|
43
|
+
session.clear
|
44
|
+
session.merge! request.session
|
45
|
+
|
46
|
+
# merge Set-Cookie
|
47
|
+
response.set_cookies.each do |cookie_seg|
|
48
|
+
# todo distinguish delete, value and set
|
49
|
+
Ext.parse_url_encoded_seg cookie, cookie_seg, false
|
50
|
+
end
|
51
|
+
|
52
|
+
server.close
|
53
|
+
client.close
|
54
|
+
end
|
55
|
+
|
56
|
+
def http meth, path, headers={}, body_string_or_hash=''
|
57
|
+
headers = (headers || {}).dup
|
58
|
+
|
59
|
+
# serialize body
|
60
|
+
# todo build multipart for file
|
61
|
+
if body_string_or_hash.is_a?(Hash)
|
62
|
+
body = body_string_or_hash.to_param
|
63
|
+
headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
64
|
+
else
|
65
|
+
body = body_string_or_hash.to_s
|
66
|
+
headers['Content-Type'] ||= 'text/plain'
|
67
|
+
end
|
68
|
+
if body.bytesize > 0
|
69
|
+
headers['Content-Length'] = body.bytesize
|
70
|
+
end
|
71
|
+
|
72
|
+
# serialize cookie / session
|
73
|
+
if headers['Cookie']
|
74
|
+
cookie.clear
|
75
|
+
cookie.merge! Cookie.decode headers
|
76
|
+
end
|
77
|
+
Session.encode_to_cookie session, cookie
|
78
|
+
headers['Cookie'] = Cookie.encode cookie
|
79
|
+
|
80
|
+
request_data = ["#{meth.upcase} #{path} HTTP/1.1\r\n"]
|
81
|
+
headers.each do |k, v|
|
82
|
+
request_data << "#{k}: #{v}\r\n"
|
83
|
+
end
|
84
|
+
request_data << "\r\n"
|
85
|
+
request_data << body
|
86
|
+
process_request_data request_data.join
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def env
|
91
|
+
@_env ||= Env.new
|
92
|
+
end
|
93
|
+
|
94
|
+
# :call-seq:
|
95
|
+
#
|
96
|
+
# get '/', headers
|
97
|
+
#
|
98
|
+
def get path, header={}, body_string_or_hash=""
|
99
|
+
env.http 'GET', path, header, body_string_or_hash
|
100
|
+
end
|
101
|
+
|
102
|
+
# :call-seq:
|
103
|
+
#
|
104
|
+
# post '/', {}, page: 3
|
105
|
+
# post '/', { 'content-type' => 'application/json' }, '{"page":3}'
|
106
|
+
#
|
107
|
+
def post path, header={}, body_string_or_hash=""
|
108
|
+
env.http 'POST', path, header, body_string_or_hash
|
109
|
+
end
|
110
|
+
|
111
|
+
def put path, header={}, body_string_or_hash=""
|
112
|
+
env.http 'PUT', path, header, body_string_or_hash
|
113
|
+
end
|
114
|
+
|
115
|
+
def delete path, header={}, body_string_or_hash=""
|
116
|
+
env.http 'DELETE', path, header, body_string_or_hash
|
117
|
+
end
|
118
|
+
|
119
|
+
def patch path, header={}, body_string_or_hash=""
|
120
|
+
env.http 'PATCH', path, header, body_string_or_hash
|
121
|
+
end
|
122
|
+
|
123
|
+
def options path, header={}, body_string_or_hash=""
|
124
|
+
env.http 'OPTIONS', path, header, body_string_or_hash
|
125
|
+
end
|
126
|
+
|
127
|
+
def path_to id, *args
|
128
|
+
# similar to Controller#path_to, but without local query
|
129
|
+
if args.last.is_a?(Hash)
|
130
|
+
opts = args.pop
|
131
|
+
end
|
132
|
+
|
133
|
+
r = Route.global_path_template(id) % args
|
134
|
+
|
135
|
+
if opts
|
136
|
+
format = opts.delete :format
|
137
|
+
r << ".#{format}" if format
|
138
|
+
r << '?' << opts.to_param unless query.empty?
|
139
|
+
end
|
140
|
+
r
|
141
|
+
end
|
142
|
+
|
143
|
+
def cookie
|
144
|
+
env.cookie
|
145
|
+
end
|
146
|
+
|
147
|
+
def session
|
148
|
+
env.session
|
149
|
+
end
|
150
|
+
|
151
|
+
def request
|
152
|
+
env.request
|
153
|
+
end
|
154
|
+
|
155
|
+
def response
|
156
|
+
env.response
|
157
|
+
end
|
158
|
+
|
159
|
+
def redirect_location
|
160
|
+
env.response.redirect_location
|
161
|
+
end
|
162
|
+
|
163
|
+
def follow_redirect
|
164
|
+
# todo validate scheme and host
|
165
|
+
u = URI.parse(redirect_location)
|
166
|
+
path = [u.path, u.query].compact.join '?'
|
167
|
+
get path
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
data/lib/nyara/view.rb
CHANGED
@@ -42,7 +42,7 @@ module Nyara
|
|
42
42
|
end
|
43
43
|
attr_reader :root
|
44
44
|
|
45
|
-
# +path+ needs extension
|
45
|
+
# NOTE: +path+ needs extension
|
46
46
|
def on_delete path
|
47
47
|
meth = path2meth path
|
48
48
|
Renderable.class_eval do
|
@@ -64,7 +64,7 @@ module Nyara
|
|
64
64
|
@meth2ext.clear
|
65
65
|
end
|
66
66
|
|
67
|
-
# +path+ needs extension
|
67
|
+
# NOTE: +path+ needs extension<br>
|
68
68
|
# returns dot_ext for further use
|
69
69
|
def on_update path
|
70
70
|
meth = path2meth path
|
@@ -108,7 +108,7 @@ module Nyara
|
|
108
108
|
line = 1
|
109
109
|
|
110
110
|
if stream_friendly
|
111
|
-
Renderable.class_eval <<-RUBY, __FILE__, __LINE__
|
111
|
+
Renderable.class_eval <<-RUBY, __FILE__, __LINE__
|
112
112
|
def render locals={}
|
113
113
|
@_nyara_locals = locals
|
114
114
|
src = locals.map{|k, _| "\#{k} = @_nyara_locals[:\#{k}];" }.join
|
@@ -119,7 +119,7 @@ module Nyara
|
|
119
119
|
RUBY
|
120
120
|
ENGINE_STREAM_FRIENDLY[ext] = true
|
121
121
|
else
|
122
|
-
Renderable.class_eval <<-RUBY, __FILE__, __LINE__
|
122
|
+
Renderable.class_eval <<-RUBY, __FILE__, __LINE__
|
123
123
|
def render locals=nil
|
124
124
|
Tilt[#{ext.inspect}].new(#{file}, #{line}){ @_nyara_view.in }.render self, locals
|
125
125
|
end
|
@@ -278,8 +278,7 @@ RUBY
|
|
278
278
|
Fiber.yield :term_close
|
279
279
|
end
|
280
280
|
|
281
|
-
# :nodoc:
|
282
|
-
def _render
|
281
|
+
def _render # :nodoc:
|
283
282
|
t, _ = @rest_layouts.pop
|
284
283
|
if @rest_layouts.empty?
|
285
284
|
@instance.send t, @locals
|
data/lib/nyara.rb
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
# auto run
|
2
2
|
require_relative "nyara/nyara"
|
3
3
|
|
4
|
-
|
5
|
-
Nyara
|
6
|
-
|
7
|
-
|
8
|
-
end
|
4
|
+
END {
|
5
|
+
if $!.nil? and !Nyara.config.test?
|
6
|
+
Nyara.setup
|
7
|
+
Nyara.start_server
|
8
|
+
end
|
9
|
+
}
|
9
10
|
|
10
11
|
module Nyara
|
11
12
|
class SimpleController < Controller
|
12
13
|
end
|
13
14
|
end
|
14
15
|
|
15
|
-
%w[on tag get post put delete patch options].each do |m|
|
16
|
+
%w[on tag get post put delete patch options meta].each do |m|
|
16
17
|
eval <<-RUBY
|
17
18
|
def #{m} *xs, &blk
|
18
19
|
Nyara::SimpleController.#{m} *xs, &blk
|
data/nyara.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "nyara"
|
3
|
-
s.version = "0.0.1.pre.
|
3
|
+
s.version = "0.0.1.pre.6"
|
4
4
|
s.author = "Zete Lui"
|
5
5
|
s.email = "nobody@example.com"
|
6
6
|
s.homepage = "https://github.com/luikore/nyara"
|
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.summary = "Fast, slim and fuzzy ruby web framework + server"
|
9
9
|
s.description = "Fast, slim and fuzzy ruby web framework + server, based on preforked event queue and Fiber. NO rack NOR eventmachine are used."
|
10
10
|
s.required_ruby_version = ">=2.0.0"
|
11
|
-
s.licenses = ['BSD']
|
11
|
+
s.licenses = ['BSD 3-Clause']
|
12
12
|
|
13
13
|
s.files = Dir.glob('{rakefile,nyara.gemspec,readme.md,**/*.{rb,h,c,cc,inc}}')
|
14
14
|
s.files += Dir.glob('ext/http-parser/{AUTHORS,CONTRIBUTIONS,LICENSE-MIT}')
|
data/rakefile
CHANGED
@@ -2,13 +2,13 @@ require "rake"
|
|
2
2
|
|
3
3
|
Dir.chdir __dir__
|
4
4
|
|
5
|
-
status_file = "ext/inc/status_codes.
|
5
|
+
status_file = "ext/inc/status_codes.h"
|
6
6
|
version_file = "ext/inc/version.inc"
|
7
7
|
makefile = "ext/Makefile"
|
8
8
|
extconf = "ext/extconf.rb"
|
9
9
|
|
10
10
|
desc "code generate"
|
11
|
-
task :gen => [
|
11
|
+
task :gen => [version_file]
|
12
12
|
|
13
13
|
desc "generate #{status_file}"
|
14
14
|
file status_file => __FILE__ do
|
@@ -47,6 +47,7 @@ end
|
|
47
47
|
desc "generate makefile"
|
48
48
|
file makefile => extconf do
|
49
49
|
Dir.chdir 'ext' do
|
50
|
+
sh 'make clean' if File.exist?('Makefile')
|
50
51
|
sh 'ruby extconf.rb'
|
51
52
|
end
|
52
53
|
end
|
@@ -112,14 +113,20 @@ end
|
|
112
113
|
desc "list Nyara::Ext methods"
|
113
114
|
task :list_ext do
|
114
115
|
require_relative "lib/nyara/nyara"
|
116
|
+
puts_methods = lambda{|methods|
|
117
|
+
methods.each do |m|
|
118
|
+
puts "#{m} /#{Nyara::Ext.method(m).arity}"
|
119
|
+
end
|
120
|
+
}
|
121
|
+
|
115
122
|
methods = (Nyara::Ext.methods - Module.methods).sort
|
116
123
|
[/queue/, /route/, /parse/, /request/].each do |r|
|
117
124
|
group = methods.grep r
|
118
|
-
|
125
|
+
puts_methods[group]
|
119
126
|
puts
|
120
127
|
methods -= group
|
121
128
|
end
|
122
|
-
|
129
|
+
puts_methods[methods]
|
123
130
|
end
|
124
131
|
|
125
132
|
def term_color n
|
@@ -158,3 +165,26 @@ task :audit_arity do
|
|
158
165
|
end
|
159
166
|
end
|
160
167
|
end
|
168
|
+
|
169
|
+
desc "audit http_parser / multipart_parser struct size, they should be dividable by 8 so that Request fields are aligned"
|
170
|
+
task :audit_sizeof_parsers do
|
171
|
+
require "mkmf"
|
172
|
+
$CFLAGS << " -Iext/http-parser -Iext/multipart-parser-c"
|
173
|
+
{
|
174
|
+
'http_parser' => 'http_parser.h',
|
175
|
+
'multipart_parser*' => 'multipart_parser.h' # multipart_parser is opaque -_-
|
176
|
+
}.each do |struct, header|
|
177
|
+
have_header header
|
178
|
+
res = check_sizeof(struct, header)
|
179
|
+
if res and res % 8 == 0
|
180
|
+
puts "OK"
|
181
|
+
else
|
182
|
+
term_color 9
|
183
|
+
print "Need padding"
|
184
|
+
reset_color
|
185
|
+
puts
|
186
|
+
end
|
187
|
+
puts
|
188
|
+
end
|
189
|
+
sh 'rm', 'mkmf.log'
|
190
|
+
end
|