Simple_Server_Example 0.0.1
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/.gitignore +1 -0
- data/README.md +17 -0
- data/Rakefile +8 -0
- data/bin/server +4 -0
- data/bin/test +10 -0
- data/lib/request.rb +15 -0
- data/lib/response.rb +2 -0
- data/lib/simple_server.rb +81 -0
- data/public/404.html +10 -0
- data/public/index.html +9 -0
- data/public/test.png +0 -0
- data/simple_server.gemspec +19 -0
- data/test/test_request.rb +18 -0
- data/test/test_response.rb +1 -0
- data/test/test_server.rb +37 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: afb5f851b068675773a3e7fc0d52178d9732ee3c
|
4
|
+
data.tar.gz: 35de123dfb24039b4869a632c1110110680290f8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 886a4866d3c6cb651847b1785293a6b3cd89ad9d3c938fdb2744121035fc4ca36d702a830db77b5c1a81d87f8ef973540158f2d1a4325ea491b0fa8e776134ec
|
7
|
+
data.tar.gz: 8a97d67c2bca9f5e0157d5e120d84425a3f168d0801b9edf36748a0ee19f7d3e2e5ef2f917f2d7ee0709426d43dc2de981a6f25a6b72bd2b59f8acfb6c888149
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
.DS_Store
|
data/README.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Super Awesome Server
|
2
|
+
=====================================
|
3
|
+
|
4
|
+
1. Download this git repo
|
5
|
+
|
6
|
+
2. Inside the root of the repo, build the gem by typing:
|
7
|
+
``` gem build server.gemspec ```
|
8
|
+
|
9
|
+
3. Install the gem by typing:
|
10
|
+
``` gem install server-0.0.1.gem ```
|
11
|
+
|
12
|
+
4. Open a new terminal/commandline and run the server:
|
13
|
+
``` server ```
|
14
|
+
|
15
|
+
5. Open a broswer and point it to localhost:2345
|
16
|
+
|
17
|
+
6. Party on
|
data/Rakefile
ADDED
data/bin/server
ADDED
data/bin/test
ADDED
data/lib/request.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
class Request
|
2
|
+
attr_reader :method, :resource, :version
|
3
|
+
|
4
|
+
def initialize(method, resource, version)
|
5
|
+
@method = method
|
6
|
+
@resource = resource
|
7
|
+
@version = version
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.parse(string)
|
11
|
+
pattern = /\A(?<method>\w+)\s+(?<resource>\S+)\s+(?<version>\S+)/
|
12
|
+
match = pattern.match(string)
|
13
|
+
Request.new(match["method"], match["resource"], match["version"])
|
14
|
+
end
|
15
|
+
end
|
data/lib/response.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require_relative 'request'
|
3
|
+
|
4
|
+
class SimpleServer
|
5
|
+
attr_reader :server
|
6
|
+
|
7
|
+
WEB_ROOT = './public'
|
8
|
+
|
9
|
+
CONTENT_TYPE_MAPPING = {
|
10
|
+
'html' => 'text/html',
|
11
|
+
'txt' => 'text/plain',
|
12
|
+
'png' => 'image/png',
|
13
|
+
'jpg' => 'image/jpg'
|
14
|
+
}
|
15
|
+
|
16
|
+
DEFAULT_CONTENT_TYPE = 'application/octet-stream'
|
17
|
+
|
18
|
+
def initialize(host='localhost', port=2345)
|
19
|
+
@server = TCPServer.new(host, port)
|
20
|
+
end
|
21
|
+
|
22
|
+
def content_type(path)
|
23
|
+
ext = File.extname(path).split('.').last
|
24
|
+
CONTENT_TYPE_MAPPING.fetch(ext, DEFAULT_CONTENT_TYPE)
|
25
|
+
end
|
26
|
+
|
27
|
+
def clean_path(path)
|
28
|
+
clean = []
|
29
|
+
|
30
|
+
parts = path.split("/")
|
31
|
+
parts.each do |part|
|
32
|
+
next if part.empty? || part == '.'
|
33
|
+
part == '..' ? clean.pop : clean << part
|
34
|
+
end
|
35
|
+
File.join(WEB_ROOT, *clean)
|
36
|
+
end
|
37
|
+
|
38
|
+
def request(path, socket)
|
39
|
+
if File.exist?(path) && !File.directory?(path)
|
40
|
+
File.open(path, "rb") do |file|
|
41
|
+
socket.print "HTTP/1.1 200 OK\r\n" +
|
42
|
+
"Content-Type: #{content_type(file)}\r\n" +
|
43
|
+
"Content-Length: #{file.size}\r\n" +
|
44
|
+
"Connection: close\r\n"
|
45
|
+
|
46
|
+
socket.print "\r\n"
|
47
|
+
|
48
|
+
IO.copy_stream(file, socket)
|
49
|
+
end
|
50
|
+
else
|
51
|
+
File.open('./public/404.html', "rb") do |file|
|
52
|
+
|
53
|
+
socket.print "HTTP/1.1 404 Not Found\r\n" +
|
54
|
+
"Content-Type: #{content_type(file)}\r\n" +
|
55
|
+
"Content-Length #{file.size}\r\n" +
|
56
|
+
"Connection: close\r\n"
|
57
|
+
|
58
|
+
socket.print "\r\n"
|
59
|
+
|
60
|
+
IO.copy_stream(file, socket)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def run
|
66
|
+
begin
|
67
|
+
loop do
|
68
|
+
Thread.start(server.accept) do |socket|
|
69
|
+
request = Request.parse(socket.gets)
|
70
|
+
STDERR.puts request
|
71
|
+
path = clean_path(request.resource)
|
72
|
+
path = File.join(path, 'index.html') if File.directory?(path)
|
73
|
+
request(path, socket)
|
74
|
+
socket.close
|
75
|
+
end
|
76
|
+
end
|
77
|
+
rescue Interrupt
|
78
|
+
puts "\nExiting...Thank you for using this super awesome server."
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/public/404.html
ADDED
data/public/index.html
ADDED
data/public/test.png
ADDED
Binary file
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'Simple_Server_Example'
|
7
|
+
s.version = "0.0.1"
|
8
|
+
s.files = `git ls-files`.split($/)
|
9
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
10
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
11
|
+
s.require_paths = ["lib"]
|
12
|
+
s.date = '2014-10-15'
|
13
|
+
s.summary = "Simple Server Example"
|
14
|
+
s.description = "A simple web server by me"
|
15
|
+
s.authors = ["Neil Northrop"]
|
16
|
+
s.email = 'nnorthrop@gmail.com'
|
17
|
+
s.homepage = 'http://www.example.com'
|
18
|
+
s.license = 'MIT'
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require './lib/request'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
|
4
|
+
class TestRequest < MiniTest::Test
|
5
|
+
def test_that_request_parser_returns_method
|
6
|
+
match = Request.parse('GET /index.html HTTP/1.1')
|
7
|
+
assert_equal match.method, 'GET'
|
8
|
+
assert_equal match.resource, '/index.html'
|
9
|
+
assert_equal match.version, 'HTTP/1.1'
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_that_request_parser_ignores_body
|
13
|
+
match = Request.parse("GET /index.html HTTP/1.1\n Accept: This and that\n Body: GET /index2.html HTTP/1.90")
|
14
|
+
assert_equal match.method, 'GET'
|
15
|
+
assert_equal match.resource, '/index.html'
|
16
|
+
assert_equal match.version, 'HTTP/1.1'
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'minitest/autorun'
|
data/test/test_server.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require './lib/simple_server'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
|
5
|
+
class TestSimpleServer < MiniTest::Test
|
6
|
+
def server
|
7
|
+
SimpleServer.new('localhost', 2346)
|
8
|
+
end
|
9
|
+
|
10
|
+
def request(path)
|
11
|
+
Net::HTTP.get_response(URI(path))
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_hello_world_from_server
|
15
|
+
assert_equal request('http://localhost:2345').code, "200"
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_content_type_mapping_html
|
19
|
+
assert_equal request('http://localhost:2345').response.content_type, 'text/html'
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_content_type_mapping_for_png
|
23
|
+
assert_equal request('http://localhost:2345/test.png').response.content_type, 'image/png'
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_requested_file_joins_a_resource
|
27
|
+
assert_equal server.clean_path('/index.html'), './public/index.html'
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_requested_file_removes_double_periods_from_resource_but_keeps_directories
|
31
|
+
assert_equal server.clean_path('/../../../hello/index.html'), './public/hello/index.html'
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_requested_file_removes_double_periods_from_resource
|
35
|
+
assert_equal server.clean_path('/../../hello/../index.html'), './public/index.html'
|
36
|
+
end
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: Simple_Server_Example
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Neil Northrop
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-15 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A simple web server by me
|
14
|
+
email: nnorthrop@gmail.com
|
15
|
+
executables:
|
16
|
+
- server
|
17
|
+
- test
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- ".gitignore"
|
22
|
+
- README.md
|
23
|
+
- Rakefile
|
24
|
+
- bin/server
|
25
|
+
- bin/test
|
26
|
+
- lib/request.rb
|
27
|
+
- lib/response.rb
|
28
|
+
- lib/simple_server.rb
|
29
|
+
- public/404.html
|
30
|
+
- public/index.html
|
31
|
+
- public/test.png
|
32
|
+
- simple_server.gemspec
|
33
|
+
- test/test_request.rb
|
34
|
+
- test/test_response.rb
|
35
|
+
- test/test_server.rb
|
36
|
+
homepage: http://www.example.com
|
37
|
+
licenses:
|
38
|
+
- MIT
|
39
|
+
metadata: {}
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
requirements: []
|
55
|
+
rubyforge_project:
|
56
|
+
rubygems_version: 2.3.0
|
57
|
+
signing_key:
|
58
|
+
specification_version: 4
|
59
|
+
summary: Simple Server Example
|
60
|
+
test_files:
|
61
|
+
- test/test_request.rb
|
62
|
+
- test/test_response.rb
|
63
|
+
- test/test_server.rb
|