teehee :3
This commit is contained in:
parent
2ce8a9c28b
commit
0f893c1d83
27 changed files with 3905 additions and 68 deletions
|
|
@ -1,13 +1,18 @@
|
|||
# Request class used as instance object of an incoming TCP request to manage that request. Splits the request into it's method, resource, version, headers and params to be read by the router.
|
||||
class Request
|
||||
attr_reader :method, :resource, :version, :headers, :params
|
||||
|
||||
# @param input [String] the string of the request
|
||||
def initialize(input)
|
||||
variable_definer(input)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def variable_definer(input) ##Defines required class variables by splitting up the input text
|
||||
# Defines required class variables by splitting up the input text
|
||||
#
|
||||
# @param input [String] the string of the request
|
||||
def variable_definer(input)
|
||||
rows = input.split(/\r\n/)
|
||||
@method, @resource, @version = rows[0].split(' ')
|
||||
@headers, @params = {}, {}
|
||||
|
|
@ -25,6 +30,10 @@ class Request
|
|||
end
|
||||
end
|
||||
|
||||
# Reorganizes the information in the header based on the format
|
||||
#
|
||||
# @param rows [Array] A list of the rows in the header
|
||||
# @param limit [Int] The limit where the header ends.
|
||||
def header_constructor(rows, limit)
|
||||
for row in rows[1..limit-1]
|
||||
context, information = row.split(' ')
|
||||
|
|
@ -33,6 +42,9 @@ class Request
|
|||
end
|
||||
end
|
||||
|
||||
# Organizes the parameter information into a dict of parameters
|
||||
#
|
||||
# @param rows [Array] A list of the rows of parameters
|
||||
def param_constructor(rows)
|
||||
for row in rows[rows.find_index("")+1..rows.length]
|
||||
information = row.split(/&/)
|
||||
|
|
@ -43,6 +55,7 @@ class Request
|
|||
end
|
||||
end
|
||||
|
||||
# Organizes the resource information into a dict of resource parameters
|
||||
def resource_deconstructor
|
||||
information = @resource.split('?')[1].split(/&/)
|
||||
for info in information
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
# Reponse class used to format and respond to a request. Takes in the touple returned by the route class and returns either the requested method or the file in the requested position (if the match returned a 404 and a file is found in the requested position)
|
||||
class Response
|
||||
|
||||
# Initialize the response by checking if a response is applicable and what information should be returned
|
||||
#
|
||||
# @param routeReturn [Array] A list consisting of the matched request and the status
|
||||
def initialize(routeReturn)
|
||||
outputContent = {}
|
||||
status = routeReturn[1]
|
||||
if status == 200
|
||||
if routeReturn[0][:block] != nil
|
||||
outputContent[:info] = routeReturn[0][:block].call
|
||||
print("Recieved HTML, enabling as called:\n #{outputContent[:info]}")
|
||||
outputContent[:type] = "text/html"
|
||||
status = 200
|
||||
else
|
||||
outputContent[:info] = nil
|
||||
status = 200
|
||||
end
|
||||
elsif status == 404
|
||||
print("HTML route not found, searching for target file...\n")
|
||||
if File.file?("./public/#{routeReturn[0].resource}")
|
||||
print("Found file: ./public/#{routeReturn[0].resource}\n")
|
||||
outputContent[:info] = File.open("./public#{routeReturn[0].resource}", "rb")
|
||||
if outputContent[:type].to_s.split("/")[0] == "text"
|
||||
print("Successfully opened file \"./public#{routeReturn[0].resource}\" with contents:\n#{outputContent[:info].read}\n ")
|
||||
end
|
||||
outputContent[:type] = getMime(File.extname("./public/#{routeReturn[0].resource}").to_str)
|
||||
status = 200
|
||||
else
|
||||
print("Could not find file: \"./public/#{routeReturn[0].resource}\"\n")
|
||||
status = 404
|
||||
end
|
||||
end
|
||||
@status = status
|
||||
@outputContent = outputContent
|
||||
end
|
||||
|
||||
# Responds to the request with the information requested
|
||||
#
|
||||
# @param session [TCPsocket] A client request through the TCP port awaiting a response
|
||||
def print(session)
|
||||
print("\nStatus: #{@status.to_s}\n")
|
||||
session.print "HTTP/1.1 #{@status}\r\n"
|
||||
if @status != 404
|
||||
session.print "Content-Type: #{@outputContent[:type]}\r\n"
|
||||
print("\nReading content type: #{@outputContent[:type]}\n")
|
||||
print("\nLoaded is of type: #{@outputContent[:info].class}\n")
|
||||
print("\nSize reading: #{File.size(@outputContent[:info])}\n")
|
||||
session.print "Content-Length: #{File.size(@outputContent[:info])}\r\n"
|
||||
session.print "\r\n"
|
||||
printContent = @outputContent[:info].read
|
||||
if printContent; session.print printContent end
|
||||
end
|
||||
session.close
|
||||
end
|
||||
|
||||
# Gets the mime extension for respond file
|
||||
#
|
||||
# @param extension [Str] a string containing the extension of the file to find the MIME format for
|
||||
# @return [String] the MIME format of the requested extension.
|
||||
def getMime(extension)
|
||||
mimes = { ".css" => "text/css", ".html" => "text/html", ".ico" => "image/vnd.microsoft.icon", ".jpg" => "image/jpeg", ".png" => "image/png"}
|
||||
if mimes[extension] != nil
|
||||
print("Found #{mimes[extension]} result for extension #{extension}\n")
|
||||
return mimes[extension]
|
||||
else
|
||||
print("Found no result for extension #{extension}\n")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
16
lib/route.rb
16
lib/route.rb
|
|
@ -1,19 +1,27 @@
|
|||
require 'debug'
|
||||
# Router class for pairing incoming requests with routes
|
||||
class Router
|
||||
attr_reader :routes
|
||||
def initialize()
|
||||
@routes = []
|
||||
end
|
||||
|
||||
# Method for adding a route to the router. Incoming requests will be checked against these routes to see if the incoming requests has a valid target.
|
||||
#
|
||||
# @param method [String] A string with the method for the request
|
||||
# @param input [String] A string for the input to match the request with
|
||||
# @param &block [Block] The block to execute and respond with if the route is matched.
|
||||
def add_route(method, input, &block)
|
||||
routeHash = {method: method, resource: input, block: block}
|
||||
@routes << routeHash
|
||||
p "added successfully, @routes are: #{@routes}"
|
||||
end
|
||||
|
||||
# Method for matching the incoming requests with the expected routes. Returns a touple with either the matched object and an int 200 representing status or the request and an int 404 representing status
|
||||
#
|
||||
# @param request [Request] the Request class to find a match for
|
||||
# @return [Array] the array consisting of the matched method or the request and the status of the match.
|
||||
def match_route(request)
|
||||
|
||||
#spec ["3" "bostongurka"]
|
||||
|
||||
match = @routes.find {|route| (route[:method] == request.method) && (request.resource.match?(route[:resource]))}
|
||||
|
||||
|
|
@ -22,9 +30,9 @@ class Router
|
|||
returner = [match, 200]
|
||||
return returner
|
||||
else
|
||||
if request.resource.match?(@routes[0][:resource]) != true
|
||||
if request.resource.match?(@routes[0][:resource]) != true #If the requested resource did not match the expected resource for that method
|
||||
p "failed to find: #{request.resource} resource.\nExpected: #{String(@routes[0][:resource])} resource"
|
||||
elsif @routes[0][:method] != request.method
|
||||
elsif @routes[0][:method] != request.method #If the current method did not match the expected method for that resource
|
||||
p "failed to find #{request.method} method.\nExpected: #{@routes[0][:method]} method"
|
||||
else
|
||||
p "Failed to match, got no reason, just kinda didn't feel like it"
|
||||
|
|
|
|||
|
|
@ -1,14 +1,21 @@
|
|||
require 'socket'
|
||||
require_relative 'request'
|
||||
require_relative 'route'
|
||||
require_relative 'response'
|
||||
|
||||
# Main class for managing and talking between sub-classes during request-response cycles. Utalizes the request, route and response classes.
|
||||
class HTTPServer
|
||||
|
||||
# Initializes the HTTPServer object
|
||||
#
|
||||
# @param port [Int] An integer representing the port number for the http server
|
||||
# @param router [Router] The Router class holding the expected routes for the server
|
||||
def initialize(port, router)
|
||||
@port = port
|
||||
@router = router
|
||||
end
|
||||
|
||||
# Starts the TCP server and begins reading for requests on the designated port. When a request comes in it turns it into a request object using the request class, and sends that to the router. It then sends the matched information to the response class.
|
||||
def start
|
||||
server = TCPServer.new(@port)
|
||||
puts "Listening on #{@port}"
|
||||
|
|
@ -27,63 +34,9 @@ class HTTPServer
|
|||
pp request
|
||||
|
||||
routeReturn = @router.match_route(request)
|
||||
# pil nedåt ska in i response-klassen
|
||||
response = Response.new(routeReturn, session)
|
||||
response.print()
|
||||
|
||||
outputContent = {}
|
||||
if routeReturn[1] == 200
|
||||
if routeReturn[0][:block] != nil
|
||||
outputContent[:info] = routeReturn[0][:block].call
|
||||
print("Recieved HTML, enabling as called:\n #{outputContent[:info]}")
|
||||
outputContent[:type] = "text/html"
|
||||
status = 200
|
||||
else
|
||||
outputContent[:info] = nil
|
||||
status = 200
|
||||
end
|
||||
elsif routeReturn[1] == 404
|
||||
print("HTML route not found, searching for target file...\n")
|
||||
if File.file?("./public/#{routeReturn[0].resource}")
|
||||
print("Found file: ./public/#{routeReturn[0].resource}\n")
|
||||
outputContent[:info] = File.open("./public#{routeReturn[0].resource}", "rb")
|
||||
if outputContent[:type].to_s.split("/")[0] == "text"
|
||||
print("Successfully opened file \"./public#{routeReturn[0].resource}\" with contents:\n#{outputContent[:info].read}\n ")
|
||||
end
|
||||
outputContent[:type] = getMime(File.extname("./public/#{routeReturn[0].resource}").to_str)
|
||||
status = 200
|
||||
else
|
||||
print("Could not find file: \"./public/#{routeReturn[0].resource}\"\n")
|
||||
status = 404
|
||||
end
|
||||
end
|
||||
|
||||
# Nedanstående bör göras i er Response-klass
|
||||
|
||||
print("\nStatus: #{status.to_s}\n")
|
||||
session.print "HTTP/1.1 #{status}\r\n"
|
||||
if status != 404
|
||||
session.print "Content-Type: #{outputContent[:type]}\r\n"
|
||||
print("\nReading content type: #{outputContent[:type]}\n")
|
||||
print("\nLoaded is of type: #{outputContent[:info].class}\n")
|
||||
print("\nSize reading: #{File.size(outputContent[:info])}\n")
|
||||
session.print "Content-Length: #{File.size(outputContent[:info])}\r\n"
|
||||
session.print "\r\n"
|
||||
printContent = outputContent[:info].read
|
||||
if printContent; session.print printContent end
|
||||
end
|
||||
session.close
|
||||
end
|
||||
end
|
||||
|
||||
def getMime(extension)
|
||||
mimes = { ".css" => "text/css", ".html" => "text/html", ".ico" => "image/vnd.microsoft.icon", ".jpg" => "image/jpeg", ".png" => "image/png"}
|
||||
if mimes[extension] != nil
|
||||
print("Found #{mimes[extension]} result for extension #{extension}\n")
|
||||
return mimes[extension]
|
||||
else
|
||||
print("Found no result for extension #{extension}\n")
|
||||
return nil
|
||||
response = Response.new(routeReturn)
|
||||
response.print(session)
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue