32leaves.net

Quick and dirty HTTP server in Ruby

Today I quickly wrote a HTTP server in Ruby for a fellow student. It’s nothing special, does not care a single bit about security. But it’s easy to use, enhance and understand and below 100 lines of code. I’m sure there are better, more efficient and propably easier ways to implement this in Ruby, but I wanted it to be done quickly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#
# DeineMudder
# written by blacki
#
# This is an extremely minimalistic implementation of a HTTP server in ruby
# It does not care about security and stuff, so don't use this in a production
# environment. The code was written to be easily understandable (and I was tired
# when writting this), so there sure are ways to improve this.
#
# If you want to add URLs have a look at the KnownURLs class
#
# THERE IS ABSOLUTELY NOW WARRANTY FOR FITNESS OR WHATSOEVER OF
# THIS SOFTWARE. SO USE AT YOUR OWN RISK
#
# Published as Public Domain
#
#

require 'socket'

HOST = 'localhost'
PORT = 8080

#
# To introduce new URLs simply add methods to this class which will
# become available using "/METHOD_NAME" (GET requests only)
#
class KnownURLs
 
  def read(params)
    return File.new(params["name"]).readlines
  end
 
  def connect(params)
    Thread.start do
      system("ping", "-c 2", params["ip"])
    end

    return <<EOF
<html><head><title>connect</title></head><body><center><h1>Connection to #{params["ip"]} established</h1></center></body></html>
EOF

  end

end



#
# If you do any modification after this point be sure you know what you do
#

KNOWN_URLS = KnownURLs.new
def dispatch(method, url)
  result = nil

  params_str = url.split("?")
  url_handler_name = params_str[0][1..-1]
  if method == "GET"
    params = {}
    if params_str.length == 2
      params_key_value_pairs = params_str[1].split("&")
      params = Hash[*params_key_value_pairs.collect {|v| p = v.split("="); [p[0], p[p.size == 2 ? 1 : 0]]}.flatten]
    end

    result = KNOWN_URLS.send(url_handler_name, params) rescue "Caught error<br /><pre>#{$!}</pre>"
  end

  return result
end

serverSocket = TCPServer.new(HOST, PORT)
while clientSocket = serverSocket.accept
  req = clientSocket.gets.strip
  method, url = req.split(" ")
  puts "[REQ] #{method} #{url}"

  result = dispatch(method, url)
  response = { :status => 300, :body => "" }
  if result.nil?
    response = { :body   => "<html><head><title>404 NOT FOUND</title></head><body><center><h1>Unknown URL</h1></center></body></html>",
                 :status => 404 }
  else
    response[:body] = result
  end

  clientSocket.puts <<EOF
HTTP/1.0 #{response[:status]} OK
Server: Deine Mudder
Content-Lenhth: #{response[:body].length}
Content-Type: text/html
Connection: close

#{response[:body]}
EOF

  clientSocket.close
end

Leave a Reply

Fork me on GitHub