ronin-web-server 0.1.0.beta1
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 +7 -0
- data/.document +5 -0
- data/.github/workflows/ruby.yml +41 -0
- data/.gitignore +13 -0
- data/.rspec +1 -0
- data/.rubocop.yml +154 -0
- data/.ruby-version +1 -0
- data/.yardopts +1 -0
- data/COPYING.txt +165 -0
- data/ChangeLog.md +38 -0
- data/Gemfile +35 -0
- data/README.md +177 -0
- data/Rakefile +34 -0
- data/gemspec.yml +31 -0
- data/lib/ronin/web/server/app.rb +33 -0
- data/lib/ronin/web/server/base.rb +214 -0
- data/lib/ronin/web/server/conditions.rb +443 -0
- data/lib/ronin/web/server/helpers.rb +67 -0
- data/lib/ronin/web/server/request.rb +78 -0
- data/lib/ronin/web/server/response.rb +36 -0
- data/lib/ronin/web/server/reverse_proxy/request.rb +230 -0
- data/lib/ronin/web/server/reverse_proxy/response.rb +35 -0
- data/lib/ronin/web/server/reverse_proxy.rb +265 -0
- data/lib/ronin/web/server/routing.rb +261 -0
- data/lib/ronin/web/server/version.rb +28 -0
- data/lib/ronin/web/server.rb +62 -0
- data/ronin-web-server.gemspec +59 -0
- data/spec/base_spec.rb +73 -0
- data/spec/classes/public1/static1.txt +1 -0
- data/spec/classes/public2/static2.txt +1 -0
- data/spec/classes/sub_app.rb +13 -0
- data/spec/classes/test_app.rb +20 -0
- data/spec/helpers/rack_app.rb +24 -0
- data/spec/request_spec.rb +58 -0
- data/spec/response_spec.rb +8 -0
- data/spec/reverse_proxy/request_spec.rb +200 -0
- data/spec/reverse_proxy/response_spec.rb +8 -0
- data/spec/reverse_proxy_spec.rb +223 -0
- data/spec/spec_helper.rb +9 -0
- metadata +180 -0
@@ -0,0 +1,443 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-web-server - A custom Ruby web server based on Sinatra.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-web-server is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-web-server is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-web-server. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'ronin/support/network/asn'
|
22
|
+
|
23
|
+
require 'ipaddr'
|
24
|
+
|
25
|
+
module Ronin
|
26
|
+
module Web
|
27
|
+
module Server
|
28
|
+
#
|
29
|
+
# Defines Sinatra routing conditions.
|
30
|
+
#
|
31
|
+
# @api semipublic
|
32
|
+
#
|
33
|
+
module Conditions
|
34
|
+
#
|
35
|
+
# Adds {ClassMethods} to the class.
|
36
|
+
#
|
37
|
+
# @param [Class] base
|
38
|
+
# The application base class that is including {Conditions}.
|
39
|
+
#
|
40
|
+
# @api private
|
41
|
+
#
|
42
|
+
def self.included(base)
|
43
|
+
base.extend ClassMethods
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Class methods to be added to the application base class.
|
48
|
+
#
|
49
|
+
module ClassMethods
|
50
|
+
protected
|
51
|
+
|
52
|
+
#
|
53
|
+
# Condition to match the client IP Address that sent the request.
|
54
|
+
#
|
55
|
+
# @param [IPAddr, String, Proc, #===] matcher
|
56
|
+
# The IP address or range of addresses to match against.
|
57
|
+
#
|
58
|
+
# @example Only allow the exact IP:
|
59
|
+
# get '/path', client_ip: '10.1.1.1' do
|
60
|
+
# # ...
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# @example Allow all IPs from the IP range:
|
64
|
+
# get '/path', client_ip: IPAddr.new('10.1.1.1/24') do
|
65
|
+
# # ...
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
def client_ip(matcher)
|
69
|
+
condition { matcher === request.ip }
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Condition to match the AS number of the client's IP address.
|
74
|
+
#
|
75
|
+
# @param [Integer] number
|
76
|
+
# The AS number to match.
|
77
|
+
#
|
78
|
+
# @example
|
79
|
+
# get '/path', asn: 13335 do
|
80
|
+
# # ...
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
def asn(number)
|
84
|
+
condition do
|
85
|
+
if (record = Support::Network::ASN.query(request.ip))
|
86
|
+
record.number == number
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# Condition to match the country code of the ASN information for the
|
93
|
+
# client's IP address.
|
94
|
+
#
|
95
|
+
# @param [String] code
|
96
|
+
# The two letter country code to match for.
|
97
|
+
#
|
98
|
+
# @example
|
99
|
+
# get '/path', country_code: 'US' do
|
100
|
+
# # ...
|
101
|
+
# end
|
102
|
+
#
|
103
|
+
def country_code(code)
|
104
|
+
condition do
|
105
|
+
if (record = Support::Network::ASN.query(request.ip))
|
106
|
+
record.country_code == country_code
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Condition to match the company/ISP name of the ASN information for
|
113
|
+
# the client's IP address.
|
114
|
+
#
|
115
|
+
# @param [String] name
|
116
|
+
# The name of the company/ISP that the ASN is assigned to.
|
117
|
+
#
|
118
|
+
# @example
|
119
|
+
# get '/path', asn_name: 'CLOUDFLARENET' do
|
120
|
+
# # ...
|
121
|
+
# end
|
122
|
+
#
|
123
|
+
def asn_name(name)
|
124
|
+
condition do
|
125
|
+
if (record = Support::Network::ASN.query(request.ip))
|
126
|
+
record.name == name
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
#
|
132
|
+
# Condition for matching the `Host` header.
|
133
|
+
#
|
134
|
+
# @param [Regexp, String, Proc, #===] matcher
|
135
|
+
# The host to match against.
|
136
|
+
#
|
137
|
+
# @example Match the exact `Host` header:
|
138
|
+
# get '/path', host: 'example.com' do
|
139
|
+
# # ...
|
140
|
+
# end
|
141
|
+
#
|
142
|
+
# @example Match any `Host` header ending in `.example.com`:
|
143
|
+
# get '/path', host: /\.example\.com$/ do
|
144
|
+
# # ...
|
145
|
+
# end
|
146
|
+
#
|
147
|
+
def host(matcher)
|
148
|
+
condition { matcher === request.host }
|
149
|
+
end
|
150
|
+
|
151
|
+
#
|
152
|
+
# Condition to match the `Referer` header of the request.
|
153
|
+
#
|
154
|
+
# @param [Regexp, String, Proc, #===] matcher
|
155
|
+
# Regular expression or exact `Referer` header to match against.
|
156
|
+
#
|
157
|
+
# @example Match the exact `Referer` URI:
|
158
|
+
# get '/path', referer: 'https://example.com/signin' do
|
159
|
+
# # ...
|
160
|
+
# end
|
161
|
+
#
|
162
|
+
# @example Match any `Referer` URI matching the Regexp:
|
163
|
+
# get '/path', referer: /^http:\/\// do
|
164
|
+
# # ...
|
165
|
+
# end
|
166
|
+
#
|
167
|
+
def referer(matcher)
|
168
|
+
condition do
|
169
|
+
if (referer = request.referer)
|
170
|
+
matcher === referer
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
alias referrer referer
|
176
|
+
|
177
|
+
#
|
178
|
+
# Condition to match the `User-Agent` header of the request.
|
179
|
+
#
|
180
|
+
# @param [Regexp, String, Proc, #===] matcher
|
181
|
+
# Regular expression, exact String, Proc, or any other object which
|
182
|
+
# defines an `#===` method.
|
183
|
+
#
|
184
|
+
# @example Match any `User-Agent` with `Intel Mac OSX` in it:
|
185
|
+
# get '/path', user_agent: /Intel Mac OSX/ do
|
186
|
+
# # ...
|
187
|
+
# end
|
188
|
+
#
|
189
|
+
def user_agent(matcher)
|
190
|
+
condition do
|
191
|
+
if (user_agent = request.user_agent)
|
192
|
+
matcher === user_agent
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
#
|
198
|
+
# Condition to match the browser name from the `User-Agent` header of
|
199
|
+
# the request.
|
200
|
+
#
|
201
|
+
# @param [:chrome, :firefox, Regexp, String, Proc, #===] matcher
|
202
|
+
# Regular expression, exact String, Proc, or any other object which
|
203
|
+
# defines an `#===` method.
|
204
|
+
#
|
205
|
+
# @example Match the exact browser name:
|
206
|
+
# get '/path', browser: "Foo" do
|
207
|
+
# # ...
|
208
|
+
# end
|
209
|
+
#
|
210
|
+
# @example Match any browser name matching the Regexp:
|
211
|
+
# get '/path', browser: /googlebot/i do
|
212
|
+
# # ...
|
213
|
+
# end
|
214
|
+
#
|
215
|
+
# @example Match all Chrome browsers:
|
216
|
+
# get '/path', browser: :chrome do
|
217
|
+
# # ...
|
218
|
+
# end
|
219
|
+
#
|
220
|
+
# @example Match all Firefox browsers:
|
221
|
+
# get '/path', browser: :firefox do
|
222
|
+
# # ...
|
223
|
+
# end
|
224
|
+
#
|
225
|
+
def browser(matcher)
|
226
|
+
case matcher
|
227
|
+
when :chrome
|
228
|
+
condition { request.browser == 'Chrome' }
|
229
|
+
when :firefox
|
230
|
+
condition { request.browser == 'Firefox' }
|
231
|
+
else
|
232
|
+
condition do
|
233
|
+
if (browser = request.browser)
|
234
|
+
matcher === browser
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
#
|
241
|
+
# Condition to match the browser vendor from the `User-Agent` header
|
242
|
+
# of the request.
|
243
|
+
#
|
244
|
+
# @param [Regexp, String, Proc, #===] matcher
|
245
|
+
# Regular expression, exact String, Proc, or any other object which
|
246
|
+
# defines an `#===` method.
|
247
|
+
#
|
248
|
+
# @example Match the browser vendor:
|
249
|
+
# get '/path', browser_vendor: 'Google' do
|
250
|
+
# # ...
|
251
|
+
# end
|
252
|
+
#
|
253
|
+
def browser_vendor(matcher)
|
254
|
+
condition do
|
255
|
+
if (browser_vendor = request.browser_vendor)
|
256
|
+
matcher === browser_vendor
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
#
|
262
|
+
# Condition to match the browser version from the `User-Agent` header
|
263
|
+
# of the request.
|
264
|
+
#
|
265
|
+
# @param [Array<String>, Set<String>,
|
266
|
+
# Regexp, String, Proc, #===] matcher
|
267
|
+
# Regular expression, exact String, Proc, or any other object which
|
268
|
+
# defines an `#===` method.
|
269
|
+
#
|
270
|
+
# @example Match an exact version of Chrome:
|
271
|
+
# get '/path', browser: :chrome, browser_version: '99.100.4844.27' do
|
272
|
+
# # ...
|
273
|
+
# end
|
274
|
+
#
|
275
|
+
# @example Match all Chrome versions in the 99.x version family:
|
276
|
+
# get '/path', browser: :chrome, browser_version: /^99\./ do
|
277
|
+
# # ...
|
278
|
+
# end
|
279
|
+
#
|
280
|
+
# @example Match versions of Chrome with known vulnerabilities:
|
281
|
+
# vuln_versions = File.readlines('chrome_versions.txt', chomp: true)
|
282
|
+
#
|
283
|
+
# get '/path', browser: :chrome, browser_version: vuln_versions do
|
284
|
+
# # ...
|
285
|
+
# end
|
286
|
+
#
|
287
|
+
def browser_version(matcher)
|
288
|
+
case matcher
|
289
|
+
when Array, Set
|
290
|
+
condition do
|
291
|
+
if (browser_version = request.browser_version)
|
292
|
+
matcher.include?(browser_version)
|
293
|
+
end
|
294
|
+
end
|
295
|
+
else
|
296
|
+
condition do
|
297
|
+
if (browser_version = request.browser_version)
|
298
|
+
matcher === browser_version
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
#
|
305
|
+
# Condition to match the device type of the `User-Agent` header of
|
306
|
+
# the request.
|
307
|
+
#
|
308
|
+
# @param [Array<:pc, :smartphone, :mobilephone, :appliance, :crawler>,
|
309
|
+
# :pc, :smartphone, :mobilephone, :appliance, :crawler,
|
310
|
+
# Proc, #===] matcher
|
311
|
+
# Array of device type Symbols, the exact devicde type Symbol,
|
312
|
+
# Proc, or any other object which defines an `#===` method.
|
313
|
+
#
|
314
|
+
# @example Match a specific device type:
|
315
|
+
# get '/path', device_type: :crawler do
|
316
|
+
# halt 404
|
317
|
+
# end
|
318
|
+
#
|
319
|
+
# @example Match multiple device types:
|
320
|
+
# get '/path', device_type: [:smartphone, :appliance] do
|
321
|
+
# # ...
|
322
|
+
# end
|
323
|
+
#
|
324
|
+
def device_type(matcher)
|
325
|
+
condition do
|
326
|
+
if (device_type = request.device_type)
|
327
|
+
case matcher
|
328
|
+
when Array then matcher.include?(device_type)
|
329
|
+
else matcher === device_type
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
#
|
336
|
+
# Condition to match the OS from the `User-Agent` header of the
|
337
|
+
# request.
|
338
|
+
#
|
339
|
+
# @param [:android, :ios, :linux, :windows,
|
340
|
+
# Regexp, String, Proc, #===] matcher
|
341
|
+
# Regular expression, exact String, Proc, or any other object which
|
342
|
+
# defines an `#===` method.
|
343
|
+
#
|
344
|
+
# @example Match all Android devices:
|
345
|
+
# get '/path', os: :android do
|
346
|
+
# # ...
|
347
|
+
# end
|
348
|
+
#
|
349
|
+
# @example Match all iOS devices:
|
350
|
+
# get '/path', os: :ios do
|
351
|
+
# # ...
|
352
|
+
# end
|
353
|
+
#
|
354
|
+
# @example Match all Linux systems:
|
355
|
+
# get '/path', os: :linux do
|
356
|
+
# # ...
|
357
|
+
# end
|
358
|
+
#
|
359
|
+
# @example Match all Windows systems:
|
360
|
+
# get '/path', os: :windows do
|
361
|
+
# # ...
|
362
|
+
# end
|
363
|
+
#
|
364
|
+
# @example Match a specific OS:
|
365
|
+
# get '/path', os: 'Windows 10' do
|
366
|
+
# # ...
|
367
|
+
# end
|
368
|
+
#
|
369
|
+
# @example Match any OS that matches the Regexp:
|
370
|
+
# get '/path', os: /^Windows (?:7|8|10)/ do
|
371
|
+
# # ...
|
372
|
+
# end
|
373
|
+
#
|
374
|
+
def os(matcher)
|
375
|
+
case matcher
|
376
|
+
when :android
|
377
|
+
condition { request.from_android_os? }
|
378
|
+
when :ios
|
379
|
+
condition { request.from_ios? }
|
380
|
+
when :linux
|
381
|
+
condition { request.os == 'Linux' }
|
382
|
+
when :windows
|
383
|
+
condition do
|
384
|
+
if (os = request.os)
|
385
|
+
os.start_with?('Windows')
|
386
|
+
end
|
387
|
+
end
|
388
|
+
else
|
389
|
+
condition do
|
390
|
+
if (os = request.os)
|
391
|
+
matcher === os
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
#
|
398
|
+
# Condition to match the OS version from the `User-Agent` header of
|
399
|
+
# the request.
|
400
|
+
#
|
401
|
+
# @param [Array<String>, Set<String>,
|
402
|
+
# Regexp, String, Proc, #===] matcher
|
403
|
+
# Regular expression, exact String, Proc, or any other object which
|
404
|
+
# defines an `#===` method.
|
405
|
+
#
|
406
|
+
# @example Match a specific Android OS version:
|
407
|
+
# get '/path', os: :android, os_version: '8.1.0' do
|
408
|
+
# # ...
|
409
|
+
# end
|
410
|
+
#
|
411
|
+
# @example Match all Android OS versions that match a Regexp:
|
412
|
+
# get '/path', os: :android, os_version: /^8\.1\./ do
|
413
|
+
# # ...
|
414
|
+
# end
|
415
|
+
#
|
416
|
+
# @example Match versions of Android with known vulnerabilities:
|
417
|
+
# vuln_versions = File.readlines('android_versions.txt', chomp: true)
|
418
|
+
#
|
419
|
+
# get '/path', os: :android, os_version: vuln_versions do
|
420
|
+
# # ...
|
421
|
+
# end
|
422
|
+
#
|
423
|
+
def os_version(matcher)
|
424
|
+
case matcher
|
425
|
+
when Array, Set
|
426
|
+
condition do
|
427
|
+
if (os_version = request.os_version)
|
428
|
+
matcher.include?(os_version)
|
429
|
+
end
|
430
|
+
end
|
431
|
+
else
|
432
|
+
condition do
|
433
|
+
if (os_version = request.os_version)
|
434
|
+
matcher === os_version
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-web-server - A custom Ruby web server based on Sinatra.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-web-server is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-web-server is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-web-server. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'sinatra/base'
|
22
|
+
require 'rack/utils'
|
23
|
+
|
24
|
+
module Ronin
|
25
|
+
module Web
|
26
|
+
module Server
|
27
|
+
#
|
28
|
+
# Provides Sinatra routing and helper methods.
|
29
|
+
#
|
30
|
+
module Helpers
|
31
|
+
|
32
|
+
include Rack::Utils
|
33
|
+
include Sinatra::Helpers
|
34
|
+
|
35
|
+
alias h escape_html
|
36
|
+
alias file send_file
|
37
|
+
|
38
|
+
#
|
39
|
+
# Returns the MIME type for a path.
|
40
|
+
#
|
41
|
+
# @param [String] path
|
42
|
+
# The path to determine the MIME type for.
|
43
|
+
#
|
44
|
+
# @return [String]
|
45
|
+
# The MIME type for the path.
|
46
|
+
#
|
47
|
+
# @api public
|
48
|
+
#
|
49
|
+
def mime_type_for(path)
|
50
|
+
mime_type(File.extname(path))
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# Sets the `Content-Type` for the file.
|
55
|
+
#
|
56
|
+
# @param [String] path
|
57
|
+
# The path to determine the `Content-Type` for.
|
58
|
+
#
|
59
|
+
# @api public
|
60
|
+
#
|
61
|
+
def content_type_for(path)
|
62
|
+
content_type mime_type_for(path)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-web-server - A custom Ruby web server based on Sinatra.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-web-server is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-web-server is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-web-server. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'sinatra/base'
|
22
|
+
|
23
|
+
module Ronin
|
24
|
+
module Web
|
25
|
+
module Server
|
26
|
+
#
|
27
|
+
# Convenience class that represents requests.
|
28
|
+
#
|
29
|
+
# @see http://rubydoc.info/gems/rack/Rack/Request
|
30
|
+
#
|
31
|
+
class Request < Sinatra::Request
|
32
|
+
|
33
|
+
alias client_ip ip
|
34
|
+
|
35
|
+
#
|
36
|
+
# Returns the remote IP address and port for the request.
|
37
|
+
#
|
38
|
+
# @return [String]
|
39
|
+
# The IP address and port number.
|
40
|
+
#
|
41
|
+
# @api semipublic
|
42
|
+
#
|
43
|
+
def ip_with_port
|
44
|
+
if env.has_key?('REMOTE_PORT')
|
45
|
+
"#{ip}:#{env['REMOTE_PORT']}"
|
46
|
+
else
|
47
|
+
ip
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# The HTTP Headers for the request.
|
53
|
+
#
|
54
|
+
# @return [Hash{String => String}]
|
55
|
+
# The HTTP Headers of the request.
|
56
|
+
#
|
57
|
+
# @api public
|
58
|
+
#
|
59
|
+
def headers
|
60
|
+
headers = {}
|
61
|
+
|
62
|
+
env.each do |name,value|
|
63
|
+
if name =~ /^HTTP_/
|
64
|
+
header_words = name[5..].split('_')
|
65
|
+
header_words.each(&:capitalize!)
|
66
|
+
header_name = header_words.join('-')
|
67
|
+
|
68
|
+
headers[header_name] = value
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
return headers
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# ronin-web-server - A custom Ruby web server based on Sinatra.
|
4
|
+
#
|
5
|
+
# Copyright (c) 2006-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
|
6
|
+
#
|
7
|
+
# ronin-web-server is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Lesser General Public License as published
|
9
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# ronin-web-server is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Lesser General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Lesser General Public License
|
18
|
+
# along with ronin-web-server. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
#
|
20
|
+
|
21
|
+
require 'sinatra/base'
|
22
|
+
|
23
|
+
module Ronin
|
24
|
+
module Web
|
25
|
+
module Server
|
26
|
+
#
|
27
|
+
# Convenience class that represents responses.
|
28
|
+
#
|
29
|
+
# @see http://rubydoc.info/gems/rack/Rack/Response
|
30
|
+
#
|
31
|
+
class Response < Sinatra::Response
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|