macaw_framework 1.0.5 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8f108da6fb2654c701154a544cea00e47d9546c5092ef3dcbc1e299c34420ddd
4
- data.tar.gz: 23c72078365336da0585d7ee88cce41db2972efcfcc72c930ccceb73edb302ed
3
+ metadata.gz: 23fe3e98800399fc740bf5a76603fab28e53502d8f5041d894ecac5bef96f00c
4
+ data.tar.gz: 5b8f46d645b2e274d005368e9f144bca0b63eac552942ea3176172a1479ac4a4
5
5
  SHA512:
6
- metadata.gz: 9e0feab01f25bab3ce8b65799c516f04a837c5e250b8f53934049c2c3f1db303d92cfa9629151c0c8b46836e9a77690aea1a27cfc7b8bb1b99c7f9340a3cb8f1
7
- data.tar.gz: cb769896b94e443248ecc419ffb69f0c587e9cda52430516204b8bcfed0a56eed5cf4aac3f6ca05f53dabe5d954777579e088c351dd82f2a61fdf47871bc143a
6
+ metadata.gz: 1757594571b01f8110c8b839c906a63488aa25120adc1b96f7a87066cbaea0473d0628398d9d134e4950d3b6dcf19ddd07bc806620608f2214404aee0950587e
7
+ data.tar.gz: 8326f4957ba9d8baa95603d5c4c4300339e6e4a4d6797fc34945e88d9e07dc9e102ac0ba5a0dbce90ea581f8ab7f5fc4e8d8f22c8cf6e0d2013863f2f634a0b2
data/CHANGELOG.md CHANGED
@@ -67,3 +67,10 @@
67
67
  ## [1.0.5] - 2023-05-12
68
68
 
69
69
  - Fixing critical bug where threads were being killed and not respawning after abrupt client connection shutdown
70
+
71
+ ## [1.1.0] - 2023-xx-xx
72
+
73
+ - Adding support for other SSL/TSL keys other than RSA
74
+ - New mechanism to handle server shutdown properly
75
+ - Improving log readability
76
+ - Automatic logging is now optional
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,30 @@
1
+ # Contributing to Macaw Framework
2
+
3
+ First off, thank you for considering contributing to Macaw Framework.
4
+
5
+ ## Getting Started
6
+
7
+ - Submit an issue for your problem or suggestion, assuming one does not already exist.
8
+ - Clearly describe the issue including steps to reproduce when it is a bug.
9
+ - Make sure you fill in the earliest version that you know has the issue.
10
+
11
+ ## Making Changes
12
+
13
+ - Fork the repository on GitHub.
14
+ - Create a topic branch from where you want to base your work. This is usually the main branch.
15
+ - To quickly create a topic branch based on main; `git checkout -b fix/main/my_contribution main`. Please avoid working directly on the `main` branch.
16
+ - Make commits of logical units.
17
+ - Check for unnecessary whitespace with `git diff --check` before committing.
18
+ - Make sure your commit messages are in the proper format.
19
+ - Make sure you have added the necessary tests for your changes.
20
+ - Run _all_ the tests to assure nothing else was accidentally broken.
21
+
22
+ ## Submitting Changes
23
+
24
+ - Run RuboCop to ensure your code adheres to our code style conventions. You can do this by running `rubocop` in your terminal.
25
+ - Push your changes to a topic branch in your fork of the repository.
26
+ - Submit a pull request to the repository in my GitHub account.
27
+ - Our automatic CI/CD pipeline will run all tests and lint for 3 different ruby versions before merges.
28
+ - I'm constantly reviewing Pull Requests and will provide feedback as soon as possible.
29
+
30
+ Thanks for contributing!
data/README.md CHANGED
@@ -108,6 +108,7 @@ end
108
108
  "ssl": {
109
109
  "min": "SSL3",
110
110
  "max": "TLS1.3",
111
+ "key_type": "EC",
111
112
  "cert_file_name": "path/to/cert/file/file.crt",
112
113
  "key_file_name": "path/to/cert/key/file.key"
113
114
  }
@@ -123,6 +124,12 @@ curl http://localhost:8080/metrics
123
124
 
124
125
  ### Tips
125
126
 
127
+ The automatic logging and log aspect are now optional. To disable them, simply start Macaw with `custom_log` set to nil.
128
+
129
+ ```ruby
130
+ MacawFramework::Macaw.new(custom_log: nil)
131
+ ```
132
+
126
133
  Cache invalidation time should be specified in seconds. In order to enable caching, The application.json file
127
134
  should exist in the app main directory and it need the `cache_invalidation` config set. It is possible to
128
135
  provide a list of strings in the property `ignore_headers`. All the client headers with the same name of any
@@ -143,7 +150,8 @@ exists inside `application.json`.
143
150
  If the SSL configuration is provided in the `application.json` file with valid certificate and key files, the TCP server
144
151
  will be wrapped with HTTPS security using the provided certificate.
145
152
 
146
- The supported values for `min` and `max` in the SSL configuration are: `SSL2`, `SSL3`, `TLS1.1`, `TLS1.2` and `TLS1.3`
153
+ The supported values for `min` and `max` in the SSL configuration are: `SSL2`, `SSL3`, `TLS1.1`, `TLS1.2` and `TLS1.3`,
154
+ and the supported values for `key_type` are `RSA` and `EC`.
147
155
 
148
156
  If prometheus is enabled, a get endpoint will be defined at path `/metrics` to collect prometheus metrics. This path
149
157
  is configurable via the `application.json` file.
@@ -9,6 +9,8 @@ require_relative "../data_filters/log_data_filter"
9
9
  # in the framework.
10
10
  module LoggingAspect
11
11
  def call_endpoint(logger, *args)
12
+ return super(*args) if logger.nil?
13
+
12
14
  endpoint_name = args[1].split(".")[1..].join("/")
13
15
  logger.info(LogDataFilter.sanitize_for_logging(
14
16
  "Request received for #{endpoint_name} with arguments: #{args[2..]}"
@@ -70,7 +70,7 @@ class Server
70
70
  loop do
71
71
  @work_queue << @server.accept
72
72
  rescue OpenSSL::SSL::SSLError => e
73
- @macaw_log.error("SSL error: #{e.message}")
73
+ @macaw_log&.error("SSL error: #{e.message}")
74
74
  rescue IOError, Errno::EBADF
75
75
  break
76
76
  end
@@ -79,9 +79,7 @@ class Server
79
79
  ##
80
80
  # Method Responsible for closing the TCP server.
81
81
  def close
82
- @server.close
83
- @num_threads.times { @work_queue << :shutdown }
84
- @workers.each(&:join)
82
+ shutdown
85
83
  end
86
84
 
87
85
  private
@@ -94,7 +92,7 @@ class Server
94
92
  declare_client_session(client)
95
93
  client_data = get_client_data(body, headers, parameters)
96
94
 
97
- @macaw_log.info("Running #{path.gsub("\n", "").gsub("\r", "")}")
95
+ @macaw_log&.info("Running #{path.gsub("\n", "").gsub("\r", "")}")
98
96
  message, status, response_headers = call_endpoint(@prometheus_middleware, @macaw_log, @cache,
99
97
  method_name, client_data, client.peeraddr[3])
100
98
  status ||= 200
@@ -102,19 +100,19 @@ class Server
102
100
  response_headers ||= nil
103
101
  client.puts ResponseDataFilter.mount_response(status, response_headers, message)
104
102
  rescue IOError, Errno::EPIPE => e
105
- @macaw_log.error("Error writing to client: #{e.message}")
103
+ @macaw_log&.error("Error writing to client: #{e.message}")
106
104
  rescue TooManyRequestsError
107
105
  client.print "HTTP/1.1 429 Too Many Requests\r\n\r\n"
108
106
  rescue EndpointNotMappedError
109
107
  client.print "HTTP/1.1 404 Not Found\r\n\r\n"
110
108
  rescue StandardError => e
111
109
  client.print "HTTP/1.1 500 Internal Server Error\r\n\r\n"
112
- @macaw_log.info("Error: #{e}")
110
+ @macaw_log&.info("Error: #{e}")
113
111
  ensure
114
112
  begin
115
113
  client.close
116
114
  rescue IOError => e
117
- @macaw_log.error("Error closing client: #{e.message}")
115
+ @macaw_log&.error("Error closing client: #{e.message}")
118
116
  end
119
117
  end
120
118
 
@@ -147,13 +145,20 @@ class Server
147
145
  @context.min_version = SupportedSSLVersions::VERSIONS[version_config[:min]] unless version_config[:min].nil?
148
146
  @context.max_version = SupportedSSLVersions::VERSIONS[version_config[:max]] unless version_config[:max].nil?
149
147
  @context.cert = OpenSSL::X509::Certificate.new(File.read(ssl_config["cert_file_name"]))
150
- @context.key = OpenSSL::PKey::RSA.new(File.read(ssl_config["key_file_name"]))
148
+
149
+ if ssl_config["key_type"] == "RSA" || ssl_config["key_type"].nil?
150
+ @context.key = OpenSSL::PKey::RSA.new(File.read(ssl_config["key_file_name"]))
151
+ elsif ssl_config["key_type"] == "EC"
152
+ @context.key = OpenSSL::PKey::EC.new(File.read(ssl_config["key_file_name"]))
153
+ else
154
+ raise ArgumentError, "Unsupported SSL/TLS key type: #{ssl_config["key_type"]}"
155
+ end
151
156
  end
152
157
  @context ||= nil
153
158
  rescue IOError => e
154
- @macaw_log.error("It was not possible to read files #{@macaw.config["macaw"]["ssl"]["cert_file_name"]} and
155
- #{@macaw.config["macaw"]["ssl"]["key_file_name"]}. Please assure the files exists and their names are correct.")
156
- @macaw_log.error(e.backtrace)
159
+ @macaw_log&.error("It was not possible to read files #{@macaw.config["macaw"]["ssl"]["cert_file_name"]} and
160
+ #{@macaw.config["macaw"]["ssl"]["key_file_name"]}. Please assure the files exist and their names are correct.")
161
+ @macaw_log&.error(e.backtrace)
157
162
  raise e
158
163
  end
159
164
 
@@ -168,6 +173,7 @@ class Server
168
173
  end
169
174
 
170
175
  def set_features
176
+ @is_shutting_down = false
171
177
  set_rate_limiting
172
178
  set_session
173
179
  set_ssl
@@ -206,10 +212,27 @@ class Server
206
212
  @workers_mutex.synchronize do
207
213
  @workers.each_with_index do |worker, index|
208
214
  unless worker.alive?
209
- @macaw_log.error("Worker thread #{index} died, respawning...")
210
- @workers[index] = spawn_worker
215
+ if @is_shutting_down
216
+ @macaw_log&.info("Worker thread #{index} finished, not respawning due to server shutdown.")
217
+ else
218
+ @macaw_log&.error("Worker thread #{index} died, respawning...")
219
+ @workers[index] = spawn_worker
220
+ end
211
221
  end
212
222
  end
213
223
  end
214
224
  end
225
+
226
+ def shutdown
227
+ @is_shutting_down = true
228
+ loop do
229
+ break if @work_queue.empty?
230
+
231
+ sleep 0.1
232
+ end
233
+
234
+ @num_threads.times { @work_queue << :shutdown }
235
+ @workers.each(&:join)
236
+ @server.close
237
+ end
215
238
  end
@@ -36,6 +36,7 @@ module LogDataFilter
36
36
  data = data.to_s.force_encoding("UTF-8")
37
37
  data = data.gsub(/[\x00-\x1F\x7F]/, "")
38
38
  data = data.gsub(/\s+/, " ")
39
+ data = data.gsub("/", "")
39
40
  data = data.slice(0, config[:max_length])
40
41
 
41
42
  sensitive_fields.each do |field|
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MacawFramework
4
- VERSION = "1.0.5"
4
+ VERSION = "1.1.0"
5
5
  end
@@ -22,10 +22,10 @@ module MacawFramework
22
22
 
23
23
  ##
24
24
  # @param {Logger} custom_log
25
- def initialize(custom_log: nil, server: Server)
25
+ def initialize(custom_log: Logger.new($stdout), server: Server)
26
26
  begin
27
27
  @routes = []
28
- @macaw_log ||= custom_log.nil? ? Logger.new($stdout) : custom_log
28
+ @macaw_log ||= custom_log
29
29
  @config = JSON.parse(File.read("application.json"))
30
30
  @port = @config["macaw"]["port"] || 8080
31
31
  @bind = @config["macaw"]["bind"] || "localhost"
@@ -37,7 +37,7 @@ module MacawFramework
37
37
  @prometheus_middleware = PrometheusMiddleware.new if @config["macaw"]["prometheus"]
38
38
  @prometheus_middleware.configure_prometheus(@prometheus, @config, self) if @config["macaw"]["prometheus"]
39
39
  rescue StandardError => e
40
- @macaw_log.warn(e.message)
40
+ @macaw_log&.warn(e.message)
41
41
  end
42
42
  @port ||= 8080
43
43
  @bind ||= "localhost"
@@ -103,15 +103,28 @@ module MacawFramework
103
103
  ##
104
104
  # Starts the web server
105
105
  def start!
106
- @macaw_log.info("---------------------------------")
107
- @macaw_log.info("Starting server at port #{@port}")
108
- @macaw_log.info("Number of threads: #{@threads}")
109
- @macaw_log.info("---------------------------------")
106
+ if @macaw_log.nil?
107
+ puts("---------------------------------")
108
+ puts("Starting server at port #{@port}")
109
+ puts("Number of threads: #{@threads}")
110
+ puts("---------------------------------")
111
+ else
112
+ @macaw_log.info("---------------------------------")
113
+ @macaw_log.info("Starting server at port #{@port}")
114
+ @macaw_log.info("Number of threads: #{@threads}")
115
+ @macaw_log.info("---------------------------------")
116
+ end
110
117
  server_loop(@server)
111
118
  rescue Interrupt
112
- @macaw_log.info("Stopping server")
113
- @server.close
114
- @macaw_log.info("Macaw stop flying for some seeds...")
119
+ if @macaw_log.nil?
120
+ puts("Stopping server")
121
+ @server.close
122
+ puts("Macaw stop flying for some seeds...")
123
+ else
124
+ @macaw_log.info("Stopping server")
125
+ @server.close
126
+ @macaw_log.info("Macaw stop flying for some seeds...")
127
+ end
115
128
  end
116
129
 
117
130
  private
@@ -123,7 +136,7 @@ module MacawFramework
123
136
  def map_new_endpoint(prefix, cache, path, &block)
124
137
  @endpoints_to_cache << "#{prefix}.#{RequestDataFiltering.sanitize_method_name(path)}" if cache
125
138
  path_clean = RequestDataFiltering.extract_path(path)
126
- @macaw_log.info("Defining #{prefix.upcase} endpoint at /#{path}")
139
+ @macaw_log&.info("Defining #{prefix.upcase} endpoint at /#{path}")
127
140
  define_singleton_method("#{prefix}.#{path_clean}", block || lambda {
128
141
  |context = { headers: {}, body: "", params: {} }|
129
142
  })
@@ -4,7 +4,7 @@ module MacawFramework
4
4
  @cache: untyped
5
5
  @config: Hash[String, untyped]
6
6
  @endpoints_to_cache: Array[String]
7
- @macaw_log: Logger
7
+ @macaw_log: Logger?
8
8
 
9
9
  @prometheus: untyped
10
10
  @prometheus_middleware: untyped
@@ -14,7 +14,7 @@ module MacawFramework
14
14
 
15
15
  attr_reader bind: String
16
16
  attr_reader config: Hash[String, untyped]
17
- attr_reader macaw_log: Logger
17
+ attr_reader macaw_log: Logger?
18
18
  attr_reader port: Integer
19
19
  attr_reader routes: Array[String]
20
20
 
data/sig/server.rbs CHANGED
@@ -4,7 +4,7 @@ class Server
4
4
  @context: OpenSSL::SSL::SSLContext
5
5
  @endpoints_to_cache: Array[String]
6
6
  @macaw: MacawFramework::Macaw
7
- @macaw_log: Logger
7
+ @macaw_log: Logger?
8
8
  @num_threads: Integer
9
9
  @port: Integer
10
10
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: macaw_framework
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aria Diniz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-05-12 00:00:00.000000000 Z
11
+ date: 2023-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prometheus-client
@@ -36,6 +36,7 @@ files:
36
36
  - ".rubocop.yml"
37
37
  - CHANGELOG.md
38
38
  - CODE_OF_CONDUCT.md
39
+ - CONTRIBUTING.md
39
40
  - Gemfile
40
41
  - LICENSE.txt
41
42
  - README.md