itsi 0.1.14 → 0.1.19
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/Cargo.lock +126 -272
- data/Cargo.toml +6 -0
- data/crates/itsi_error/Cargo.toml +1 -0
- data/crates/itsi_error/src/lib.rs +100 -10
- data/crates/itsi_scheduler/src/itsi_scheduler.rs +1 -1
- data/crates/itsi_server/Cargo.toml +12 -11
- data/crates/itsi_server/src/default_responses/html/401.html +68 -0
- data/crates/itsi_server/src/default_responses/html/403.html +68 -0
- data/crates/itsi_server/src/default_responses/html/404.html +68 -0
- data/crates/itsi_server/src/default_responses/html/413.html +71 -0
- data/crates/itsi_server/src/default_responses/html/429.html +68 -0
- data/crates/itsi_server/src/default_responses/html/500.html +71 -0
- data/crates/itsi_server/src/default_responses/html/502.html +71 -0
- data/crates/itsi_server/src/default_responses/html/503.html +68 -0
- data/crates/itsi_server/src/default_responses/html/504.html +69 -0
- data/crates/itsi_server/src/default_responses/html/index.html +238 -0
- data/crates/itsi_server/src/default_responses/json/401.json +6 -0
- data/crates/itsi_server/src/default_responses/json/403.json +6 -0
- data/crates/itsi_server/src/default_responses/json/404.json +6 -0
- data/crates/itsi_server/src/default_responses/json/413.json +6 -0
- data/crates/itsi_server/src/default_responses/json/429.json +6 -0
- data/crates/itsi_server/src/default_responses/json/500.json +6 -0
- data/crates/itsi_server/src/default_responses/json/502.json +6 -0
- data/crates/itsi_server/src/default_responses/json/503.json +6 -0
- data/crates/itsi_server/src/default_responses/json/504.json +6 -0
- data/crates/itsi_server/src/default_responses/mod.rs +11 -0
- data/crates/itsi_server/src/lib.rs +58 -26
- data/crates/itsi_server/src/prelude.rs +2 -0
- data/crates/itsi_server/src/ruby_types/README.md +21 -0
- data/crates/itsi_server/src/ruby_types/itsi_body_proxy/mod.rs +8 -6
- data/crates/itsi_server/src/ruby_types/itsi_grpc_call.rs +344 -0
- data/crates/itsi_server/src/ruby_types/{itsi_grpc_stream → itsi_grpc_response_stream}/mod.rs +121 -73
- data/crates/itsi_server/src/ruby_types/itsi_http_request.rs +103 -40
- data/crates/itsi_server/src/ruby_types/itsi_http_response.rs +8 -5
- data/crates/itsi_server/src/ruby_types/itsi_server/file_watcher.rs +4 -4
- data/crates/itsi_server/src/ruby_types/itsi_server/itsi_server_config.rs +37 -17
- data/crates/itsi_server/src/ruby_types/itsi_server.rs +4 -3
- data/crates/itsi_server/src/ruby_types/mod.rs +6 -13
- data/crates/itsi_server/src/server/{bind.rs → binds/bind.rs} +23 -4
- data/crates/itsi_server/src/server/{listener.rs → binds/listener.rs} +24 -10
- data/crates/itsi_server/src/server/binds/mod.rs +4 -0
- data/crates/itsi_server/src/server/{tls.rs → binds/tls.rs} +9 -4
- data/crates/itsi_server/src/server/http_message_types.rs +97 -0
- data/crates/itsi_server/src/server/io_stream.rs +2 -1
- data/crates/itsi_server/src/server/middleware_stack/middleware.rs +28 -16
- data/crates/itsi_server/src/server/middleware_stack/middlewares/allow_list.rs +17 -8
- data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_api_key.rs +47 -18
- data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_basic.rs +13 -9
- data/crates/itsi_server/src/server/middleware_stack/middlewares/auth_jwt.rs +50 -29
- data/crates/itsi_server/src/server/middleware_stack/middlewares/cache_control.rs +5 -2
- data/crates/itsi_server/src/server/middleware_stack/middlewares/compression.rs +37 -48
- data/crates/itsi_server/src/server/middleware_stack/middlewares/cors.rs +25 -20
- data/crates/itsi_server/src/server/middleware_stack/middlewares/deny_list.rs +14 -7
- data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response/default_responses.rs +190 -0
- data/crates/itsi_server/src/server/middleware_stack/middlewares/error_response.rs +125 -95
- data/crates/itsi_server/src/server/middleware_stack/middlewares/etag.rs +9 -5
- data/crates/itsi_server/src/server/middleware_stack/middlewares/header_interpretation.rs +1 -4
- data/crates/itsi_server/src/server/middleware_stack/middlewares/intrusion_protection.rs +25 -19
- data/crates/itsi_server/src/server/middleware_stack/middlewares/log_requests.rs +4 -4
- data/crates/itsi_server/src/server/middleware_stack/middlewares/max_body.rs +47 -0
- data/crates/itsi_server/src/server/middleware_stack/middlewares/mod.rs +9 -4
- data/crates/itsi_server/src/server/middleware_stack/middlewares/proxy.rs +260 -62
- data/crates/itsi_server/src/server/middleware_stack/middlewares/rate_limit.rs +29 -22
- data/crates/itsi_server/src/server/middleware_stack/middlewares/redirect.rs +6 -6
- data/crates/itsi_server/src/server/middleware_stack/middlewares/request_headers.rs +6 -5
- data/crates/itsi_server/src/server/middleware_stack/middlewares/response_headers.rs +4 -2
- data/crates/itsi_server/src/server/middleware_stack/middlewares/ruby_app.rs +51 -18
- data/crates/itsi_server/src/server/middleware_stack/middlewares/static_assets.rs +31 -13
- data/crates/itsi_server/src/server/middleware_stack/middlewares/static_response.rs +55 -0
- data/crates/itsi_server/src/server/middleware_stack/middlewares/string_rewrite.rs +13 -8
- data/crates/itsi_server/src/server/middleware_stack/mod.rs +101 -69
- data/crates/itsi_server/src/server/mod.rs +3 -9
- data/crates/itsi_server/src/server/process_worker.rs +21 -3
- data/crates/itsi_server/src/server/request_job.rs +2 -2
- data/crates/itsi_server/src/server/serve_strategy/cluster_mode.rs +8 -3
- data/crates/itsi_server/src/server/serve_strategy/single_mode.rs +26 -26
- data/crates/itsi_server/src/server/signal.rs +24 -41
- data/crates/itsi_server/src/server/size_limited_incoming.rs +101 -0
- data/crates/itsi_server/src/server/thread_worker.rs +59 -28
- data/crates/itsi_server/src/services/itsi_http_service.rs +239 -0
- data/crates/itsi_server/src/services/mime_types.rs +1416 -0
- data/crates/itsi_server/src/services/mod.rs +6 -0
- data/crates/itsi_server/src/services/password_hasher.rs +83 -0
- data/crates/itsi_server/src/{server → services}/rate_limiter.rs +35 -31
- data/crates/itsi_server/src/{server → services}/static_file_server.rs +521 -181
- data/crates/itsi_tracing/src/lib.rs +145 -55
- data/{Itsi.rb → foo/Itsi.rb} +6 -9
- data/gems/scheduler/Cargo.lock +7 -0
- data/gems/scheduler/lib/itsi/scheduler/version.rb +1 -1
- data/gems/scheduler/test/helpers/test_helper.rb +0 -1
- data/gems/scheduler/test/test_address_resolve.rb +0 -1
- data/gems/scheduler/test/test_network_io.rb +1 -1
- data/gems/scheduler/test/test_process_wait.rb +0 -1
- data/gems/server/Cargo.lock +126 -272
- data/gems/server/exe/itsi +65 -19
- data/gems/server/itsi-server.gemspec +4 -3
- data/gems/server/lib/itsi/http_request/response_status_shortcodes.rb +74 -0
- data/gems/server/lib/itsi/http_request.rb +117 -17
- data/gems/server/lib/itsi/http_response.rb +2 -0
- data/gems/server/lib/itsi/passfile.rb +109 -0
- data/gems/server/lib/itsi/server/config/dsl.rb +171 -99
- data/gems/server/lib/itsi/server/config.rb +58 -23
- data/gems/server/lib/itsi/server/default_app/default_app.rb +25 -29
- data/gems/server/lib/itsi/server/default_app/index.html +113 -89
- data/gems/server/lib/itsi/server/{Itsi.rb → default_config/Itsi-rackup.rb} +1 -1
- data/gems/server/lib/itsi/server/default_config/Itsi.rb +107 -0
- data/gems/server/lib/itsi/server/grpc/grpc_call.rb +246 -0
- data/gems/server/lib/itsi/server/grpc/grpc_interface.rb +100 -0
- data/gems/server/lib/itsi/server/grpc/reflection/v1/reflection_pb.rb +26 -0
- data/gems/server/lib/itsi/server/grpc/reflection/v1/reflection_services_pb.rb +122 -0
- data/gems/server/lib/itsi/server/route_tester.rb +107 -0
- data/gems/server/lib/itsi/server/typed_handlers/param_parser.rb +200 -0
- data/gems/server/lib/itsi/server/typed_handlers/source_parser.rb +55 -0
- data/gems/server/lib/itsi/server/typed_handlers.rb +17 -0
- data/gems/server/lib/itsi/server/version.rb +1 -1
- data/gems/server/lib/itsi/server.rb +82 -12
- data/gems/server/lib/ruby_lsp/itsi/addon.rb +111 -0
- data/gems/server/lib/shell_completions/completions.rb +26 -0
- data/gems/server/test/helpers/test_helper.rb +2 -1
- data/lib/itsi/version.rb +1 -1
- data/sandbox/README.md +5 -0
- data/sandbox/itsi_file/Gemfile +4 -2
- data/sandbox/itsi_file/Gemfile.lock +48 -6
- data/sandbox/itsi_file/Itsi.rb +327 -129
- data/sandbox/itsi_file/call.json +1 -0
- data/sandbox/itsi_file/echo_client/Gemfile +10 -0
- data/sandbox/itsi_file/echo_client/Gemfile.lock +27 -0
- data/sandbox/itsi_file/echo_client/README.md +95 -0
- data/sandbox/itsi_file/echo_client/echo_client.rb +164 -0
- data/sandbox/itsi_file/echo_client/gen_proto.sh +17 -0
- data/sandbox/itsi_file/echo_client/lib/echo_pb.rb +16 -0
- data/sandbox/itsi_file/echo_client/lib/echo_services_pb.rb +29 -0
- data/sandbox/itsi_file/echo_client/run_client.rb +64 -0
- data/sandbox/itsi_file/echo_client/test_compressions.sh +20 -0
- data/sandbox/itsi_file/echo_service_nonitsi/Gemfile +10 -0
- data/sandbox/itsi_file/echo_service_nonitsi/Gemfile.lock +79 -0
- data/sandbox/itsi_file/echo_service_nonitsi/echo.proto +26 -0
- data/sandbox/itsi_file/echo_service_nonitsi/echo_pb.rb +16 -0
- data/sandbox/itsi_file/echo_service_nonitsi/echo_services_pb.rb +29 -0
- data/sandbox/itsi_file/echo_service_nonitsi/server.rb +52 -0
- data/sandbox/itsi_sandbox_async/config.ru +0 -1
- data/sandbox/itsi_sandbox_rack/Gemfile.lock +2 -2
- data/sandbox/itsi_sandbox_rails/Gemfile +2 -2
- data/sandbox/itsi_sandbox_rails/Gemfile.lock +76 -2
- data/sandbox/itsi_sandbox_rails/app/controllers/home_controller.rb +15 -0
- data/sandbox/itsi_sandbox_rails/config/environments/development.rb +1 -0
- data/sandbox/itsi_sandbox_rails/config/environments/production.rb +1 -0
- data/sandbox/itsi_sandbox_rails/config/routes.rb +2 -0
- data/sandbox/itsi_sinatra/app.rb +0 -1
- data/sandbox/static_files/.env +1 -0
- data/sandbox/static_files/404.html +25 -0
- data/sandbox/static_files/_DSC0102.NEF.jpg +0 -0
- data/sandbox/static_files/about.html +68 -0
- data/sandbox/static_files/tiny.html +1 -0
- data/sandbox/static_files/writebook.zip +0 -0
- data/tasks.txt +28 -33
- metadata +87 -26
- data/crates/itsi_error/src/from.rs +0 -68
- data/crates/itsi_server/src/ruby_types/itsi_grpc_request.rs +0 -147
- data/crates/itsi_server/src/ruby_types/itsi_grpc_response.rs +0 -19
- data/crates/itsi_server/src/server/itsi_service.rs +0 -172
- data/crates/itsi_server/src/server/middleware_stack/middlewares/grpc_service.rs +0 -72
- data/crates/itsi_server/src/server/types.rs +0 -43
- data/gems/server/lib/itsi/server/grpc_interface.rb +0 -213
- data/sandbox/itsi_file/public/assets/index.html +0 -1
- /data/crates/itsi_server/src/server/{bind_protocol.rs → binds/bind_protocol.rs} +0 -0
- /data/crates/itsi_server/src/server/{tls → binds/tls}/locked_dir_cache.rs +0 -0
- /data/crates/itsi_server/src/{server → services}/cache_store.rs +0 -0
data/sandbox/itsi_file/Itsi.rb
CHANGED
@@ -1,150 +1,360 @@
|
|
1
1
|
workers 1
|
2
2
|
threads 1
|
3
|
+
fiber_scheduler true
|
4
|
+
|
5
|
+
scheduler_threads 1
|
6
|
+
|
7
|
+
request_timeout 2
|
3
8
|
|
4
9
|
preload false
|
5
10
|
|
6
11
|
bind 'http://localhost:3000'
|
7
|
-
bind 'http://0.0.0.0:8000'
|
8
12
|
|
9
|
-
shutdown_timeout
|
10
|
-
multithreaded_reactor true
|
13
|
+
shutdown_timeout 10
|
11
14
|
|
12
|
-
|
15
|
+
auto_reload_config!
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
response.status = 200
|
17
|
-
response.add_header('Content-Type', 'text/plain')
|
18
|
-
response << 'Hello, user!'
|
19
|
-
response.close
|
20
|
-
end
|
17
|
+
log_level :debug
|
18
|
+
log_format :plain
|
21
19
|
|
22
|
-
|
23
|
-
|
24
|
-
response.status = 201
|
25
|
-
response.add_header('Content-Type', 'text/plain')
|
26
|
-
response << 'User created!'
|
27
|
-
response.close
|
20
|
+
get "/root" do |req|
|
21
|
+
req.ok "Got from root"
|
28
22
|
end
|
29
23
|
|
30
|
-
location "/etag-test" do
|
31
|
-
etag type: 'strong', algorithm: 'sha256', min_body_size: 0
|
32
24
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
resp = req.response
|
39
|
-
req.respond("Content: #{content}.# Generated at: #{Time.now}")
|
25
|
+
location "app" do
|
26
|
+
location "/users" do
|
27
|
+
get "/:id" do |req|
|
28
|
+
req.ok "Got user #{req.url_params[:id]}"
|
29
|
+
end
|
40
30
|
end
|
31
|
+
|
32
|
+
run(->(env){
|
33
|
+
[200, {}, ["Fallback Rack app"]]
|
34
|
+
})
|
41
35
|
end
|
42
36
|
|
43
37
|
|
44
|
-
|
45
|
-
|
46
|
-
|
38
|
+
static_assets \
|
39
|
+
relative_path: true,
|
40
|
+
root_dir: "public",
|
41
|
+
not_found_behavior: "fallthrough",
|
42
|
+
try_html_extension: true,
|
43
|
+
auto_index: true,
|
44
|
+
max_file_size_in_memory: 1024 * 1024,
|
45
|
+
max_files_in_memory: 1000,
|
46
|
+
file_check_interval: 5,
|
47
|
+
serve_hidden_files: false
|
48
|
+
|
49
|
+
run(->(env){
|
50
|
+
[200, {}, ["Final Fallback Rack App. SN: #{env['SCRIPT_NAME']} PI: #{env['PATH_INFO']}"]]
|
51
|
+
})
|
52
|
+
# location %q{/foo/:id(\d+)/test/:name/bla} do
|
53
|
+
# get "/" do |req|
|
54
|
+
# req.respond json: req.url_params
|
55
|
+
# end
|
56
|
+
# end
|
47
57
|
|
48
|
-
|
49
|
-
|
58
|
+
# location "blocking" do
|
59
|
+
# run ->(env){
|
60
|
+
# sleep 0.25
|
61
|
+
# [200, {}, [:ok]]
|
62
|
+
# }
|
63
|
+
# end
|
50
64
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
65
|
+
# location "nonblocking" do
|
66
|
+
# run(->(env){
|
67
|
+
# sleep 0.25
|
68
|
+
# [200, {}, [:ok]]
|
69
|
+
# }, nonblocking: true)
|
70
|
+
# end
|
55
71
|
|
72
|
+
# require_relative 'echo_service/echo_service_impl'
|
56
73
|
|
57
|
-
|
58
|
-
|
74
|
+
# grpc EchoServiceImpl.new, nonblocking: false do
|
75
|
+
# end
|
59
76
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
get '/users/id' do |req|
|
64
|
-
user_id = 5
|
65
|
-
req.respond("User data for #{user_id}")
|
66
|
-
end
|
67
|
-
end
|
77
|
+
# location "foo" do
|
78
|
+
# static_response code: 200, headers: [["Headers","Foo"]], body: "This is my body"
|
79
|
+
# end
|
68
80
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
get '/' do |req|
|
79
|
-
puts "Headers are", "#{req["foo"]}"
|
80
|
-
req.respond("Is this still fast?")
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
81
|
+
# location "/public" do
|
82
|
+
# static_assets relative_path: true, root_dir: "public", not_found_behavior: {error: 'not_found'},
|
83
|
+
# try_html_extension: true, auto_index: true, max_file_size_in_memory: 1024 * 1024,
|
84
|
+
# # Maximum number of files to keep in memory cache
|
85
|
+
# max_files_in_memory: 1000,
|
86
|
+
# # Check for file modifications every 5 seconds
|
87
|
+
# file_check_interval: 5,
|
88
|
+
# serve_hidden_files: false
|
89
|
+
# end
|
84
90
|
|
85
|
-
|
86
|
-
|
87
|
-
cache_control max_age: 3600, public: true, vary: ['Accept-Encoding']
|
88
|
-
get '/' do |req|
|
89
|
-
req.respond("This content is cached for 1 hour.")
|
90
|
-
end
|
91
|
-
end
|
91
|
+
# require 'debug'
|
92
|
+
# require 'date'
|
92
93
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
content = "This content will have ETags. " * 20
|
98
|
-
req.respond(content)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
94
|
+
# UserSchema = {
|
95
|
+
# id: Integer,
|
96
|
+
# name: String
|
97
|
+
# }
|
102
98
|
|
103
99
|
|
100
|
+
# ResultSchema = {
|
101
|
+
# status_code: Integer,
|
102
|
+
# user: UserSchema
|
103
|
+
# }
|
104
104
|
|
105
|
-
#
|
106
|
-
location "/assets" do
|
107
|
-
cache_control max_age: 604800, s_max_age: 2592000,
|
108
|
-
stale_while_revalidate: 86400,
|
109
|
-
public: true, immutable: true
|
105
|
+
# module UserController
|
110
106
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
107
|
+
# def self.create(req)
|
108
|
+
# req.ok \
|
109
|
+
# json: {
|
110
|
+
# status: :created,
|
111
|
+
# user: user
|
112
|
+
# }
|
113
|
+
# end
|
114
|
+
|
115
|
+
# def self.create(req, params: UserSchema, return_type: ResultSchema)
|
116
|
+
# req.ok \
|
117
|
+
# json: {
|
118
|
+
# status_code: 5,
|
119
|
+
# user: params
|
120
|
+
# },
|
121
|
+
# as: return_type
|
122
|
+
# end
|
123
|
+
|
124
|
+
# def self.create_no_type(req, params)
|
125
|
+
# req.ok json: "foo"
|
126
|
+
# end
|
127
|
+
|
128
|
+
# end
|
129
|
+
|
130
|
+
# controller UserController
|
131
|
+
# post "/", :create
|
132
|
+
# get "/" do |req, return_type: ResultSchema|
|
133
|
+
# req.ok as: return_type, json: {
|
134
|
+
# status_code: 5,
|
135
|
+
# user: {
|
136
|
+
# id: 3,
|
137
|
+
# name: "Foo Bar"
|
138
|
+
# }
|
139
|
+
# }
|
140
|
+
# end
|
141
|
+
|
142
|
+
# post "/nt", :create_no_type
|
143
|
+
|
144
|
+
# location "/rack" do
|
145
|
+
# run(->(env){
|
146
|
+
# sleep 5
|
147
|
+
# [200, {}, [:ok]]
|
148
|
+
# })
|
149
|
+
# end
|
150
|
+
# location '*' do
|
151
|
+
# proxy to: 'http://{host}{path_and_query}', backends: ['127.0.0.1:8082','127.0.0.1:8080', '127.0.0.1:8081'], headers: {}, verify_ssl: false, timeout: 1, tls_sni: false, backend_priority: 'round_robin'
|
152
|
+
# end
|
116
153
|
|
117
|
-
#
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
154
|
+
# # require_relative 'echo_service/echo_service_impl'
|
155
|
+
|
156
|
+
# # grpc EchoServiceImpl.new do
|
157
|
+
|
158
|
+
# # end
|
159
|
+
|
160
|
+
# location '/' do
|
161
|
+
# # compress algorithms: ['zstd'], min_size: 0, compress_streams: true, mime_types: ['all'], level: 'fastest'
|
162
|
+
# max_body max_size: 5
|
163
|
+
# get '/' do |req|
|
164
|
+
# req.respond('Foo')
|
165
|
+
# end
|
166
|
+
# etag type: 'weak', algorithm: 'md5', min_body_size: 0
|
167
|
+
# post '/' do |req|
|
168
|
+
# puts "Post to me!"
|
169
|
+
# req.respond('Foo')
|
170
|
+
# end
|
171
|
+
# end
|
172
|
+
|
173
|
+
# location '/' do
|
174
|
+
# end
|
175
|
+
# rate_limit requests: 5, seconds: 5, key: 'address', store_config: { redis: { connection_url: 'redis://localhost:6379/0' } }, error_response: { plaintext: 'no way', code: 429, default: 'plaintext' }
|
176
|
+
|
177
|
+
#
|
178
|
+
|
179
|
+
# static_assets\
|
180
|
+
# relative_path: true,
|
181
|
+
# root_dir: 'spa/dist',
|
182
|
+
# # # Only allow certain file extensions
|
183
|
+
# # allowed_extensions: %w[css js jpg jpeg png gif svg ico woff woff2 ttf
|
184
|
+
# # otf html],
|
185
|
+
# # Return a 404 error if file is not found
|
186
|
+
# not_found_behavior: { index: 'index.html' },
|
187
|
+
# # Enable auto-indexing of directories
|
188
|
+
# auto_index: true,
|
189
|
+
# # Try adding .html extension to extensionless URLs
|
190
|
+
# try_html_extension: true,
|
191
|
+
# # Files under this size are cached in memory
|
192
|
+
# max_file_size_in_memory: 1024 * 1024, # 1MB
|
193
|
+
# # Maximum number of files to keep in memory cache
|
194
|
+
# max_files_in_memory: 1000,
|
195
|
+
# # Check for file modifications every 5 seconds
|
196
|
+
# file_check_interval: 5,
|
197
|
+
# # Add custom headers to all responses
|
198
|
+
# headers: {
|
199
|
+
# 'Cache-Control' => 'public, max-age=86400',
|
200
|
+
# 'X-Content-Type-Options' => 'nosniff'
|
201
|
+
# }
|
202
|
+
|
203
|
+
# run(lambda { |env|
|
204
|
+
# [200, {}, ["I'm a fallback"]]
|
205
|
+
# })
|
206
|
+
|
207
|
+
# def user_serve(request)
|
208
|
+
# response = request.response
|
209
|
+
# response.status = 200
|
210
|
+
# response.add_header('Content-Type', 'text/plain')
|
211
|
+
# response << 'Hello, user!'
|
212
|
+
# response.close
|
213
|
+
# end
|
214
|
+
|
215
|
+
# def user_create(request)
|
216
|
+
# response = request.response
|
217
|
+
# response.status = 201
|
218
|
+
# response.add_header('Content-Type', 'text/plain')
|
219
|
+
# response << 'User created!'
|
220
|
+
# response.close
|
221
|
+
# end
|
222
|
+
|
223
|
+
# location "/etag-test" do
|
224
|
+
# etag type: 'strong', algorithm: 'sha256', min_body_size: 0
|
225
|
+
|
226
|
+
# get '/' do |req|
|
227
|
+
# # Fixed content that will generate the same ETag each time
|
228
|
+
# content = "This is a fixed response that will always have the same ETag."
|
229
|
+
|
230
|
+
# # Add a timestamp as a comment to see the response is fresh
|
231
|
+
# resp = req.response
|
232
|
+
# req.respond("Content: #{content}.# Generated at: #{Time.now}")
|
233
|
+
# end
|
234
|
+
# end
|
235
|
+
|
236
|
+
# location "/cached-with-etag" do
|
237
|
+
# # Set up caching parameters
|
238
|
+
# cache_control max_age: 3600, public: true, vary: ['Accept-Encoding']
|
239
|
+
|
240
|
+
# # Add ETags for cache validation
|
241
|
+
# etag type: 'weak', algorithm: 'md5', min_body_size: 0
|
242
|
+
|
243
|
+
# get '/' do |req|
|
244
|
+
# req.respond("This response will have both cache headers and an ETag.")
|
245
|
+
# end
|
246
|
+
# end
|
247
|
+
|
248
|
+
# location "/" do
|
249
|
+
# intrusion_protection banned_time_seconds: 5, banned_url_patterns: [/\/admin/, /\/secret/], store_config: { redis: { connection_url: 'redis://localhost:6379/0' } }, error_response: { plaintext: 'no way', code: 403, default: 'plaintext' }
|
250
|
+
|
251
|
+
# # Example for API endpoints with ETags
|
252
|
+
# location "/api" do
|
253
|
+
# etag type: 'weak', algorithm: 'md5', min_body_size: 0
|
254
|
+
# get '/users/id' do |req|
|
255
|
+
# user_id = 5
|
256
|
+
# req.respond("User data for #{user_id}")
|
257
|
+
# end
|
258
|
+
# end
|
259
|
+
|
260
|
+
# location "/hey" do
|
261
|
+
# location "/world*" do
|
262
|
+
# request_headers additions: {"X-Custom-Req" => ["Foo", "Bar", "Baz"]}, removals: [""]
|
263
|
+
# response_headers additions: {"X-Custom-Resp" => ["Foo", "Bar"]}, removals: []
|
264
|
+
# rate_limit requests: 5, seconds: 30, key: 'address', store_config: { redis: { connection_url: 'redis://localhost:6379/0' } }, error_response: { plaintext: 'no way', code: 429, default: 'plaintext' }
|
265
|
+
# post '/' do |req|
|
266
|
+
# puts "I'm a post!"
|
267
|
+
# req.respond("Post successful!")
|
268
|
+
# end
|
269
|
+
# get '/' do |req|
|
270
|
+
# req.respond("Is this still fast?")
|
271
|
+
# end
|
272
|
+
# end
|
273
|
+
# end
|
274
|
+
|
275
|
+
# # Add a new location with cache_control middleware
|
276
|
+
# location "/cached" do
|
277
|
+
# cache_control max_age: 3600, public: true, vary: ['Accept-Encoding']
|
278
|
+
# get '/' do |req|
|
279
|
+
# req.respond("This content is cached for 1 hour.")
|
280
|
+
# end
|
281
|
+
# end
|
282
|
+
|
283
|
+
# location "/etag" do
|
284
|
+
# etag enabled: true, etag_type: 'strong', hash_algorithm: 'sha256', min_body_size: 0
|
285
|
+
# get '/' do |req|
|
286
|
+
# # Create a response large enough to be worth ETagging
|
287
|
+
# content = "This content will have ETags. " * 20
|
288
|
+
# req.respond(content)
|
289
|
+
# end
|
290
|
+
# end
|
291
|
+
|
292
|
+
# location "/jwt" do
|
293
|
+
# auth_jwt token_source: { header: { name: 'Authorization', prefix: 'Bearer ' } },
|
294
|
+
# verifiers: {
|
295
|
+
# 'hs256' => ["1V6nZzztO/F6Y3XAYXJ1I37AAXCJ/V7EVHJoVnD8lr4="],
|
296
|
+
# 'rs256' => [%Q{
|
297
|
+
# -----BEGIN PUBLIC KEY-----
|
298
|
+
# MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs8XK+wP7nnKkOGXP6+il
|
299
|
+
# +JDQMFRV8zoVg1BYYapGla6AzR0YCV6xq28lNB1FE8C6xhCEKYiOlnkXZwj+a4UW
|
300
|
+
# q4Bex/U9qvfza0zGxHlTnQT9T+vjwXNsWYuefYC4EAZjEd6bGeP23De128QfhlLc
|
301
|
+
# oQpcfW32/e8KjSYtn8rtWuKV6Anqf92o9zEbVn8y2OZwZbiW0LbfDnimazqP5ATy
|
302
|
+
# SI6a5kQorBeG9cU4WW93ctuT5nkyAbBaEpiejWIpjbMkofD5fj2pUgg7H/Xvh+eR
|
303
|
+
# S9A+//VGfy4A4SFjBooVewhJ04VhDkMnVC29fbVwVuNqm6Z+FZaxI5pqvisxvH8S
|
304
|
+
# XwIDAQAB
|
305
|
+
# -----END PUBLIC KEY-----
|
306
|
+
# }]
|
307
|
+
# }, error_response: { code: 401, plaintext: 'Unauthorized', default: 'plaintext' }
|
308
|
+
# get "/" do |req|
|
309
|
+
# req.respond('Hello, JWT user!')
|
310
|
+
# end
|
311
|
+
# end
|
312
|
+
|
313
|
+
# end
|
314
|
+
|
315
|
+
# # For an assets example
|
316
|
+
# location "/assets" do
|
317
|
+
# cache_control max_age: 604800, s_max_age: 2592000,
|
318
|
+
# stale_while_revalidate: 86400,
|
319
|
+
# public: true, immutable: true
|
320
|
+
|
321
|
+
# get "/:file" do |req|
|
322
|
+
# file_name = req.params["file"]
|
323
|
+
# req.respond("Pretending to serve #{file_name} with long-lived caching")
|
324
|
+
# end
|
325
|
+
# end
|
326
|
+
|
327
|
+
# # location '' do
|
328
|
+
|
329
|
+
# location '/spa' do
|
330
|
+
# # Serve static files from the "public/assets" directory
|
331
|
+
# log_requests before: { format: "REQUEST_ID={request_id} METHOD={method} PATH={path} QUERY={query} HOST={host} PORT={port} START_TIME={start_time}" , level: 'INFO'}, after: { format: "REQUEST_ID={request_id} RESPONSE_TIME={response_time}", level: 'INFO' }
|
332
|
+
# allow_list allowed_patterns: [/127.*/], error_response: { plaintext: 'no way', code: 401, default: 'plaintext' }
|
333
|
+
# static_assets\
|
334
|
+
# relative_path: true,
|
335
|
+
# root_dir: 'spa/dist',
|
336
|
+
# # # Only allow certain file extensions
|
337
|
+
# # allowed_extensions: %w[css js jpg jpeg png gif svg ico woff woff2 ttf
|
338
|
+
# # otf html],
|
339
|
+
# # Return a 404 error if file is not found
|
340
|
+
# not_found_behavior: { index: 'index.html' },
|
341
|
+
# # Enable auto-indexing of directories
|
342
|
+
# auto_index: true,
|
343
|
+
# # Try adding .html extension to extensionless URLs
|
344
|
+
# try_html_extension: true,
|
345
|
+
# # Files under this size are cached in memory
|
346
|
+
# max_file_size_in_memory: 1024 * 1024, # 1MB
|
347
|
+
# # Maximum number of files to keep in memory cache
|
348
|
+
# max_files_in_memory: 1000,
|
349
|
+
# # Check for file modifications every 5 seconds
|
350
|
+
# file_check_interval: 5,
|
351
|
+
# # Add custom headers to all responses
|
352
|
+
# headers: {
|
353
|
+
# 'Cache-Control' => 'public, max-age=86400',
|
354
|
+
# 'X-Content-Type-Options' => 'nosniff'
|
355
|
+
# }
|
356
|
+
# compress algorithms: ['zstd'], min_size: 0, compress_streams: true, mime_types: ['all'], level: 'fastest'
|
357
|
+
# end
|
148
358
|
# end
|
149
359
|
|
150
360
|
# location "/cors_test" do
|
@@ -154,17 +364,7 @@ end
|
|
154
364
|
# end
|
155
365
|
# end
|
156
366
|
|
157
|
-
# location "/basic" do
|
158
|
-
# auth_basic realm: 'My Realm', credential_pairs: { 'user' => 'password' }
|
159
|
-
# end
|
160
367
|
|
161
|
-
# location "/jwt" do
|
162
|
-
# auth_jwt token_source: { header: { name: 'Authorization', prefix: 'Bearer ' } }, verifiers: {'hs256' => ["1V6nZzztO/F6Y3XAYXJ1I37AAXCJ/V7EVHJoVnD8lr4="]
|
163
|
-
# }, error_response: { code: 401, plaintext: 'Unauthorized', default: 'plaintext' }
|
164
|
-
# get "/" do |req|
|
165
|
-
# req.respond('Hello, JWT user!')
|
166
|
-
# end
|
167
|
-
# end
|
168
368
|
|
169
369
|
# location '/proxy_as_foo_com' do
|
170
370
|
# compress algorithms: ['zstd'], min_size: 0, compress_streams: true, mime_types: ['all'], level: 'fastest'
|
@@ -229,7 +429,6 @@ end
|
|
229
429
|
# req.respond("This is a test")
|
230
430
|
# end
|
231
431
|
|
232
|
-
|
233
432
|
# location '*', protocols: :http do
|
234
433
|
# location 'foo' do
|
235
434
|
# redirect to: 'https://{host}:3001{path}'
|
@@ -272,5 +471,4 @@ end
|
|
272
471
|
|
273
472
|
# Example with both caching and ETags
|
274
473
|
|
275
|
-
|
276
474
|
# Simple ETag test endpoint with predictable content
|
@@ -0,0 +1 @@
|
|
1
|
+
{"message": "Hello, World!"}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
colorize (0.8.1)
|
5
|
+
google-protobuf (3.25.6)
|
6
|
+
googleapis-common-protos-types (1.19.0)
|
7
|
+
google-protobuf (>= 3.18, < 5.a)
|
8
|
+
grpc (1.71.0)
|
9
|
+
google-protobuf (>= 3.25, < 5.0)
|
10
|
+
googleapis-common-protos-types (~> 1.0)
|
11
|
+
grpc (1.71.0-arm64-darwin)
|
12
|
+
google-protobuf (>= 3.25, < 5.0)
|
13
|
+
googleapis-common-protos-types (~> 1.0)
|
14
|
+
grpc-tools (1.71.0)
|
15
|
+
|
16
|
+
PLATFORMS
|
17
|
+
arm64-darwin-23
|
18
|
+
ruby
|
19
|
+
|
20
|
+
DEPENDENCIES
|
21
|
+
colorize (~> 0.8.1)
|
22
|
+
google-protobuf (~> 3.21)
|
23
|
+
grpc (~> 1.50)
|
24
|
+
grpc-tools (~> 1.50)
|
25
|
+
|
26
|
+
BUNDLED WITH
|
27
|
+
2.6.3
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# Echo gRPC Client
|
2
|
+
|
3
|
+
A simple Ruby gRPC client for the Echo service.
|
4
|
+
|
5
|
+
## Setup
|
6
|
+
|
7
|
+
1. Install dependencies:
|
8
|
+
|
9
|
+
```bash
|
10
|
+
bundle install
|
11
|
+
```
|
12
|
+
|
13
|
+
2. Generate Ruby code from the proto file:
|
14
|
+
|
15
|
+
```bash
|
16
|
+
./gen_proto.sh
|
17
|
+
```
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Run the client with optional compression:
|
22
|
+
|
23
|
+
```bash
|
24
|
+
# Run without compression (default)
|
25
|
+
ruby echo_client.rb
|
26
|
+
|
27
|
+
# Run with gzip compression
|
28
|
+
ruby echo_client.rb gzip
|
29
|
+
|
30
|
+
# Run with deflate compression
|
31
|
+
ruby echo_client.rb deflate
|
32
|
+
|
33
|
+
# Show help
|
34
|
+
ruby echo_client.rb help
|
35
|
+
```
|
36
|
+
|
37
|
+
## Client Details
|
38
|
+
|
39
|
+
This client implements all four types of gRPC methods:
|
40
|
+
|
41
|
+
1. Unary RPC (`echo`)
|
42
|
+
2. Server streaming RPC (`echo_stream`)
|
43
|
+
3. Client streaming RPC (`echo_collect`)
|
44
|
+
4. Bidirectional streaming RPC (`echo_bidirectional`)
|
45
|
+
|
46
|
+
## Compression Options
|
47
|
+
|
48
|
+
You can control compression by modifying the client initialization in `echo_client.rb`:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
# No compression
|
52
|
+
client = EchoClient.new('localhost', 50051, compression: nil)
|
53
|
+
|
54
|
+
# Gzip compression
|
55
|
+
client = EchoClient.new('localhost', 50051, compression: :gzip)
|
56
|
+
|
57
|
+
# Deflate compression
|
58
|
+
client = EchoClient.new('localhost', 50051, compression: :deflate)
|
59
|
+
```
|
60
|
+
|
61
|
+
The compression settings are implemented using the gRPC channel arguments, which allows you to test different compression algorithms.
|
62
|
+
|
63
|
+
## Troubleshooting
|
64
|
+
|
65
|
+
If you encounter any issues:
|
66
|
+
|
67
|
+
1. Make sure you have installed all dependencies with `bundle install`
|
68
|
+
2. Ensure the protocol buffer code has been generated with `./gen_proto.sh`
|
69
|
+
3. Check that the gRPC server is running on the specified host and port
|
70
|
+
4. If you see connectivity issues, try running with debugging enabled:
|
71
|
+
|
72
|
+
```bash
|
73
|
+
GRPC_VERBOSITY=DEBUG GRPC_TRACE=all ruby echo_client.rb
|
74
|
+
```
|
75
|
+
|
76
|
+
## Example Server
|
77
|
+
|
78
|
+
The client is designed to work with the EchoService server in the `../echo_service_nonitsi` directory. Make sure the server is running before starting the client.
|
79
|
+
|
80
|
+
## Compression Testing
|
81
|
+
|
82
|
+
To test different compression algorithms with the same message payload:
|
83
|
+
|
84
|
+
```bash
|
85
|
+
# Test without compression
|
86
|
+
./run_client.rb -m "Large message repeated many times" -c none
|
87
|
+
|
88
|
+
# Test with gzip compression
|
89
|
+
./run_client.rb -m "Large message repeated many times" -c gzip
|
90
|
+
|
91
|
+
# Test with deflate compression
|
92
|
+
./run_client.rb -m "Large message repeated many times" -c deflate
|
93
|
+
```
|
94
|
+
|
95
|
+
This allows you to compare the performance and behavior with different compression settings.
|