Created
April 6, 2022 01:40
-
-
Save leandronsp/f5f2cc4a509dad73488e6a1d4af4aa40 to your computer and use it in GitHub Desktop.
Web Login/Logout in Ruby, using TCP socket, in less than 110 lines
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
require 'socket' | |
require 'cgi' | |
PORT = 3000 | |
socket = TCPServer.new('0.0.0.0', PORT) | |
puts "Listening to the port #{PORT}..." | |
loop do | |
# Wait for a new TCP connection..." | |
client = socket.accept | |
# Request | |
request = '' | |
headers = {} | |
body = '' | |
params = {} | |
cookies = {} | |
request_verb = '' | |
request_path = '' | |
while line = client.gets | |
break if line == "\r\n" | |
# Extract Request verb and path | |
if line.match(/HTTP\/.*?/) | |
request_verb, request_path, _ = line.split | |
end | |
request += line | |
# Request headers | |
header_key, header_value = line.split(': ') | |
headers[header_key] = header_value | |
end | |
puts request | |
puts "\n" | |
# Request body | |
content_length = headers['Content-Length'] | |
body = client.read(content_length.to_i) if content_length | |
# Extract params from body | |
body_parts = body.split('&') | |
params = body_parts | |
.map { |part| part.split('=').map(&CGI.method(:unescape)) } | |
.to_h | |
# Request cookies | |
if cookie = headers['Cookie'] | |
cookie_name, cookie_value = cookie.split('=') | |
cookies[cookie_name] = CGI.unescape(cookie_value) | |
end | |
# Response | |
response_headline = "HTTP/2.0" | |
response_status = 200 | |
response_headers = { 'Content-Type' => 'text/html' } | |
if request_verb == 'POST' && request_path == '/logout' | |
response_status = 301 | |
response_headers['Set-Cookie'] = "email=; path=/; HttpOnly; Expires=Thu, 01 Jan 1970 00:00:00 GMT" | |
response_headers['Location'] = "http://localhost:3000/" | |
elsif request_verb == 'POST' && request_path == '/login' | |
email = params['email'] | |
response_status = 301 | |
response_headers['Set-Cookie'] = "email=#{email}; path=/; HttpOnly" | |
response_headers['Location'] = "http://localhost:3000/" | |
elsif request_verb == 'GET' && request_path == '/' | |
if email = cookies['email'] | |
response_body = %{ | |
<h1>Hello, #{email}</h1> | |
<form action="/logout" method="POST"> | |
<input type="submit" value="Logout" /> | |
</form> | |
} | |
else | |
response_body = %{ | |
<form action="/login" method="POST"> | |
<input type="text" placeholder="Email" name="email"/> | |
<input type="password" placeholder="Password" name="password"/> | |
<input type="submit" value="Login"/> | |
</form> | |
} | |
end | |
else | |
response_status = 404 | |
response_body = %{ | |
<h1>Not Found</h1> | |
} | |
end | |
response_headers_str = | |
response_headers.reduce('') do |acc, (key, value)| | |
acc += "#{key}: #{value}\r\n"; acc | |
end | |
response = "#{response_headline} #{response_status}\r\n#{response_headers_str}\r\n#{response_body}" | |
client.puts(response.strip.gsub(/\n+/, "\n")) | |
# Close connection | |
client.close | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment