tsurezure 0.0.34 → 0.0.36

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,24 +1,24 @@
1
- # frozen_string_literal: true
2
-
3
- # for storing generic, reusable error codes.
4
- module ErrorCodes
5
- def self.nan_error(item)
6
- "invalid parameter: #{item} must be a number."
7
- end
8
-
9
- def self.no_method_error(item)
10
- "invalid http method: #{item} is not a valid http method."
11
- end
12
-
13
- def self.invalid_type_error(item)
14
- "invalid type: #{item} is not a valid type."
15
- end
16
-
17
- def self.range_error(min, max)
18
- "invalid port number: port must be in range [#{min}, #{max}]"
19
- end
20
-
21
- def self.invalid_structure_error(keys, method)
22
- "invalid object with keys #{keys} supplied to #{method}"
23
- end
24
- end
1
+ # frozen_string_literal: true
2
+
3
+ # for storing generic, reusable error codes.
4
+ module ErrorCodes
5
+ def self.nan_error(item)
6
+ "invalid parameter: #{item} must be a number."
7
+ end
8
+
9
+ def self.no_method_error(item)
10
+ "invalid http method: #{item} is not a valid http method."
11
+ end
12
+
13
+ def self.invalid_type_error(item)
14
+ "invalid type: #{item} is not a valid type."
15
+ end
16
+
17
+ def self.range_error(min, max)
18
+ "invalid port number: port must be in range [#{min}, #{max}]"
19
+ end
20
+
21
+ def self.invalid_structure_error(keys, method)
22
+ "invalid object with keys #{keys} supplied to #{method}"
23
+ end
24
+ end
data/lib/utils/errors.rb CHANGED
@@ -1,65 +1,65 @@
1
- # frozen_string_literal: true
2
-
3
- # simple methods for showing error messages
4
- module ErrorMessage
5
- def self.invalid_key_error(method, key)
6
- raise ArgumentError, {
7
- message: "invalid key '#{key}' used as parameter to #{method}."
8
- }.to_json
9
- end
10
-
11
- def self.invalid_http_method_error(key, val, method)
12
- raise ArgumentError, {
13
- message: "#{key} used to access #{method}. use #{val}.",
14
- status: 405,
15
- options: {
16
- allowed: val
17
- }
18
- }.to_json
19
- end
20
-
21
- def self.missing_arguments_error(method)
22
- raise ArgumentError, {
23
- status: 500,
24
- message: "missing arguments to #{method}"
25
- }.to_json
26
- end
27
-
28
- def self.missing_parameter_error(method)
29
- raise ArgumentError, {
30
- status: 400,
31
- message: "missing url parameter id to #{method}."
32
- }.to_json
33
- end
34
-
35
- def self.invalid_structure_error(method, keys)
36
- raise ArgumentError, {
37
- status: 400,
38
- message: "invalid object with keys #{keys} passed to #{method}."
39
- }.to_json
40
- end
41
-
42
- def self.make_http_error(status, message, options)
43
- error = { status: status, options: options }
44
- error.delete :options if options.nil?
45
-
46
- case status.to_s.chr.to_i
47
- when 4
48
- error[:message] = "bad request: #{message}"
49
- when 5
50
- error[:message] = "server error: #{message}"
51
- end
52
-
53
- error.to_json
54
- end
55
- end
56
-
57
- # module for multiple custom error classes
58
- module CustomError
59
- # for throwing a server error (like 500)
60
- class ServerError < StandardError
61
- def initialize(message = 'an internal server error occurred.')
62
- super
63
- end
64
- end
65
- end
1
+ # frozen_string_literal: true
2
+
3
+ # simple methods for showing error messages
4
+ module ErrorMessage
5
+ def self.invalid_key_error(method, key)
6
+ raise ArgumentError, {
7
+ message: "invalid key '#{key}' used as parameter to #{method}."
8
+ }.to_json
9
+ end
10
+
11
+ def self.invalid_http_method_error(key, val, method)
12
+ raise ArgumentError, {
13
+ message: "#{key} used to access #{method}. use #{val}.",
14
+ status: 405,
15
+ options: {
16
+ allowed: val
17
+ }
18
+ }.to_json
19
+ end
20
+
21
+ def self.missing_arguments_error(method)
22
+ raise ArgumentError, {
23
+ status: 500,
24
+ message: "missing arguments to #{method}"
25
+ }.to_json
26
+ end
27
+
28
+ def self.missing_parameter_error(method)
29
+ raise ArgumentError, {
30
+ status: 400,
31
+ message: "missing url parameter id to #{method}."
32
+ }.to_json
33
+ end
34
+
35
+ def self.invalid_structure_error(method, keys)
36
+ raise ArgumentError, {
37
+ status: 400,
38
+ message: "invalid object with keys #{keys} passed to #{method}."
39
+ }.to_json
40
+ end
41
+
42
+ def self.make_http_error(status, message, options)
43
+ error = { status: status, options: options }
44
+ error.delete :options if options.nil?
45
+
46
+ case status.to_s.chr.to_i
47
+ when 4
48
+ error[:message] = "bad request: #{message}"
49
+ when 5
50
+ error[:message] = "server error: #{message}"
51
+ end
52
+
53
+ error.to_json
54
+ end
55
+ end
56
+
57
+ # module for multiple custom error classes
58
+ module CustomError
59
+ # for throwing a server error (like 500)
60
+ class ServerError < StandardError
61
+ def initialize(message = 'an internal server error occurred.')
62
+ super
63
+ end
64
+ end
65
+ end
@@ -1,202 +1,212 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'logbook'
4
-
5
- # all utilities for dealing with http-related things
6
- module HTTPUtils
7
- include Logbook
8
- # class URLUtils - for dealing with urls
9
- class URLUtils
10
- def self.extract_url_params(url)
11
- url_params = {}
12
-
13
- if url.split('?')
14
- .length > 1
15
- url.split('?')[1].split('&').map do |e|
16
- key, value = e.split('=')
17
-
18
- break if value.nil?
19
-
20
- url_params[key] = value
21
- end
22
- end
23
-
24
- url_params
25
- end
26
-
27
- def self.url_path_matches?(url, path)
28
- return true if url == path
29
-
30
- split_url = url.split '/'
31
- split_path = path.split '/'
32
-
33
- return false if split_url.empty? || split_url.length != split_path.length
34
-
35
- true
36
- end
37
-
38
- def self.get_match_indices(url, path)
39
- split_url = url.split '/'
40
- split_path = path.split '/'
41
-
42
- hash_with_variables = {}
43
-
44
- return unless url_path_matches? url, path
45
-
46
- split_url.each_with_index do |pname, idx|
47
- part = pname.sub(':', '')
48
- hash_with_variables[part] = split_path[idx] if pname[0] == ':'
49
- end
50
-
51
- hash_with_variables
52
- end
53
-
54
- def self.matches_url_regex?(url, regex)
55
- return unless url_path_matches? url, regex
56
-
57
- matches = url.scan %r{((?<=\/):[^\/]+)}
58
- newregexp = url.dup
59
-
60
- return url.match? Regexp.new("^#{regex}$") if matches.empty?
61
-
62
- matches.each do |mat|
63
- newregexp.gsub!(Regexp.new(mat[0].to_s), '.+')
64
- end
65
-
66
- url.match? Regexp.new(newregexp)
67
- end
68
- end
69
-
70
- # for dealing with header data.
71
- class HeaderUtils
72
- def self.get_headers(client)
73
- headers = {}
74
-
75
- while (line = client.gets.split(' ', 2))
76
- break if line[0] == ''
77
-
78
- headers[line[0].chop] = line[1].strip
79
- end
80
-
81
- headers
82
- end
83
-
84
- def self.get_req_data(client, headers)
85
- data = client.read headers['Content-Length'].to_i
86
-
87
- return if data.empty?
88
-
89
- data
90
- end
91
- end
92
-
93
- def self.make_proper_request(client, request)
94
- headers = HeaderUtils.get_headers(client)
95
- data = HeaderUtils.get_req_data(client, headers)
96
- method = request.split(' ')[0]
97
- url = request.split(' ')[1]
98
- proto = request.split(' ')[2]
99
-
100
- { headers: headers, data: data, method: method, url: url, protocol: proto }
101
- end
102
-
103
- def self.make_request_object(req)
104
- req[:data] = '{}' if req[:data].nil?
105
-
106
- {
107
- headers: req[:headers],
108
- data: JSON.parse(req[:data]),
109
- method: req[:method],
110
- url: req[:url],
111
- protocol: req[:protocol]
112
- }
113
- end
114
-
115
- # class ServerResponses - for sending HTTP responses
116
- class ServerResponse
117
- def initialize(session, length)
118
- @session = session
119
- @length = length
120
- end
121
-
122
- def valid_options?(options)
123
- acceptable_keys = %i[location method]
124
-
125
- return true if acceptable_keys.any? { |key| options.key? key }
126
-
127
- false
128
- end
129
-
130
- def respond(response,
131
- options = {},
132
- status = 200,
133
- content_type = 'application/json')
134
- @content_type = options[:content_type] || content_type
135
-
136
- if respond_to? "r_#{status}"
137
- method("r_#{status}").call unless valid_options? options
138
- method("r_#{status}").call options if valid_options? options
139
- else
140
- r_400
141
- end
142
-
143
- @session.puts
144
- @session.puts response
145
- @session.close
146
- end
147
-
148
- def r_200
149
- @session.puts 'HTTP/1.1 200 OK'
150
- @session.puts "Content-Type: #{@content_type}"
151
- @session.puts "Content-Length: #{@length}"
152
- end
153
-
154
- def r_201
155
- @session.puts 'HTTP/1.1 201 Created'
156
- @session.puts "Content-Type: #{@content_type}"
157
- @session.puts "Content-Length: #{@length}"
158
- end
159
-
160
- def r_301(options)
161
- @session.puts 'HTTP/1.1 301 Moved Permanently'
162
- @session.puts "Content-Type: #{@content_type}"
163
- @session.puts "Content-Length: #{@length}"
164
- @session.puts "Location: #{options[:location]}"
165
- end
166
-
167
- def r_304
168
- @session.puts 'HTTP/1.1 304 Not Modified'
169
- @session.puts "Content-Type: #{@content_type}"
170
- @session.puts "Content-Length: #{@length}"
171
- end
172
-
173
- def r_400
174
- @session.puts 'HTTP/1.1 400 Bad Request'
175
- @session.puts "Content-Type: #{@content_type}"
176
- @session.puts "Content-Length: #{@length}"
177
- end
178
-
179
- def r_404
180
- @session.puts 'HTTP/1.1 404 Not Found'
181
- @session.puts "Content-Type: #{@content_type}"
182
- @session.puts "Content-Length: #{@length}"
183
- end
184
-
185
- def r_405(options)
186
- @session.puts 'HTTP/1.1 405 Method Not Allowed'
187
- @session.puts "Content-Type: #{@content_type}"
188
- @session.puts "Content-Length: #{@length}"
189
- @session.puts "Allow: #{options[:method]}"
190
- end
191
-
192
- def r_500
193
- @session.puts 'HTTP/1.1 500 Internal Server Error'
194
- @session.puts "Content-Type: #{@content_type}"
195
- @session.puts "Content-Length: #{@length}"
196
- end
197
- end
198
- end
199
-
200
- __END__
201
-
202
- this is the file that made me realize that the content_length header actually directly controls the length of the content in the response. I incorrectly set the content_length once as a mistake, and my responses were coming out short. interesting!
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'logbook'
4
+
5
+ # all utilities for dealing with http-related things
6
+ module HTTPUtils
7
+ include Logbook
8
+ # class URLUtils - for dealing with urls
9
+ class URLUtils
10
+ def self.extract_url_params(url)
11
+ url_params = {}
12
+
13
+ if url.split('?')
14
+ .length > 1
15
+ url.split('?')[1].split('&').map do |e|
16
+ key, value = e.split('=')
17
+
18
+ break if value.nil?
19
+
20
+ url_params[key] = value
21
+ end
22
+ end
23
+
24
+ url_params
25
+ end
26
+
27
+ # TODO: make this less complicated
28
+ # hello, eris from [current year]! have you been practicing? good luck!
29
+ def self.url_path_matches?(url, path)
30
+ return true if url == path
31
+
32
+ split_url = url.split '/'
33
+ split_path = path.split '/'
34
+ non_var_equality = true
35
+
36
+ return false if split_url.length != split_path.length
37
+
38
+ split_path.each_with_index do |p, i|
39
+ next if split_url[i][0] == ':'
40
+ non_var_equality = false if p != split_url[i]
41
+ end
42
+
43
+ return false unless non_var_equality == true
44
+ return false if split_url.empty?
45
+ true
46
+ end
47
+
48
+ def self.get_match_indices(url, path)
49
+ split_url = url.split '/'
50
+ split_path = path.split '/'
51
+
52
+ hash_with_variables = {}
53
+
54
+ return unless url_path_matches? url, path
55
+
56
+ split_url.each_with_index do |pname, idx|
57
+ part = pname.sub(':', '')
58
+ hash_with_variables[part] = split_path[idx] if pname[0] == ':'
59
+ end
60
+
61
+ hash_with_variables
62
+ end
63
+
64
+ def self.matches_url_regex?(url, regex)
65
+ return unless url_path_matches? url, regex
66
+
67
+ matches = url.scan %r{((?<=/):[^/]+)}
68
+ newregexp = url.dup
69
+
70
+ return url.match? Regexp.new("^#{regex}$") if matches.empty?
71
+
72
+ matches.each do |mat|
73
+ newregexp.gsub!(Regexp.new(mat[0].to_s), '.+')
74
+ end
75
+
76
+ url.match? Regexp.new(newregexp)
77
+ end
78
+ end
79
+
80
+ # for dealing with header data.
81
+ class HeaderUtils
82
+ def self.get_headers(client)
83
+ headers = {}
84
+
85
+ while (line = client.gets.split(' ', 2))
86
+ break if line[0] == ''
87
+
88
+ headers[line[0].chop] = line[1].strip
89
+ end
90
+
91
+ headers
92
+ end
93
+
94
+ def self.get_req_data(client, headers)
95
+ data = client.read headers['Content-Length'].to_i
96
+
97
+ return if data.empty?
98
+
99
+ data
100
+ end
101
+ end
102
+
103
+ def self.make_proper_request(client, request)
104
+ headers = HeaderUtils.get_headers(client)
105
+ data = HeaderUtils.get_req_data(client, headers)
106
+ method = request.split(' ')[0]
107
+ url = request.split(' ')[1]
108
+ proto = request.split(' ')[2]
109
+
110
+ { headers: headers, data: data, method: method, url: url, protocol: proto }
111
+ end
112
+
113
+ def self.make_request_object(req)
114
+ req[:data] = '{}' if req[:data].nil?
115
+
116
+ {
117
+ headers: req[:headers],
118
+ data: JSON.parse(req[:data]),
119
+ method: req[:method],
120
+ url: req[:url],
121
+ protocol: req[:protocol]
122
+ }
123
+ end
124
+
125
+ # class ServerResponses - for sending HTTP responses
126
+ class ServerResponse
127
+ def initialize(session, length)
128
+ @session = session
129
+ @length = length
130
+ end
131
+
132
+ def valid_options?(options)
133
+ acceptable_keys = %i[location method]
134
+
135
+ return true if acceptable_keys.any? { |key| options.key? key }
136
+
137
+ false
138
+ end
139
+
140
+ def respond(response,
141
+ options = {},
142
+ status = 200,
143
+ content_type = 'application/json')
144
+ @content_type = options[:content_type] || content_type
145
+
146
+ if respond_to? "r#{status}"
147
+ method("r#{status}").call unless valid_options? options
148
+ method("r#{status}").call options if valid_options? options
149
+ else
150
+ r400
151
+ end
152
+
153
+ @session.puts
154
+ @session.puts response
155
+ @session.close
156
+ end
157
+
158
+ def r200
159
+ @session.puts 'HTTP/1.1 200 OK'
160
+ @session.puts "Content-Type: #{@content_type}"
161
+ @session.puts "Content-Length: #{@length}"
162
+ end
163
+
164
+ def r201
165
+ @session.puts 'HTTP/1.1 201 Created'
166
+ @session.puts "Content-Type: #{@content_type}"
167
+ @session.puts "Content-Length: #{@length}"
168
+ end
169
+
170
+ def r301(options)
171
+ @session.puts 'HTTP/1.1 301 Moved Permanently'
172
+ @session.puts "Content-Type: #{@content_type}"
173
+ @session.puts "Content-Length: #{@length}"
174
+ @session.puts "Location: #{options[:location]}"
175
+ end
176
+
177
+ def r304
178
+ @session.puts 'HTTP/1.1 304 Not Modified'
179
+ @session.puts "Content-Type: #{@content_type}"
180
+ @session.puts "Content-Length: #{@length}"
181
+ end
182
+
183
+ def r400
184
+ @session.puts 'HTTP/1.1 400 Bad Request'
185
+ @session.puts "Content-Type: #{@content_type}"
186
+ @session.puts "Content-Length: #{@length}"
187
+ end
188
+
189
+ def r404
190
+ @session.puts 'HTTP/1.1 404 Not Found'
191
+ @session.puts "Content-Type: #{@content_type}"
192
+ @session.puts "Content-Length: #{@length}"
193
+ end
194
+
195
+ def r405(options)
196
+ @session.puts 'HTTP/1.1 405 Method Not Allowed'
197
+ @session.puts "Content-Type: #{@content_type}"
198
+ @session.puts "Content-Length: #{@length}"
199
+ @session.puts "Allow: #{options[:method]}"
200
+ end
201
+
202
+ def r500
203
+ @session.puts 'HTTP/1.1 500 Internal Server Error'
204
+ @session.puts "Content-Type: #{@content_type}"
205
+ @session.puts "Content-Length: #{@length}"
206
+ end
207
+ end
208
+ end
209
+
210
+ __END__
211
+
212
+ this is the file that made me realize that the content_length header actually directly controls the length of the content in the response. I incorrectly set the content_length once as a mistake, and my responses were coming out short. interesting!