class MIDB::API::Engine
@author unrar This class handles runs the server engine using sockets and a loop.
Attributes
Attribute declaration here @!attribute config
@return [Hash] Contains the project's configuration, saved in .midb.yaml
@!attribute db
@return [String] Database name (if SQLite is the engine, file name without extension)
@!attribute http_status
@return [String] HTTP status code and string representation for the header
@!attribute h
@return [Object] MIDB::API::Hooks instance
Attribute declaration here @!attribute config
@return [Hash] Contains the project's configuration, saved in .midb.yaml
@!attribute db
@return [String] Database name (if SQLite is the engine, file name without extension)
@!attribute http_status
@return [String] HTTP status code and string representation for the header
@!attribute h
@return [Object] MIDB::API::Hooks instance
Attribute declaration here @!attribute config
@return [Hash] Contains the project's configuration, saved in .midb.yaml
@!attribute db
@return [String] Database name (if SQLite is the engine, file name without extension)
@!attribute http_status
@return [String] HTTP status code and string representation for the header
@!attribute h
@return [Object] MIDB::API::Hooks instance
Attribute declaration here @!attribute config
@return [Hash] Contains the project's configuration, saved in .midb.yaml
@!attribute db
@return [String] Database name (if SQLite is the engine, file name without extension)
@!attribute http_status
@return [String] HTTP status code and string representation for the header
@!attribute h
@return [Object] MIDB::API::Hooks instance
Public Class Methods
Constructor
@param db [String] Database to which the server will bind. @param stat [Fixnum] HTTP Status @param cnf [Hash] Config from the server controller.
# File lib/midb/serverengine_controller.rb, line 42 def initialize(db, stat, cnf, hooks=nil) @config = cnf @db = db @http_status = stat if hooks == nil @hooks = MIDB::API::Hooks.new else @hooks = hooks end end
Public Instance Methods
Method: parse_request
Parses an HTTP requests and returns an array [method, uri]
# File lib/midb/serverengine_controller.rb, line 210 def parse_request(req) [req.split(" ")[0], req.split(" ")[1]] end
Starts the server on a given port (default: 8081)
@param port [Fixnum] Port to which the server will listen.
# File lib/midb/serverengine_controller.rb, line 56 def start(port=8081) serv = TCPServer.new("localhost", port) MIDB::Interface::Server.info(:start, port) # Manage the requests loop do socket = serv.accept MIDB::Interface::Server.info(:incoming_request, socket.addr[3]) request = self.parse_request(socket.gets) # Get a hash with the headers headers = {} while line = socket.gets.split(' ', 2) break if line[0] == "" headers[line[0].chop] = line[1].strip end data = socket.read(headers["Content-Length"].to_i) MIDB::Interface::Server.info(:request, request) response_json = Hash.new() # Endpoint syntax: ["", FILE, ID, (ACTION)] endpoint = request[1].split("/") if endpoint.length >= 2 ep_file = endpoint[1].split("?")[0] else ep_file = "" end method = request[0] endpoints = [] # Valid endpoints # Load the JSON served files @config["serves"].each do |js| # The filename is a valid endpoint endpoints.push File.basename(js, ".*") end # Load the endpoints found = false endpoints.each do |ep| if ep_file == ep found = true MIDB::Interface::Server.info(:match_json, ep) # Create the model dbop = MIDB::API::Model.new(ep, @db, self) # Analyze the request and pass it to the model # Is the method accepted? accepted_methods = ["GET", "POST", "PUT", "DELETE"] unless accepted_methods.include? method @http_status = "405 Method Not Allowed" response_json = MIDB::Interface::Server.json_error(405, "Method Not Allowed").to_json else # Do we need authentication? auth_req = false unauthenticated = false if @config["privacy#{method.downcase}"] == true MIDB::Interface::Server.info(:auth_required) auth_req = true # For GET and DELETE requests, the object of the digest is the endpoint if (method == "GET") || (method == "DELETE") data = ep_file end # If it's a GET request and we have a different key for GET methods... if (@config["apigetkey"] != nil) && (method == "GET") unauthenticated = (not headers.has_key? "Authentication") || (not MIDB::API::Security.check?(headers["Authentication"], data, @config["apigetkey"])) else unauthenticated = (not headers.has_key? "Authentication") || (not MIDB::API::Security.check?(headers["Authentication"], data, @config["apikey"])) end end # Proceed to handle the request if unauthenticated response_json = self.unauth_request puts ">> has header: #{headers.has_key? "Authentication"}" else MIDB::Interface::Server.info(:auth_success) if (not unauthenticated) && auth_req if method == "GET" case endpoint.length when 2 # No ID has been specified. Return all the entries # Pass it to the model and get the JSON MIDB::Interface::Server.info(:fetch, "get_all_entries()") response_json = dbop.get_all_entries().to_json when 3 # This regular expression checks if it contains an integer if /\A[-+]?\d+\z/ === endpoint[2] # An ID has been specified. Should it exist, return all of its entries. MIDB::Interface::Server.info(:fetch, "get_entries(#{endpoint[2]})") response_json = dbop.get_entries(endpoint[2].to_i).to_json else # A row has been specified, but no pattern MIDB::Interface::Server.info(:fetch, "get_column_entries(#{endpoint[2]})") response_json = dbop.get_column_entries(endpoint[2]).to_json end when 4 if (endpoint[2].is_a? String) && (endpoint[3].is_a? String) then # A row and a pattern have been specified MIDB::Interface::Server.info(:fetch, "get_matching_rows(#{endpoint[2]}, #{endpoint[3]})") response_json = dbop.get_matching_rows(endpoint[2], endpoint[3]).to_json end end elsif method == "POST" MIDB::Interface::Server.info(:fetch, "post(#{data})") response_json = dbop.post(data).to_json else if endpoint.length >= 3 if method == "DELETE" MIDB::Interface::Server.info(:fetch, "delete(#{endpoint[2]})") response_json = dbop.delete(endpoint[2]).to_json elsif method == "PUT" MIDB::Interface::Server.info(:fetch, "put(#{endpoint[2]}, data)") response_json = dbop.put(endpoint[2], data).to_json end else @http_status = "404 Not Found" response_json = MIDB::Interface::Server.json_error(404, "Must specify an ID.").to_json end end end end MIDB::Interface::Server.info(:response, response_json) # Return the results via HTTP socket.print "HTTP/1.1 #{@http_status}\r\n" + "Content-Type: text/json\r\n" + "Content-Length: #{response_json.size}\r\n" + "Connection: close\r\n" socket.print "\r\n" socket.print response_json socket.print "\r\n" MIDB::Interface::Server.info(:success) end end unless found MIDB::Interface::Server.info(:not_found) response = MIDB::Interface::Server.json_error(404, "Invalid API endpoint.").to_json socket.print "HTTP/1.1 404 Not Found\r\n" + "Content-Type: text/json\r\n" + "Content-Length: #{response.size}\r\n" + "Connection: close\r\n" socket.print "\r\n" socket.print response end end end
Handle an unauthorized request
# File lib/midb/serverengine_controller.rb, line 31 def unauth_request @http_status = "401 Unauthorized" MIDB::Interface::Server.info(:no_auth) MIDB::Interface::Server.json_error(401, "Unauthorized").to_json end