macaw_framework 0.1.1 → 0.1.2
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/CHANGELOG.md +8 -1
- data/README.md +1 -1
- data/lib/macaw_framework/http_status_code.rb +61 -64
- data/lib/macaw_framework/request_data_filtering.rb +60 -0
- data/lib/macaw_framework/version.rb +1 -1
- data/lib/macaw_framework.rb +36 -47
- data/sig/http_status_code.rbs +3 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 512b14576a1be6337300fc758b7be6acf48603fa605c0d60c21d494b2d411a10
|
4
|
+
data.tar.gz: 29f0115f9e93539c740e56834515d7d66dd768a2b5a8c5ef2668beb82d403fa5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa4dd23ceaa6579ab7f0b77caa42b8745fb48f830aa8f5db9eb713bff5330d1879653209781e888c873b071c45b11afd5744282401d77c9c7609c0ed9f721e4b
|
7
|
+
data.tar.gz: 2cc30aff12830763c3e9a19c8597fa4cd5f8e8ec7bfc1201f5c367883e93c480cef243d2590725084b62922538e6e27798f53840df0660b8872e09be01336f8a
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,13 @@
|
|
4
4
|
|
5
5
|
- Initial release
|
6
6
|
|
7
|
-
## [0.1.
|
7
|
+
## [0.1.1] - 2022-12-06
|
8
8
|
|
9
9
|
- Adding support for headers and body
|
10
|
+
|
11
|
+
## [0.1.2] - 2022-12-10
|
12
|
+
|
13
|
+
- Adding support to URL parameters
|
14
|
+
- Adding logs to the framework activity
|
15
|
+
- Removing undefined Status Codes from http_status_code hash
|
16
|
+
- Moving methods from Macaw class to RequestDataFiltering module, respecting SOLID
|
data/README.md
CHANGED
@@ -7,69 +7,66 @@ module HttpStatusCode
|
|
7
7
|
##
|
8
8
|
# Http Status Code Map
|
9
9
|
HTTP_STATUS_CODE_MAP = {
|
10
|
-
100 =>
|
11
|
-
101 =>
|
12
|
-
102 =>
|
13
|
-
103 =>
|
14
|
-
200 =>
|
15
|
-
201 =>
|
16
|
-
202 =>
|
17
|
-
203 =>
|
18
|
-
204 =>
|
19
|
-
205 =>
|
20
|
-
206 =>
|
21
|
-
207 =>
|
22
|
-
208 =>
|
23
|
-
226 =>
|
24
|
-
300 =>
|
25
|
-
301 =>
|
26
|
-
302 =>
|
27
|
-
303 =>
|
28
|
-
304 =>
|
29
|
-
305 =>
|
30
|
-
307 =>
|
31
|
-
308 =>
|
32
|
-
400 =>
|
33
|
-
401 =>
|
34
|
-
402 =>
|
35
|
-
403 =>
|
36
|
-
404 =>
|
37
|
-
405 =>
|
38
|
-
406 =>
|
39
|
-
407 =>
|
40
|
-
408 =>
|
41
|
-
409 =>
|
42
|
-
410 =>
|
43
|
-
411 =>
|
44
|
-
412 =>
|
45
|
-
413 =>
|
46
|
-
414 =>
|
47
|
-
415 =>
|
48
|
-
416 =>
|
49
|
-
417 =>
|
50
|
-
421 =>
|
51
|
-
422 =>
|
52
|
-
423 =>
|
53
|
-
424 =>
|
54
|
-
425 =>
|
55
|
-
426 =>
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
509 => 'Unassigned',
|
72
|
-
510 => 'Not Extended (OBSOLETED)',
|
73
|
-
511 => 'Network Authentication Required'
|
10
|
+
100 => "Continue",
|
11
|
+
101 => "Switching Protocols",
|
12
|
+
102 => "Processing",
|
13
|
+
103 => "Early Hints",
|
14
|
+
200 => "OK",
|
15
|
+
201 => "Created",
|
16
|
+
202 => "Accepted",
|
17
|
+
203 => "Non-Authoritative Information",
|
18
|
+
204 => "No Content",
|
19
|
+
205 => "Reset Content",
|
20
|
+
206 => "Partial Content",
|
21
|
+
207 => "Multi-Status",
|
22
|
+
208 => "Already Reported",
|
23
|
+
226 => "IM Used",
|
24
|
+
300 => "Multiple Choices",
|
25
|
+
301 => "Moved Permanently",
|
26
|
+
302 => "Found",
|
27
|
+
303 => "See Other",
|
28
|
+
304 => "Not Modified",
|
29
|
+
305 => "Use Proxy",
|
30
|
+
307 => "Temporary Redirect",
|
31
|
+
308 => "Permanent Redirect",
|
32
|
+
400 => "Bad Request",
|
33
|
+
401 => "Unauthorized",
|
34
|
+
402 => "Payment Required",
|
35
|
+
403 => "Forbidden",
|
36
|
+
404 => "Not Found",
|
37
|
+
405 => "Method Not Allowed",
|
38
|
+
406 => "Not Acceptable",
|
39
|
+
407 => "Proxy Authentication Required",
|
40
|
+
408 => "Request Timeout",
|
41
|
+
409 => "Conflict",
|
42
|
+
410 => "Gone",
|
43
|
+
411 => "Length Required",
|
44
|
+
412 => "Precondition Failed",
|
45
|
+
413 => "Content Too Large",
|
46
|
+
414 => "URI Too Long",
|
47
|
+
415 => "Unsupported Media Type",
|
48
|
+
416 => "Range Not Satisfiable",
|
49
|
+
417 => "Expectation Failed",
|
50
|
+
421 => "Misdirected Request",
|
51
|
+
422 => "Unprocessable Content",
|
52
|
+
423 => "Locked",
|
53
|
+
424 => "Failed Dependency",
|
54
|
+
425 => "Too Early",
|
55
|
+
426 => "Upgrade Required",
|
56
|
+
428 => "Precondition Required",
|
57
|
+
429 => "Too Many Requests",
|
58
|
+
431 => "Request Header Fields Too Large",
|
59
|
+
451 => "Unavailable For Legal Reasons",
|
60
|
+
500 => "Internal Server Error",
|
61
|
+
501 => "Not Implemented",
|
62
|
+
502 => "Bad Gateway",
|
63
|
+
503 => "Service Unavailable",
|
64
|
+
504 => "Gateway Timeout",
|
65
|
+
505 => "HTTP Version Not Supported",
|
66
|
+
506 => "Variant Also Negotiates",
|
67
|
+
507 => "Insufficient Storage",
|
68
|
+
508 => "Loop Detected",
|
69
|
+
510 => "Not Extended (OBSOLETED)",
|
70
|
+
511 => "Network Authentication Required"
|
74
71
|
}.freeze
|
75
72
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
##
|
4
|
+
# Module containing methods to filter Strings
|
5
|
+
module RequestDataFiltering
|
6
|
+
##
|
7
|
+
# Method responsible for extracting information
|
8
|
+
# provided by the client like Headers and Body
|
9
|
+
def self.extract_client_info(client)
|
10
|
+
path, parameters = extract_url_parameters(client.gets.gsub('HTTP/1.1', ''))
|
11
|
+
method_name = path.gsub('/', '_').strip!.downcase
|
12
|
+
method_name.gsub!(' ', '')
|
13
|
+
body_first_line, headers = extract_headers(client)
|
14
|
+
body = extract_body(client, body_first_line, headers['Content-Length'].to_i)
|
15
|
+
[path, method_name, headers, body, parameters]
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Method responsible for extracting the path from URI
|
20
|
+
def self.extract_path(path)
|
21
|
+
path[0] == '/' ? path[1..].gsub('/', '_') : path.gsub('/', '_')
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Method responsible for extracting the headers from request
|
26
|
+
def self.extract_headers(client)
|
27
|
+
header = client.gets.delete("\n").delete("\r")
|
28
|
+
headers = {}
|
29
|
+
while header.match(%r{[a-zA-Z0-9\-/*]*: [a-zA-Z0-9\-/*]})
|
30
|
+
split_header = header.split(':')
|
31
|
+
headers[split_header[0]] = split_header[1][1..]
|
32
|
+
header = client.gets.delete("\n").delete("\r")
|
33
|
+
end
|
34
|
+
[header, headers]
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Method responsible for extracting the body from request
|
39
|
+
def self.extract_body(client, body_first_line, content_length)
|
40
|
+
body = client.read(content_length)
|
41
|
+
body_first_line << body.to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
##
|
45
|
+
# Method responsible for extracting the parameters from URI
|
46
|
+
def self.extract_url_parameters(http_first_line)
|
47
|
+
return http_first_line, nil unless http_first_line =~ /\?/
|
48
|
+
|
49
|
+
path_and_parameters = http_first_line.split('?', 2)
|
50
|
+
path = "#{path_and_parameters[0]} "
|
51
|
+
parameters_array = path_and_parameters[1].split('&')
|
52
|
+
parameters_array.map! do |item|
|
53
|
+
split_item = item.split('=')
|
54
|
+
{ split_item[0] => split_item[1].gsub("\n", '').gsub("\r", '').gsub("\s", '') }
|
55
|
+
end
|
56
|
+
parameters = {}
|
57
|
+
parameters_array.each { |item| parameters.merge!(item) }
|
58
|
+
[path, parameters]
|
59
|
+
end
|
60
|
+
end
|
data/lib/macaw_framework.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "macaw_framework/endpoint_not_mapped_error"
|
4
|
+
require_relative "macaw_framework/request_data_filtering"
|
4
5
|
require_relative "macaw_framework/http_status_code"
|
5
6
|
require_relative "macaw_framework/version"
|
6
7
|
require "socket"
|
@@ -12,14 +13,17 @@ module MacawFramework
|
|
12
13
|
# starting the web server.
|
13
14
|
class Macaw
|
14
15
|
include(HttpStatusCode)
|
15
|
-
|
16
|
+
##
|
17
|
+
# @param {Logger} custom_log
|
18
|
+
def initialize(custom_log = nil)
|
16
19
|
begin
|
17
|
-
config = JSON.parse(File.read(
|
18
|
-
@port = config[
|
20
|
+
config = JSON.parse(File.read('application.json'))
|
21
|
+
@port = config['macaw']['port']
|
19
22
|
rescue StandardError
|
20
23
|
@port ||= 8080
|
21
24
|
end
|
22
25
|
@port ||= 8080
|
26
|
+
@macaw_log ||= custom_log.nil? ? Logger.new($stdout) : custom_log
|
23
27
|
end
|
24
28
|
|
25
29
|
##
|
@@ -29,8 +33,9 @@ module MacawFramework
|
|
29
33
|
# @param {Proc} block
|
30
34
|
# @return {Integer, String}
|
31
35
|
def get(path, &block)
|
32
|
-
path_clean =
|
33
|
-
|
36
|
+
path_clean = RequestDataFiltering.extract_path(path)
|
37
|
+
@macaw_log.info("Defining GET endpoint at #{path_clean}")
|
38
|
+
map_new_endpoint('get', path_clean, &block)
|
34
39
|
end
|
35
40
|
|
36
41
|
##
|
@@ -40,8 +45,9 @@ module MacawFramework
|
|
40
45
|
# @param {Proc} block
|
41
46
|
# @return {String, Integer}
|
42
47
|
def post(path, &block)
|
43
|
-
path_clean = path[0] ==
|
44
|
-
|
48
|
+
path_clean = path[0] == '/' ? path[1..].gsub('/', '_') : path.gsub('/', '_')
|
49
|
+
@macaw_log.info("Defining POST endpoint at #{path_clean}")
|
50
|
+
map_new_endpoint('post', path_clean, &block)
|
45
51
|
end
|
46
52
|
|
47
53
|
##
|
@@ -51,8 +57,9 @@ module MacawFramework
|
|
51
57
|
# @param {Proc} block
|
52
58
|
# @return {String, Integer}
|
53
59
|
def put(path, &block)
|
54
|
-
path_clean = path[0] ==
|
55
|
-
|
60
|
+
path_clean = path[0] == '/' ? path[1..].gsub('/', '_') : path.gsub('/', '_')
|
61
|
+
@macaw_log.info("Defining PUT endpoint at #{path_clean}")
|
62
|
+
map_new_endpoint('put', path_clean, &block)
|
56
63
|
end
|
57
64
|
|
58
65
|
##
|
@@ -62,8 +69,9 @@ module MacawFramework
|
|
62
69
|
# @param {Proc} block
|
63
70
|
# @return {String, Integer}
|
64
71
|
def patch(path, &block)
|
65
|
-
path_clean = path[0] ==
|
66
|
-
|
72
|
+
path_clean = path[0] == '/' ? path[1..].gsub('/', '_') : path.gsub('/', '_')
|
73
|
+
@macaw_log.info("Defining PATCH endpoint at #{path_clean}")
|
74
|
+
map_new_endpoint('patch', path_clean, &block)
|
67
75
|
end
|
68
76
|
|
69
77
|
##
|
@@ -73,67 +81,48 @@ module MacawFramework
|
|
73
81
|
# @param {Proc} block
|
74
82
|
# @return {String, Integer}
|
75
83
|
def delete(path, &block)
|
76
|
-
path_clean = path[0] ==
|
77
|
-
|
84
|
+
path_clean = path[0] == '/' ? path[1..].gsub('/', '_') : path.gsub('/', '_')
|
85
|
+
@macaw_log.info("Defining DELETE endpoint at #{path_clean}")
|
86
|
+
map_new_endpoint('delete', path_clean, &block)
|
78
87
|
end
|
79
88
|
|
80
89
|
##
|
81
90
|
# Starts the web server
|
82
91
|
def start!
|
92
|
+
@macaw_log.info("Starting server at port #{@port}")
|
93
|
+
time = Time.now
|
83
94
|
server = TCPServer.open(@port)
|
84
|
-
|
95
|
+
@macaw_log.info("Server started in #{Time.now - time} seconds.")
|
85
96
|
loop do
|
86
97
|
Thread.start(server.accept) do |client|
|
87
|
-
client
|
88
|
-
method_name, headers, body = extract_client_info(client)
|
98
|
+
path, method_name, headers, body, parameters = RequestDataFiltering.extract_client_info(client)
|
89
99
|
raise EndpointNotMappedError unless respond_to?(method_name)
|
90
100
|
|
91
|
-
|
101
|
+
@macaw_log.info("Running #{path.gsub("\n", '').gsub("\r", '')}")
|
102
|
+
message, status = send(method_name, headers, body, parameters)
|
92
103
|
status ||= 200
|
93
|
-
message ||=
|
104
|
+
message ||= 'Ok'
|
94
105
|
client.puts "HTTP/1.1 #{status} #{HTTP_STATUS_CODE_MAP[status]} \r\n\r\n#{message}"
|
95
106
|
client.close
|
96
107
|
rescue EndpointNotMappedError
|
97
108
|
client.print "HTTP/1.1 404 Not Found\r\n\r\n"
|
98
109
|
client.close
|
99
|
-
rescue StandardError
|
110
|
+
rescue StandardError => e
|
100
111
|
client.print "HTTP/1.1 500 Internal Server Error\r\n\r\n"
|
112
|
+
@macaw_log.info("Error: #{e}")
|
101
113
|
client.close
|
102
114
|
end
|
103
115
|
end
|
104
116
|
rescue Interrupt
|
105
|
-
|
117
|
+
@macaw_log.info('Stopping server')
|
118
|
+
server.close
|
119
|
+
@macaw_log.info('Macaw stop flying for some seeds...')
|
106
120
|
end
|
107
121
|
|
108
122
|
private
|
109
123
|
|
110
|
-
|
111
|
-
|
112
|
-
# provided by the client like Headers and Body
|
113
|
-
def extract_client_info(client)
|
114
|
-
method_name = client.gets.gsub("HTTP/1.1", "").gsub("/", "_").strip!.downcase
|
115
|
-
method_name.gsub!(" ", "")
|
116
|
-
body_first_line, headers = extract_headers(client)
|
117
|
-
body = extract_body(client, body_first_line, headers["Content-Length"].to_i)
|
118
|
-
[method_name, headers, body]
|
119
|
-
end
|
120
|
-
|
121
|
-
##
|
122
|
-
# Extract application headers
|
123
|
-
def extract_headers(client)
|
124
|
-
header = client.gets.delete("\n").delete("\r")
|
125
|
-
headers = {}
|
126
|
-
while header.match(%r{[a-zA-Z0-9\-/*]*: [a-zA-Z0-9\-/*]})
|
127
|
-
split_header = header.split(":")
|
128
|
-
headers[split_header[0]] = split_header[1][1..]
|
129
|
-
header = client.gets.delete("\n").delete("\r")
|
130
|
-
end
|
131
|
-
[header, headers]
|
132
|
-
end
|
133
|
-
|
134
|
-
def extract_body(client, body_first_line, content_length)
|
135
|
-
body = client.read(content_length)
|
136
|
-
body_first_line << body.to_s
|
124
|
+
def map_new_endpoint(prefix, path, &block)
|
125
|
+
define_singleton_method("#{prefix}_#{path}", block)
|
137
126
|
end
|
138
127
|
end
|
139
128
|
end
|
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: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aria Diniz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-12-
|
11
|
+
date: 2022-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A project started for study purpose that I intend to keep working on.
|
14
14
|
email:
|
@@ -27,7 +27,9 @@ files:
|
|
27
27
|
- lib/macaw_framework.rb
|
28
28
|
- lib/macaw_framework/endpoint_not_mapped_error.rb
|
29
29
|
- lib/macaw_framework/http_status_code.rb
|
30
|
+
- lib/macaw_framework/request_data_filtering.rb
|
30
31
|
- lib/macaw_framework/version.rb
|
32
|
+
- sig/http_status_code.rbs
|
31
33
|
- sig/macaw_framework.rbs
|
32
34
|
- sig/macaw_framework/macaw.rbs
|
33
35
|
homepage: https://github.com/ariasdiniz/macaw_framework
|