adelnor 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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: []