adelnor 0.0.4

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8fd3bdc715084ebccf29d504de4cbba7346dbc8c985f5434c70d8fa4547c3d76
4
+ data.tar.gz: 41b0ba8c691e39cc7e2e77f508d450b7f74ec52c2cd75defaa8497982d0a2338
5
+ SHA512:
6
+ metadata.gz: 9756b4e0d68b17cb1dacc39e6eebd4b549b1dd5fe8b820174e865bceaf04a1cee252868bac89e4c8b7f4bfebea7d0421e29cf5e5972eb02dcba0efa32866dce5
7
+ data.tar.gz: a8f6604f3167d7dccbb7c4a0853714f2fe1edcd2b35d0c3e9e40b9699bd9f92020a333c0ab55451b891be04f090bf5a5a48676deee6f330494b5113f260707a5
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rack'
data/Gemfile.lock ADDED
@@ -0,0 +1,13 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ rack (2.2.3)
5
+
6
+ PLATFORMS
7
+ aarch64-linux
8
+
9
+ DEPENDENCIES
10
+ rack
11
+
12
+ BUNDLED WITH
13
+ 2.3.3
data/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # Adelnor
2
+
3
+ A dead simple, yet Rack-compatible, HTTP server written in Ruby
4
+
5
+ ## Running a sample server in development
6
+
7
+ ```bash
8
+ make bundle.install
9
+ make sample.server
10
+ ```
11
+
12
+ Open `http://localhost:3000`
13
+
14
+ ## Publishing the gem
15
+
16
+ ```bash
17
+ make gem.build
18
+ make gem.install # locally
19
+ make gem.signin # sign in to rubygems.org using owner credentials
20
+ make gem.push # push gem to rubygems.org
21
+ ```
data/adelnor.gemspec ADDED
@@ -0,0 +1,11 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = 'adelnor'
3
+ spec.version = '0.0.4'
4
+ spec.summary = 'Adelnor HTTP server'
5
+ spec.description = 'A dead simple, yet Rack-compatible, HTTP server written in Ruby'
6
+ spec.authors = ['Leandro Proença']
7
+ spec.email = 'leandronsp@gmail.com'
8
+ spec.files = Dir['lib/**/*'] + %w(Gemfile Gemfile.lock README.md adelnor.gemspec)
9
+ spec.homepage = 'https://github.com/leandronsp/adelnor'
10
+ spec.license = 'MIT'
11
+ end
@@ -0,0 +1,53 @@
1
+ module Adelnor
2
+ class Request
3
+ attr_reader :request_method, :request_path, :headers, :body,
4
+ :content_length, :path_info, :query_string
5
+
6
+ def initialize(message)
7
+ @message = message
8
+ @request_method = @request_path = nil
9
+
10
+ @headers = {}
11
+ @body = ''
12
+ end
13
+
14
+ def self.build(*args)
15
+ new(*args).build
16
+ end
17
+
18
+ def build
19
+ lines = @message.split(/\r\n/)
20
+ headline = lines.shift
21
+
22
+ parse_headline!(headline)
23
+ parse_headers!(lines)
24
+
25
+ self
26
+ end
27
+
28
+ def parse_body!(client)
29
+ @content_length = @headers['Content-Length']
30
+ return unless @content_length
31
+
32
+ @body = client.read(@content_length.to_i)
33
+ end
34
+
35
+ private
36
+
37
+ def parse_headline!(line)
38
+ return unless line.match(/HTTP\/.*?/)
39
+
40
+ @request_method, @request_path, _ = line.split
41
+ @path_info, @query_string = @request_path.split('?')
42
+ end
43
+
44
+ def parse_headers!(lines)
45
+ lines.each(&method(:parse_header!))
46
+ end
47
+
48
+ def parse_header!(line)
49
+ header_key, header_value = line.split(': ')
50
+ @headers[header_key] = header_value
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,30 @@
1
+ module Adelnor
2
+ class Response
3
+ def initialize(status, headers, body)
4
+ @status = status
5
+ @headers = headers
6
+ @body = body
7
+ end
8
+
9
+ def self.build(*args)
10
+ new(*args).build
11
+ end
12
+
13
+ def build
14
+ "HTTP/2.0 #{@status}\r\n#{headers_as_string}\r\n#{body_as_string}"
15
+ end
16
+
17
+ private
18
+
19
+ def body_as_string = @body.respond_to?(:first) ? @body.first : @body
20
+
21
+ def headers_as_string
22
+ @headers.reduce('') do |acc, (key, value)|
23
+ acc += header_as_string(key, value)
24
+ acc
25
+ end
26
+ end
27
+
28
+ def header_as_string(key, value) = "#{key}: #{value}\r\n"
29
+ end
30
+ end
@@ -0,0 +1,86 @@
1
+ require 'socket'
2
+ require 'rack'
3
+ require 'stringio'
4
+
5
+ require_relative './request'
6
+ require_relative './response'
7
+
8
+ module Adelnor
9
+ class Server
10
+ def initialize(rack_app, port)
11
+ @rack_app = rack_app
12
+ @port = port
13
+ @socket = Socket.new(:INET, :STREAM)
14
+ addr = Socket.sockaddr_in(@port, '0.0.0.0')
15
+
16
+ @socket.bind(addr)
17
+ @socket.listen(2)
18
+
19
+ puts welcome_message
20
+ end
21
+
22
+ def self.run(*args)
23
+ new(*args).run
24
+ end
25
+
26
+ def rack_data(request)
27
+ {
28
+ 'REQUEST_METHOD' => request.request_method,
29
+ 'PATH_INFO' => request.path_info,
30
+ 'QUERY_STRING' => request.query_string,
31
+ 'SERVER_PORT' => @port,
32
+ 'SERVER_NAME' => request.headers['Host'],
33
+ 'CONTENT_LENGTH' => request.content_length,
34
+ 'HTTP_COOKIE' => request.headers['Cookie'],
35
+ 'rack.input' => StringIO.new(request.body)
36
+ }.merge(request.headers)
37
+ end
38
+
39
+ def run
40
+ loop do
41
+ client, _ = @socket.accept
42
+
43
+ read_request_message(client)
44
+ .then { |message| Request.build(message) }
45
+ .tap { |request| request.parse_body!(client) }
46
+ .then { |request| rack_data(request) }
47
+ .then { |data| @rack_app.call(data) }
48
+ .then { |result| Response.build(*result) }
49
+ .then { |response| client.puts(response) }
50
+
51
+ client.close
52
+ end
53
+ end
54
+
55
+ def read_request_message(client)
56
+ message = ''
57
+
58
+ message += client.gets
59
+ puts
60
+ puts "[#{Time.now}] #{message}"
61
+
62
+ while line = client.gets
63
+ break if line == "\r\n"
64
+
65
+ message += line
66
+ end
67
+
68
+ message
69
+ end
70
+
71
+ def welcome_message
72
+ <<-WELCOME
73
+ |\---/|
74
+ | o_o |
75
+ \_^_/
76
+
77
+ adelnor HTTP server
78
+
79
+ ------------------------------------------------
80
+
81
+ Adelnor is running at http://0.0.0.0:#{@port}
82
+ Listening to HTTP connections
83
+ WELCOME
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,3 @@
1
+ module Adelnor
2
+ VERSION = "0.0.4"
3
+ end
data/lib/adelnor.rb ADDED
@@ -0,0 +1,6 @@
1
+ require_relative './adelnor/server'
2
+ require_relative './adelnor/request'
3
+ require_relative './adelnor/response'
4
+
5
+ module Adelnor
6
+ end
metadata ADDED
@@ -0,0 +1,51 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: adelnor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Leandro Proença
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-05-20 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A dead simple, yet Rack-compatible, HTTP server written in Ruby
14
+ email: leandronsp@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - Gemfile
20
+ - Gemfile.lock
21
+ - README.md
22
+ - adelnor.gemspec
23
+ - lib/adelnor.rb
24
+ - lib/adelnor/request.rb
25
+ - lib/adelnor/response.rb
26
+ - lib/adelnor/server.rb
27
+ - lib/adelnor/version.rb
28
+ homepage: https://github.com/leandronsp/adelnor
29
+ licenses:
30
+ - MIT
31
+ metadata: {}
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ requirements: []
47
+ rubygems_version: 3.3.3
48
+ signing_key:
49
+ specification_version: 4
50
+ summary: Adelnor HTTP server
51
+ test_files: []