macaw_framework 0.1.3 → 0.1.5
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/.rubocop.yml +3 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +2 -0
- data/README.md +11 -3
- data/lib/macaw_framework/aspects/logging_aspect.rb +16 -0
- data/lib/macaw_framework/middlewares/request_data_filtering.rb +119 -0
- data/lib/macaw_framework/middlewares/server.rb +85 -0
- data/lib/macaw_framework/version.rb +1 -1
- data/lib/macaw_framework.rb +27 -34
- data/macaw_logo.png +0 -0
- data/sig/logging_aspect.rbs +3 -0
- data/sig/macaw_framework/macaw.rbs +8 -0
- data/sig/request_data_filtering.rbs +3 -0
- data/sig/server.rbs +25 -0
- metadata +12 -6
- data/lib/macaw_framework/request_data_filtering.rb +0 -60
- /data/lib/macaw_framework/{endpoint_not_mapped_error.rb → errors/endpoint_not_mapped_error.rb} +0 -0
- /data/lib/macaw_framework/{http_status_code.rb → utils/http_status_code.rb} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d900a18480da4792dfa03608ca8c85c0d0ba4084a3430c39008f4ca026ae784c
|
4
|
+
data.tar.gz: e3bc35f7b78bc0a6e995c0abd906879dda434e4c12306d3d55713c35dc45065c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ac4eb646bb2510fbc67ddec9ccfca45bea8dfcb6833f9e55b60f0f18d5edebaf392645c53dae7745eec797c926af1700c273516682bd6f10e66c2b018f1cea6
|
7
|
+
data.tar.gz: 0ecb2e16a9f1762833751bb403d824e04571c4f3b79f01355ffb6f1f29eb29c234befc759c7d76d7b939f05d5f9f3c252d8a5828198e9c7674b7854fe2edcdf1
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -18,3 +18,9 @@
|
|
18
18
|
## [0.1.3] - 2022-12-13
|
19
19
|
|
20
20
|
- Adding logger gem to Macaw class to fix a bug on the application start
|
21
|
+
|
22
|
+
## [0.1.4] - 2023-04-09
|
23
|
+
|
24
|
+
- Adding log by aspect on endpoint calls to improve observability
|
25
|
+
- Moving the server for a new separate class to respect single responsibility
|
26
|
+
- Improved the data filtering middleware to sanitize inputs
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
# MacawFramework
|
2
2
|
|
3
|
+
<img src="macaw_logo.png" alt= “” style="width: 30%;height: 30%;margin-left: 35%">
|
4
|
+
|
3
5
|
This is a framework for developing web applications. Please have in mind that this is still a work in progress and
|
4
|
-
it is strongly advised to not use it for production purposes for now.
|
6
|
+
it is strongly advised to not use it for production purposes for now. Actualy it supports only HTTP. HTTPS and SSL
|
7
|
+
support will be implemented soon. Anyone who wishes to contribute is welcome.
|
5
8
|
|
6
9
|
## Installation
|
7
10
|
|
@@ -24,7 +27,9 @@ in the same directory of the script that will start the application with the fol
|
|
24
27
|
```json
|
25
28
|
{
|
26
29
|
"macaw": {
|
27
|
-
"port":
|
30
|
+
"port": 8080,
|
31
|
+
"bind": "localhost",
|
32
|
+
"threads": 10
|
28
33
|
}
|
29
34
|
}
|
30
35
|
```
|
@@ -37,7 +42,10 @@ require 'json'
|
|
37
42
|
|
38
43
|
m = MacawFramework::Macaw.new
|
39
44
|
|
40
|
-
m.get('/hello_world') do |
|
45
|
+
m.get('/hello_world') do |context|
|
46
|
+
context[:body] # Returns the request body as string
|
47
|
+
context[:params] # Returns query parameters and path variables as a hash
|
48
|
+
context[:headers] # Returns headers as a hash
|
41
49
|
return JSON.pretty_generate({ hello_message: 'Hello World!' }), 200
|
42
50
|
end
|
43
51
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
##
|
6
|
+
# This Aspect is responsible for logging
|
7
|
+
# the input and output of every endpoint called
|
8
|
+
# in the framework.
|
9
|
+
module LoggingAspect
|
10
|
+
def call_endpoint(logger, *args)
|
11
|
+
logger.info("Input of #{args[0]}: #{args}")
|
12
|
+
response = super(*args)
|
13
|
+
logger.info("Output of #{args[0]} #{response}")
|
14
|
+
response
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../errors/endpoint_not_mapped_error"
|
4
|
+
|
5
|
+
##
|
6
|
+
# Module containing methods to filter Strings
|
7
|
+
module RequestDataFiltering
|
8
|
+
VARIABLE_PATTERN = %r{:[^/]+}.freeze
|
9
|
+
|
10
|
+
##
|
11
|
+
# Method responsible for extracting information
|
12
|
+
# provided by the client like Headers and Body
|
13
|
+
def self.parse_request_data(client, routes)
|
14
|
+
path, parameters = extract_url_parameters(client.gets.gsub("HTTP/1.1", ""))
|
15
|
+
parameters = {} if parameters.nil?
|
16
|
+
|
17
|
+
method_name = sanitize_method_name(path)
|
18
|
+
method_name = select_path(method_name, routes, parameters)
|
19
|
+
body_first_line, headers = extract_headers(client)
|
20
|
+
body = extract_body(client, body_first_line, headers["Content-Length"].to_i)
|
21
|
+
[path, method_name, headers, body, parameters]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.select_path(method_name, routes, parameters)
|
25
|
+
return method_name if routes.include?(method_name)
|
26
|
+
|
27
|
+
selected_route = nil
|
28
|
+
routes.each do |route|
|
29
|
+
split_route = route.split(".")
|
30
|
+
split_name = method_name.split(".")
|
31
|
+
|
32
|
+
next unless split_route.length == split_name.length
|
33
|
+
next unless match_path_with_route(split_name, split_route)
|
34
|
+
|
35
|
+
selected_route = route
|
36
|
+
split_route.each_with_index do |var, index|
|
37
|
+
parameters[var[1..].to_sym] = split_name[index] if var =~ VARIABLE_PATTERN
|
38
|
+
end
|
39
|
+
break
|
40
|
+
end
|
41
|
+
|
42
|
+
raise EndpointNotMappedError if selected_route.nil?
|
43
|
+
|
44
|
+
selected_route
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.match_path_with_route(split_path, split_route)
|
48
|
+
split_route.each_with_index do |var, index|
|
49
|
+
return false if var != split_path[index] && !var.match?(VARIABLE_PATTERN)
|
50
|
+
end
|
51
|
+
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Method responsible for sanitizing the method name
|
57
|
+
def self.sanitize_method_name(path)
|
58
|
+
path = extract_path(path)
|
59
|
+
method_name = path.gsub("/", ".").strip.downcase
|
60
|
+
method_name.gsub!(" ", "")
|
61
|
+
method_name
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Method responsible for extracting the path from URI
|
66
|
+
def self.extract_path(path)
|
67
|
+
path[0] == "/" ? path[1..].gsub("/", ".") : path.gsub("/", ".")
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Method responsible for extracting the headers from request
|
72
|
+
def self.extract_headers(client)
|
73
|
+
header = client.gets.delete("\n").delete("\r")
|
74
|
+
headers = {}
|
75
|
+
while header.match(%r{[a-zA-Z0-9\-/*]*: [a-zA-Z0-9\-/*]})
|
76
|
+
split_header = header.split(":")
|
77
|
+
headers[split_header[0].strip] = split_header[1].strip
|
78
|
+
header = client.gets.delete("\n").delete("\r")
|
79
|
+
end
|
80
|
+
[header, headers]
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# Method responsible for extracting the body from request
|
85
|
+
def self.extract_body(client, body_first_line, content_length)
|
86
|
+
body = client.read(content_length)
|
87
|
+
body_first_line << body.to_s
|
88
|
+
end
|
89
|
+
|
90
|
+
##
|
91
|
+
# Method responsible for extracting the parameters from URI
|
92
|
+
def self.extract_url_parameters(http_first_line)
|
93
|
+
return http_first_line, nil unless http_first_line =~ /\?/
|
94
|
+
|
95
|
+
path_and_parameters = http_first_line.split("?", 2)
|
96
|
+
path = "#{path_and_parameters[0]} "
|
97
|
+
parameters_array = path_and_parameters[1].split("&")
|
98
|
+
parameters_array.map! do |item|
|
99
|
+
split_item = item.split("=")
|
100
|
+
{ sanitize_parameter_name(split_item[0]) => sanitize_parameter_value(split_item[1]) }
|
101
|
+
end
|
102
|
+
parameters = {}
|
103
|
+
parameters_array.each { |item| parameters.merge!(item) }
|
104
|
+
[path, parameters]
|
105
|
+
end
|
106
|
+
|
107
|
+
##
|
108
|
+
# Method responsible for sanitizing the parameter name
|
109
|
+
def self.sanitize_parameter_name(name)
|
110
|
+
name.gsub(/[^\w\s]/, "")
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# Method responsible for sanitizing the parameter value
|
115
|
+
def self.sanitize_parameter_value(value)
|
116
|
+
value.gsub(/[^\w\s]/, "")
|
117
|
+
value.gsub(/[\r\n\s]/, "")
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../aspects/logging_aspect"
|
4
|
+
require_relative "../utils/http_status_code"
|
5
|
+
|
6
|
+
##
|
7
|
+
# Class responsible for providing a default
|
8
|
+
# webserver.
|
9
|
+
class Server
|
10
|
+
prepend LoggingAspect
|
11
|
+
include HttpStatusCode
|
12
|
+
|
13
|
+
##
|
14
|
+
# Create a new instance of Server.
|
15
|
+
# @param {Macaw} macaw
|
16
|
+
# @param {Logger} logger
|
17
|
+
# @param {Integer} port
|
18
|
+
# @param {String} bind
|
19
|
+
# @param {Integer} num_threads
|
20
|
+
# @return {Server}
|
21
|
+
def initialize(macaw, logger, port, bind, num_threads)
|
22
|
+
@port = port
|
23
|
+
@bind = bind
|
24
|
+
@macaw = macaw
|
25
|
+
@macaw_log = logger
|
26
|
+
@num_threads = num_threads
|
27
|
+
@work_queue = Queue.new
|
28
|
+
@workers = []
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Start running the webserver.
|
33
|
+
def run
|
34
|
+
@server = TCPServer.new(@bind, @port)
|
35
|
+
@num_threads.times do
|
36
|
+
@workers << Thread.new do
|
37
|
+
loop do
|
38
|
+
client = @work_queue.pop
|
39
|
+
break if client == :shutdown
|
40
|
+
|
41
|
+
handle_client(client)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
loop do
|
47
|
+
@work_queue << @server.accept
|
48
|
+
rescue IOError, Errno::EBADF
|
49
|
+
break
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Method Responsible for closing the TCP server.
|
55
|
+
def close
|
56
|
+
@server.close
|
57
|
+
@num_threads.times { @work_queue << :shutdown }
|
58
|
+
@workers.each(&:join)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def handle_client(client)
|
64
|
+
path, method_name, headers, body, parameters = RequestDataFiltering.parse_request_data(client, @macaw.routes)
|
65
|
+
raise EndpointNotMappedError unless @macaw.respond_to?(method_name)
|
66
|
+
|
67
|
+
@macaw_log.info("Running #{path.gsub("\n", "").gsub("\r", "")}")
|
68
|
+
message, status = call_endpoint(@macaw_log, method_name, headers, body, parameters)
|
69
|
+
status ||= 200
|
70
|
+
message ||= "Ok"
|
71
|
+
client.puts "HTTP/1.1 #{status} #{HTTP_STATUS_CODE_MAP[status]} \r\n\r\n#{message}"
|
72
|
+
client.close
|
73
|
+
rescue EndpointNotMappedError
|
74
|
+
client.print "HTTP/1.1 404 Not Found\r\n\r\n"
|
75
|
+
client.close
|
76
|
+
rescue StandardError => e
|
77
|
+
client.print "HTTP/1.1 500 Internal Server Error\r\n\r\n"
|
78
|
+
@macaw_log.info("Error: #{e}")
|
79
|
+
client.close
|
80
|
+
end
|
81
|
+
|
82
|
+
def call_endpoint(name, headers, body, parameters)
|
83
|
+
@macaw.send(name.to_sym, { headers: headers, body: body, params: parameters })
|
84
|
+
end
|
85
|
+
end
|
data/lib/macaw_framework.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "macaw_framework/endpoint_not_mapped_error"
|
4
|
-
require_relative "macaw_framework/request_data_filtering"
|
5
|
-
require_relative "macaw_framework/
|
3
|
+
require_relative "macaw_framework/errors/endpoint_not_mapped_error"
|
4
|
+
require_relative "macaw_framework/middlewares/request_data_filtering"
|
5
|
+
require_relative "macaw_framework/middlewares/server"
|
6
6
|
require_relative "macaw_framework/version"
|
7
7
|
require "logger"
|
8
8
|
require "socket"
|
@@ -13,18 +13,27 @@ module MacawFramework
|
|
13
13
|
# Class responsible for creating endpoints and
|
14
14
|
# starting the web server.
|
15
15
|
class Macaw
|
16
|
-
|
16
|
+
##
|
17
|
+
# Array containing the routes defined in the application
|
18
|
+
attr_reader :routes
|
19
|
+
|
17
20
|
##
|
18
21
|
# @param {Logger} custom_log
|
19
|
-
def initialize(custom_log
|
22
|
+
def initialize(custom_log: nil, server: Server)
|
20
23
|
begin
|
24
|
+
@routes = []
|
25
|
+
@macaw_log ||= custom_log.nil? ? Logger.new($stdout) : custom_log
|
21
26
|
config = JSON.parse(File.read("application.json"))
|
22
27
|
@port = config["macaw"]["port"]
|
23
|
-
|
24
|
-
@
|
28
|
+
@bind = config["macaw"]["bind"]
|
29
|
+
@threads = config["macaw"]["threads"].to_i
|
30
|
+
rescue StandardError => e
|
31
|
+
@macaw_log.error(e.message)
|
25
32
|
end
|
26
33
|
@port ||= 8080
|
27
|
-
@
|
34
|
+
@bind ||= "localhost"
|
35
|
+
@threads ||= 5
|
36
|
+
@server = server.new(self, @macaw_log, @port, @bind, @threads)
|
28
37
|
end
|
29
38
|
|
30
39
|
##
|
@@ -80,46 +89,30 @@ module MacawFramework
|
|
80
89
|
##
|
81
90
|
# Starts the web server
|
82
91
|
def start!
|
92
|
+
@macaw_log.info("---------------------------------")
|
83
93
|
@macaw_log.info("Starting server at port #{@port}")
|
84
|
-
|
85
|
-
|
86
|
-
@
|
87
|
-
server_loop(server)
|
94
|
+
@macaw_log.info("Number of threads: #{@threads}")
|
95
|
+
@macaw_log.info("---------------------------------")
|
96
|
+
server_loop(@server)
|
88
97
|
rescue Interrupt
|
89
98
|
@macaw_log.info("Stopping server")
|
90
|
-
server.close
|
99
|
+
@server.close
|
91
100
|
@macaw_log.info("Macaw stop flying for some seeds...")
|
92
101
|
end
|
93
102
|
|
94
103
|
private
|
95
104
|
|
96
105
|
def server_loop(server)
|
97
|
-
|
98
|
-
Thread.start(server.accept) do |client|
|
99
|
-
path, method_name, headers, body, parameters = RequestDataFiltering.extract_client_info(client)
|
100
|
-
raise EndpointNotMappedError unless respond_to?(method_name)
|
101
|
-
|
102
|
-
@macaw_log.info("Running #{path.gsub("\n", "").gsub("\r", "")}")
|
103
|
-
message, status = send(method_name, headers, body, parameters)
|
104
|
-
status ||= 200
|
105
|
-
message ||= "Ok"
|
106
|
-
client.puts "HTTP/1.1 #{status} #{HTTP_STATUS_CODE_MAP[status]} \r\n\r\n#{message}"
|
107
|
-
client.close
|
108
|
-
rescue EndpointNotMappedError
|
109
|
-
client.print "HTTP/1.1 404 Not Found\r\n\r\n"
|
110
|
-
client.close
|
111
|
-
rescue StandardError => e
|
112
|
-
client.print "HTTP/1.1 500 Internal Server Error\r\n\r\n"
|
113
|
-
@macaw_log.info("Error: #{e}")
|
114
|
-
client.close
|
115
|
-
end
|
116
|
-
end
|
106
|
+
server.run
|
117
107
|
end
|
118
108
|
|
119
109
|
def map_new_endpoint(prefix, path, &block)
|
120
110
|
path_clean = RequestDataFiltering.extract_path(path)
|
121
111
|
@macaw_log.info("Defining #{prefix.upcase} endpoint at /#{path}")
|
122
|
-
define_singleton_method("#{prefix}
|
112
|
+
define_singleton_method("#{prefix}.#{path_clean}", block || lambda {
|
113
|
+
|context = { headers: {}, body: "", params: {} }|
|
114
|
+
})
|
115
|
+
@routes << "#{prefix}.#{path_clean}"
|
123
116
|
end
|
124
117
|
end
|
125
118
|
end
|
data/macaw_logo.png
ADDED
Binary file
|
data/sig/server.rbs
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
class Server
|
2
|
+
@bind: String
|
3
|
+
@macaw: MacawFramework::Macaw
|
4
|
+
@macaw_log: Logger
|
5
|
+
@num_threads: Integer
|
6
|
+
@port: Integer
|
7
|
+
|
8
|
+
@server: TCPServer
|
9
|
+
|
10
|
+
@threads: Integer
|
11
|
+
|
12
|
+
@work_queue: Thread::Queue
|
13
|
+
|
14
|
+
@workers: Array[Thread]
|
15
|
+
|
16
|
+
def close: -> nil
|
17
|
+
|
18
|
+
def run: -> nil
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def call_endpoint: -> Array[untyped]
|
23
|
+
|
24
|
+
def handle_client: -> nil
|
25
|
+
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.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aria Diniz
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-04-16 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:
|
@@ -25,13 +25,19 @@ files:
|
|
25
25
|
- README.md
|
26
26
|
- Rakefile
|
27
27
|
- lib/macaw_framework.rb
|
28
|
-
- lib/macaw_framework/
|
29
|
-
- lib/macaw_framework/
|
30
|
-
- lib/macaw_framework/request_data_filtering.rb
|
28
|
+
- lib/macaw_framework/aspects/logging_aspect.rb
|
29
|
+
- lib/macaw_framework/errors/endpoint_not_mapped_error.rb
|
30
|
+
- lib/macaw_framework/middlewares/request_data_filtering.rb
|
31
|
+
- lib/macaw_framework/middlewares/server.rb
|
32
|
+
- lib/macaw_framework/utils/http_status_code.rb
|
31
33
|
- lib/macaw_framework/version.rb
|
34
|
+
- macaw_logo.png
|
32
35
|
- sig/http_status_code.rbs
|
36
|
+
- sig/logging_aspect.rbs
|
33
37
|
- sig/macaw_framework.rbs
|
34
38
|
- sig/macaw_framework/macaw.rbs
|
39
|
+
- sig/request_data_filtering.rbs
|
40
|
+
- sig/server.rbs
|
35
41
|
homepage: https://github.com/ariasdiniz/macaw_framework
|
36
42
|
licenses:
|
37
43
|
- MIT
|
@@ -54,7 +60,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
60
|
- !ruby/object:Gem::Version
|
55
61
|
version: '0'
|
56
62
|
requirements: []
|
57
|
-
rubygems_version: 3.
|
63
|
+
rubygems_version: 3.4.10
|
58
64
|
signing_key:
|
59
65
|
specification_version: 4
|
60
66
|
summary: A web framework still in development.
|
@@ -1,60 +0,0 @@
|
|
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/{endpoint_not_mapped_error.rb → errors/endpoint_not_mapped_error.rb}
RENAMED
File without changes
|
File without changes
|