Skip to content

Instantly share code, notes, and snippets.

@sepulworld
Last active August 29, 2015 13:56
Show Gist options
  • Save sepulworld/9082680 to your computer and use it in GitHub Desktop.
Save sepulworld/9082680 to your computer and use it in GitHub Desktop.
TCPServerDeluxe, simple tcp socket server that responds to http requests for an executable
class TcpServerDeluxe
require 'socket'
"""
Ruby 2.1.0
Description:
TCP Server, runs from command line or upstart. Requires two agruments.
Argument #1 is server port, Argument #2 is executable path
200 will return stdout of executable (cgi)
405 error if not using HTTP GET method
404 error if client requests anything besides GET /
500 error if executable returns non-zero exitstatus
"""
"""
Running:
Start server with by executing:
ruby /path/to/tcpserverdeluxe.rb <port_number> </path/to/executable> &
tcpserverdeluxe.rb will run in the background.
Or manage with upstart, example:
console log
respawn
script
exec ruby /path/to/tcpserverdeluxe.rb $1 $2 >> /var/log/tcpserverdeluxe.log 2>&1
end script
"""
def self.success_responses_header
success_headers = [['HTTP/1.1 200',
'Content-Type: text/plain \r\n',
'Status 200 \r\n'].join("\r\n")]
return success_headers
end
def self.failure_responses_header
failure_headers = [['HTTP/1.1 405',
'Content-Type: text/plain \r\n',
'Status 405 \r\n'].join("\r\n"),
['HTTP/1.1 404',
'Content-Type: text/plain \r\n',
'Status 404 \r\n'].join("\r\n"),
['HTTP/1.1 500' ,
'Content-Type: text/plain \r\n',
'Status 500 \r\n'].join("\r\n")
]
return failure_headers
end
def self.body_responses
resp = ["405 Error",
"404 Error",
"500 Error",]
return resp
end
def self.client_response(client, status, resp)
client.write status
client.puts "\r\n\r\n", resp
client.close
end
def self.execute_cgi(executable_file)
executable = executable_file
cgi = IO.popen(executable, "r")
exitstatus = $?.to_i
return exitstatus, cgi.read
end
def self.init_server(port)
read_chunk = 1024 * 4
server = TCPServer.open(port)
return read_chunk, server
end
def self.run_server(port, executable)
read_chunk, server = init_server(port)
loop {
begin
client = server.accept
http_data = client.readpartial(read_chunk)
rescue EOFError
retry
end
case http_data.lines.first
when /^(OPTIONS|HEAD|POST|PUT|DELETE|TRACE|CONNECT).*/
resp = body_responses[0]
failure_headers = failure_responses_header[0]
client_response(client, failure_headers, resp)
when /^GET \/[a-zA-Z0-9]/
resp = body_responses[1]
failure_headers = failure_responses_header[1]
client_response(client, failure_headers, resp)
when /^GET \/./
exitstatus, cgi = execute_cgi(executable)
if exitstatus == 0 then
success_headers = success_responses_header[0]
client_response(client, success_headers, cgi)
else
resp = body_responses[2]
failure_headers = failure_responses_header[2]
client_response(client, failure_headers, resp)
end
else
resp = body_responses[0]
failure_headers = failure_responses_header[0]
client_response(client, failure_headers, resp)
end
}
end
end
TcpServerDeluxe.run_server(ARGV[0], ARGV[1]) if __FILE__==$0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment