Last active
August 29, 2015 13:56
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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