Class: SmallVictories::Server
- Inherits:
-
Object
- Object
- SmallVictories::Server
- Defined in:
- lib/smallvictories/server.rb
Constant Summary collapse
- WEB_ROOT =
Files will be served from this directory
'./'- TEMP_FILE =
'./.sv_temp'- DEFAULT_CONTENT_TYPE =
Treat as binary data if content type cannot be found
'application/octet-stream'
Instance Attribute Summary collapse
-
#config ⇒ Object
Returns the value of attribute config.
-
#server ⇒ Object
Returns the value of attribute server.
-
#socket ⇒ Object
Returns the value of attribute socket.
Instance Method Summary collapse
- #content_type(path) ⇒ Object
-
#initialize(attributes = {}) ⇒ Server
constructor
This helper function parses the extension of the requested file and then looks up its content type.
-
#render_file(file, content_type = nil) ⇒ Object
This helper function saves the string to a temp file and streams it.
- #render_string(string, content_type = nil) ⇒ Object
- #render_stylesheet ⇒ Object
-
#requested_file(request_line) ⇒ Object
This helper function parses the Request-Line and generates a path to a file on the server.
- #run ⇒ Object
Constructor Details
#initialize(attributes = {}) ⇒ Server
This helper function parses the extension of the requested file and then looks up its content type.
22 23 24 |
# File 'lib/smallvictories/server.rb', line 22 def initialize attributes={} self.config = attributes[:config] end |
Instance Attribute Details
#config ⇒ Object
Returns the value of attribute config.
10 11 12 |
# File 'lib/smallvictories/server.rb', line 10 def config @config end |
#server ⇒ Object
Returns the value of attribute server.
10 11 12 |
# File 'lib/smallvictories/server.rb', line 10 def server @server end |
#socket ⇒ Object
Returns the value of attribute socket.
10 11 12 |
# File 'lib/smallvictories/server.rb', line 10 def socket @socket end |
Instance Method Details
#content_type(path) ⇒ Object
26 27 28 29 30 31 32 |
# File 'lib/smallvictories/server.rb', line 26 def content_type(path) if ext = File.extname(path).split(".").last MIME::Types.type_for(ext).first.to_s else 'text/html' end end |
#render_file(file, content_type = nil) ⇒ Object
This helper function saves the string to a temp file and streams it
62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/smallvictories/server.rb', line 62 def render_file file, content_type=nil socket.print "HTTP/1.1 200 OK\r\n" + "Content-Type: #{content_type || content_type(file)}\r\n" + "Content-Length: #{file.size}\r\n" + "Connection: close\r\n" socket.print "\r\n" # write the contents of the file to the socket IO.copy_stream(file, socket) end |
#render_string(string, content_type = nil) ⇒ Object
74 75 76 77 78 79 80 81 |
# File 'lib/smallvictories/server.rb', line 74 def render_string string, content_type=nil File.open(TEMP_FILE, "w") do |f| f.write(string) f.close end File.open(TEMP_FILE, "rb") { |f| render_file(f, content_type) } end |
#render_stylesheet ⇒ Object
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/smallvictories/server.rb', line 83 def render_stylesheet if File.exist?(File.join(WEB_ROOT, '_sv_custom.scss')) begin engine = Sass::Engine.new(File.open(File.join(WEB_ROOT, '_sv_custom.scss')).read, syntax: :scss) render_string(engine.render, 'text/css') rescue => e socket.print e end elsif File.exist?(File.join(WEB_ROOT, '_sv_custom.sass')) begin engine = Sass::Engine.new(File.open(File.join(WEB_ROOT, '_sv_custom.sass')).read, syntax: :sass) render_string(engine.render, 'text/css') rescue => e socket.print e end elsif File.exist?(File.join(WEB_ROOT, '_sv_custom.css')) # Open _sv_custom.css File.open(File.join(WEB_ROOT, '_sv_custom.css'), "rb") do |file| render_file(file) end end end |
#requested_file(request_line) ⇒ Object
This helper function parses the Request-Line and generates a path to a file on the server.
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/smallvictories/server.rb', line 37 def requested_file(request_line) request_uri = request_line.split(" ")[1] path = URI.unescape(URI(request_uri).path) clean = [] # Split the path into components parts = path.split("/") parts.each do |part| # skip any empty or current directory (".") path components next if part.empty? || part == '.' # If the path component goes up one directory level (".."), # remove the last clean component. # Otherwise, add the component to the Array of clean components part == '..' ? clean.pop : clean << part end # return the web root joined to the clean path File.join(WEB_ROOT, *clean) end |
#run ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/smallvictories/server.rb', line 106 def run # Except where noted below, the general approach of # handling requests and generating responses is # similar to that of the "Hello World" example # shown earlier. @server = TCPServer.new('localhost', 2345) loop do @socket = @server.accept request_line = socket.gets STDERR.puts request_line begin path = requested_file(request_line) path = File.join(path, 'index.html') if File.directory?(path) if path == File.join(WEB_ROOT, '_sv_custom.css') render_stylesheet elsif File.exist?(path) && !File.directory?(path) File.open(path, "rb") do |file| if File.extname(path) == '.html' # parse liquid template = Liquid::Template.parse(file.read, error_mode: :warn) render_string(template.render(SiteFile.files_hash)) else render_file(file) end end else = "File not found\n" # respond with a 404 error code to indicate the file does not exist socket.print "HTTP/1.1 404 Not Found\r\n" + "Content-Type: text/plain\r\n" + "Content-Length: #{.size}\r\n" + "Connection: close\r\n" socket.print "\r\n" socket.print end rescue => e socket.print "\r\n" end socket.close end end |