add http server
This commit is contained in:
		
							
								
								
									
										162
									
								
								addons/http_server/http_server.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								addons/http_server/http_server.gd
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,162 @@
 | 
			
		||||
class_name HTTPServer extends TCPServer
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Public constants
 | 
			
		||||
 | 
			
		||||
const Method = preload("res://addons/http_server/method.gd")
 | 
			
		||||
const Request = preload("res://addons/http_server/request.gd")
 | 
			
		||||
const Response = preload("res://addons/http_server/response.gd")
 | 
			
		||||
const Status = preload("res://addons/http_server/status.gd")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Private variables
 | 
			
		||||
 | 
			
		||||
var __endpoints: Dictionary = {
 | 
			
		||||
	# key: [Int, String], array with 0 index representing method, 1 index representing endpoint
 | 
			
		||||
	# value: Callable, reference to function to call
 | 
			
		||||
}
 | 
			
		||||
var __fallback: Callable
 | 
			
		||||
var __server: TCPServer = null
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Public methods
 | 
			
		||||
 | 
			
		||||
func endpoint(type: int, endpoint: String, function: Callable) -> void:
 | 
			
		||||
	var endpoint_hash: Array = [type, endpoint]
 | 
			
		||||
	if endpoint_hash in __endpoints:
 | 
			
		||||
		print(
 | 
			
		||||
			"[ERR] Endpoint already defined type: %s, endpoint: %s" % [
 | 
			
		||||
				Method.type_to_identifier(type),
 | 
			
		||||
				endpoint,
 | 
			
		||||
			]
 | 
			
		||||
		)
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
	__endpoints[endpoint_hash] = function
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func fallback(function: Callable) -> void:
 | 
			
		||||
	__fallback = function
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func __take_connection() -> StreamPeerTCP:
 | 
			
		||||
	if !is_listening():
 | 
			
		||||
		print(
 | 
			
		||||
			"[ERR] Server is not listening, please initialize and listen before calling `take_connection`"
 | 
			
		||||
		)
 | 
			
		||||
		return null
 | 
			
		||||
 | 
			
		||||
	var connection: StreamPeerTCP = take_connection()
 | 
			
		||||
 | 
			
		||||
	if connection:
 | 
			
		||||
		__process_connection(connection)
 | 
			
		||||
 | 
			
		||||
	return connection
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Private methods
 | 
			
		||||
 | 
			
		||||
func __process_connection(connection: StreamPeerTCP) -> void:
 | 
			
		||||
	var content: PackedByteArray = PackedByteArray([])
 | 
			
		||||
 | 
			
		||||
	while true:
 | 
			
		||||
		var bytes = connection.get_available_bytes()
 | 
			
		||||
		if bytes == 0:
 | 
			
		||||
			break
 | 
			
		||||
 | 
			
		||||
		var data = connection.get_partial_data(bytes)
 | 
			
		||||
		content.append_array(data[1])
 | 
			
		||||
 | 
			
		||||
	if content.is_empty():
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
	var content_string: String = content.get_string_from_utf8()
 | 
			
		||||
	var content_parts: Array = content_string.split("\r\n")
 | 
			
		||||
 | 
			
		||||
	if content_parts.is_empty():
 | 
			
		||||
		connection.put_data(__response_from_status(Status.BAD_REQUEST).to_utf8_buffer())
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
	var request_line = content_parts[0]
 | 
			
		||||
	var request_line_parts = request_line.split(" ")
 | 
			
		||||
 | 
			
		||||
	var method: String = request_line_parts[0]
 | 
			
		||||
	var endpoint: String = request_line_parts[1]
 | 
			
		||||
 | 
			
		||||
	var headers: Dictionary = {}
 | 
			
		||||
	var header_index: int = content_parts.find("")
 | 
			
		||||
 | 
			
		||||
	if header_index == -1:
 | 
			
		||||
		print(
 | 
			
		||||
			"[ERR] Error parsing request data: %s" % [str(content)]
 | 
			
		||||
		)
 | 
			
		||||
		connection.put_data(__response_from_status(Status.BAD_REQUEST).to_utf8_buffer())
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
	for i in range(1, header_index):
 | 
			
		||||
		var header_parts: Array = content_parts[i].split(":", true, 1)
 | 
			
		||||
		var header = header_parts[0].strip_edges().to_lower()
 | 
			
		||||
		var value = header_parts[1].strip_edges()
 | 
			
		||||
 | 
			
		||||
		headers[header] = value
 | 
			
		||||
 | 
			
		||||
	var body: String = ""
 | 
			
		||||
	if header_index != content_parts.size() - 1:
 | 
			
		||||
		var body_parts: Array = content_parts.slice(header_index + 1, content_parts.size())
 | 
			
		||||
		body = "\r\n".join(PackedStringArray(body_parts))
 | 
			
		||||
 | 
			
		||||
	var response: Response = __process_request(method, endpoint, headers, body)
 | 
			
		||||
	connection.put_data(response.to_utf8_buffer())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func __process_request(method: String, endpoint: String, headers: Dictionary, body: String) -> Response:
 | 
			
		||||
	var type: int = Method.description_to_type(method)
 | 
			
		||||
 | 
			
		||||
	var request: Request = Request.new(
 | 
			
		||||
		type,
 | 
			
		||||
		endpoint,
 | 
			
		||||
		headers,
 | 
			
		||||
		body
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	var endpoint_func: Callable
 | 
			
		||||
	var endpoint_parts: PackedStringArray = endpoint.split("/", false)
 | 
			
		||||
 | 
			
		||||
	while endpoint_func.is_null():
 | 
			
		||||
		var endpoint_hash: Array = [type, "/" + "/".join(endpoint_parts)]
 | 
			
		||||
		if __endpoints.has(endpoint_hash):
 | 
			
		||||
			endpoint_func = __endpoints[endpoint_hash]
 | 
			
		||||
		elif endpoint_parts.is_empty():
 | 
			
		||||
			break
 | 
			
		||||
		else:
 | 
			
		||||
			endpoint_parts.remove_at(endpoint_parts.size() - 1)
 | 
			
		||||
 | 
			
		||||
	if endpoint_func.is_null():
 | 
			
		||||
		print(
 | 
			
		||||
			"[WRN] Recieved request for unknown endpoint, method: %s, endpoint: %s" % [method, endpoint]
 | 
			
		||||
		)
 | 
			
		||||
		if __fallback:
 | 
			
		||||
			endpoint_func = __fallback
 | 
			
		||||
		else:
 | 
			
		||||
			return __response_from_status(Status.NOT_FOUND)
 | 
			
		||||
 | 
			
		||||
	var response: Response = Response.new()
 | 
			
		||||
 | 
			
		||||
	if endpoint_func.is_null():
 | 
			
		||||
		print(
 | 
			
		||||
			"[ERR] Callable for endpoint not valid, method: %s, endpoint: %s" % [method, endpoint]
 | 
			
		||||
		)
 | 
			
		||||
	else:
 | 
			
		||||
		print(
 | 
			
		||||
			"[INF] Recieved request method: %s, endpoint: %s" % [method, endpoint]
 | 
			
		||||
		)
 | 
			
		||||
		endpoint_func.call(request, response)
 | 
			
		||||
 | 
			
		||||
	return response
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func __response_from_status(code: int) -> Response:
 | 
			
		||||
	var response: Response = Response.new()
 | 
			
		||||
	response.status(code)
 | 
			
		||||
 | 
			
		||||
	return response
 | 
			
		||||
							
								
								
									
										61
									
								
								addons/http_server/method.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								addons/http_server/method.gd
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
			
		||||
# Public Constants
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	GET = 0,
 | 
			
		||||
	HEAD,
 | 
			
		||||
	POST,
 | 
			
		||||
	PUT,
 | 
			
		||||
	DELETE,
 | 
			
		||||
	CONNECT,
 | 
			
		||||
	OPTIONS,
 | 
			
		||||
	TRACE,
 | 
			
		||||
	PATCH
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Private constants
 | 
			
		||||
 | 
			
		||||
const __DESCRIPTIONS: Dictionary = {
 | 
			
		||||
	GET: "Get",
 | 
			
		||||
	HEAD: "Head",
 | 
			
		||||
	POST: "Post",
 | 
			
		||||
	PUT: "Put",
 | 
			
		||||
	DELETE: "Delete",
 | 
			
		||||
	CONNECT: "Connect",
 | 
			
		||||
	OPTIONS: "Options",
 | 
			
		||||
	TRACE: "Trace",
 | 
			
		||||
	PATCH: "Patch",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const __TYPES: Dictionary = {
 | 
			
		||||
	"GET": GET,
 | 
			
		||||
	"HEAD": HEAD,
 | 
			
		||||
	"POST": POST,
 | 
			
		||||
	"PUT": PUT,
 | 
			
		||||
	"DELETE": DELETE,
 | 
			
		||||
	"CONNECT": CONNECT,
 | 
			
		||||
	"OPTIONS": OPTIONS,
 | 
			
		||||
	"TRACE": TRACE,
 | 
			
		||||
	"PATCH": PATCH,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Public methods
 | 
			
		||||
 | 
			
		||||
static func description_to_type(description: String) -> int:
 | 
			
		||||
	return identifier_to_type(description.to_upper())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static func identifier_to_type(identifier: String) -> int:
 | 
			
		||||
	if __TYPES.has(identifier):
 | 
			
		||||
		return __TYPES[identifier]
 | 
			
		||||
 | 
			
		||||
	return -1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static func type_to_description(type: int) -> String:
 | 
			
		||||
	return __DESCRIPTIONS[type]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static func type_to_identifier(type: int) -> String:
 | 
			
		||||
	return type_to_description(type).to_upper()
 | 
			
		||||
							
								
								
									
										7
									
								
								addons/http_server/plugin.cfg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								addons/http_server/plugin.cfg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
[plugin]
 | 
			
		||||
 | 
			
		||||
name="HTTPServer"
 | 
			
		||||
description="HTTP Server implementation for receiving HTTP requests from external sources."
 | 
			
		||||
author="velopman"
 | 
			
		||||
version="0.1"
 | 
			
		||||
script="plugin.gd"
 | 
			
		||||
							
								
								
									
										10
									
								
								addons/http_server/plugin.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								addons/http_server/plugin.gd
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
@tool
 | 
			
		||||
extends EditorPlugin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _enter_tree() -> void:
 | 
			
		||||
	pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func _exit_tree() -> void:
 | 
			
		||||
	pass
 | 
			
		||||
							
								
								
									
										69
									
								
								addons/http_server/request.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								addons/http_server/request.gd
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
 | 
			
		||||
# Public constants
 | 
			
		||||
 | 
			
		||||
const Method = preload("res://addons/http_server/method.gd")
 | 
			
		||||
 | 
			
		||||
# Private variables
 | 
			
		||||
 | 
			
		||||
var __body: String = ""
 | 
			
		||||
var __endpoint: String = ""
 | 
			
		||||
var __headers: Dictionary = {
 | 
			
		||||
	# key: String, header name
 | 
			
		||||
	# value: Variant, header value
 | 
			
		||||
}
 | 
			
		||||
var __json_data = null # Variant
 | 
			
		||||
var __type: int = Method.GET
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Lifecyle methods
 | 
			
		||||
 | 
			
		||||
func _init(type: int,endpoint: String,headers: Dictionary,body: String):
 | 
			
		||||
	__body = body
 | 
			
		||||
	__endpoint = endpoint
 | 
			
		||||
	__headers = headers
 | 
			
		||||
	__type = type
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Public methods
 | 
			
		||||
 | 
			
		||||
func body() -> String:
 | 
			
		||||
	return __body
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func endpoint() -> String:
 | 
			
		||||
	return __endpoint
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func header(name: String = "", default = null): # Variant
 | 
			
		||||
	return __headers.get(name, default)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func headers() -> Dictionary:
 | 
			
		||||
	return __headers
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func json(): # Variant
 | 
			
		||||
	if __json_data != null:
 | 
			
		||||
		return __json_data
 | 
			
		||||
 | 
			
		||||
	var content_type = header("content-type")
 | 
			
		||||
	if  content_type != "application/json":
 | 
			
		||||
		print(
 | 
			
		||||
			"[WRN] Attempting to call get_json checked a request with content-type: %s" % [content_type]
 | 
			
		||||
		)
 | 
			
		||||
		return null
 | 
			
		||||
 | 
			
		||||
	var json = JSON.new()
 | 
			
		||||
	var test_json_conv = json.parse(__body)
 | 
			
		||||
	if test_json_conv != OK:
 | 
			
		||||
		print(
 | 
			
		||||
			"[ERR] Error parsing request json at line %s: %s" % [json.get_error_line(), json.get_error_message()]
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
	__json_data = json.get_data()
 | 
			
		||||
 | 
			
		||||
	return __json_data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func type() -> int:
 | 
			
		||||
	return __type
 | 
			
		||||
							
								
								
									
										57
									
								
								addons/http_server/response.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								addons/http_server/response.gd
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
# Public Constants
 | 
			
		||||
 | 
			
		||||
const Status = preload("res://addons/http_server/status.gd")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Private variables
 | 
			
		||||
 | 
			
		||||
var __data = "" # variant
 | 
			
		||||
var __headers: Dictionary = {
 | 
			
		||||
	# key: String, header name
 | 
			
		||||
	# value: Variant, header value
 | 
			
		||||
}
 | 
			
		||||
var __status: int = 200
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Public methods
 | 
			
		||||
 | 
			
		||||
func data(data) -> void: # data: Variant
 | 
			
		||||
	__data = data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func header(name: String, value) -> void: # value: Variant
 | 
			
		||||
	__headers[name.to_lower()] = value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func json(data) -> void: # data: Variant
 | 
			
		||||
	header("content-type", "application/json")
 | 
			
		||||
	__data = data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func status(status: int) -> void:
 | 
			
		||||
	__status = status
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func to_utf8_buffer() -> PackedByteArray:
 | 
			
		||||
	var content = PackedStringArray()
 | 
			
		||||
 | 
			
		||||
	content.append(Status.code_to_status_line(__status))
 | 
			
		||||
 | 
			
		||||
	var data = __data
 | 
			
		||||
	if data.is_empty():
 | 
			
		||||
		data = Status.code_to_description(__status)
 | 
			
		||||
 | 
			
		||||
	if __headers.get("content-type", "") == "application/json":
 | 
			
		||||
		data = JSON.stringify(data)
 | 
			
		||||
 | 
			
		||||
	__headers['content-length'] = len(data)
 | 
			
		||||
 | 
			
		||||
	for header in __headers:
 | 
			
		||||
		content.append("%s: %s" % [header, str(__headers[header])])
 | 
			
		||||
 | 
			
		||||
	content.append("")
 | 
			
		||||
 | 
			
		||||
	if data:
 | 
			
		||||
		content.append(data)
 | 
			
		||||
 | 
			
		||||
	return "\r\n".join(content).to_utf8_buffer()
 | 
			
		||||
							
								
								
									
										147
									
								
								addons/http_server/status.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								addons/http_server/status.gd
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
			
		||||
# Public constants
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	CONTINUE = 100,
 | 
			
		||||
	SWITCHING_PROTOCOLS = 101,
 | 
			
		||||
	PROCESSING = 102,
 | 
			
		||||
	EARLY_HINTS = 103,
 | 
			
		||||
	OK = 200,
 | 
			
		||||
	CREATED = 201,
 | 
			
		||||
	ACCEPTED = 202,
 | 
			
		||||
	NON_AUTHORITATIVE_INFORMATION = 203,
 | 
			
		||||
	NO_CONTENT = 204,
 | 
			
		||||
	RESET_CONTENT = 205,
 | 
			
		||||
	PARTIAL_CONTENT = 206,
 | 
			
		||||
	MULTI_STATUS = 207,
 | 
			
		||||
	ALREADY_REPORTED = 208,
 | 
			
		||||
	IM_USED = 226,
 | 
			
		||||
	MULTIPLE_CHOICE = 300,
 | 
			
		||||
	MOVED_PERMANENTLY = 301,
 | 
			
		||||
	FOUND = 302,
 | 
			
		||||
	SEE_OTHER = 303,
 | 
			
		||||
	NOT_MODIFIED = 304,
 | 
			
		||||
	TEMPORARY_REDIRECT = 307,
 | 
			
		||||
	PERMANENT_REDIRECT = 308,
 | 
			
		||||
	BAD_REQUEST = 400,
 | 
			
		||||
	UNAUTHORIZED = 401,
 | 
			
		||||
	PAYMENT_REQUIRED = 402,
 | 
			
		||||
	FORBIDDEN = 403,
 | 
			
		||||
	NOT_FOUND = 404,
 | 
			
		||||
	METHOD_NOT_ALLOWED = 405,
 | 
			
		||||
	NOT_ACCEPTABLE = 406,
 | 
			
		||||
	PROXY_AUTHENTICATION_REQUIRED = 407,
 | 
			
		||||
	REQUEST_TIMEOUT = 408,
 | 
			
		||||
	CONFLICT = 409,
 | 
			
		||||
	GONE = 410,
 | 
			
		||||
	LENGTH_REQUIRED = 411,
 | 
			
		||||
	PRECONDITION_FAILED = 412,
 | 
			
		||||
	PAYLOAD_TOO_LARGE = 413,
 | 
			
		||||
	URI_TOO_LONG = 414,
 | 
			
		||||
	UNSUPPORTED_MEDIA_TYPE = 415,
 | 
			
		||||
	RANGE_NOT_SATISFIABLE = 416,
 | 
			
		||||
	EXPECTATION_FAILED = 417,
 | 
			
		||||
	IM_A_TEAPOT = 418,
 | 
			
		||||
	MISDIRECTED_REQUEST = 421,
 | 
			
		||||
	UNPROCESSABLE_ENTITY = 422,
 | 
			
		||||
	LOCKED = 423,
 | 
			
		||||
	FAILED_DEPENDENCY = 424,
 | 
			
		||||
	TOO_EARLY = 425,
 | 
			
		||||
	UPGRADE_REQUIRED = 426,
 | 
			
		||||
	PRECONDITION_REQUIRED = 428,
 | 
			
		||||
	TOO_MANY_REQUESTS = 429,
 | 
			
		||||
	REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
 | 
			
		||||
	UNAVAILABLE_FOR_LEGAL_REASONS = 451,
 | 
			
		||||
	INTERNAL_SERVER_ERROR = 500,
 | 
			
		||||
	NOT_IMPLEMENTED = 501,
 | 
			
		||||
	BAD_GATEWAY = 502,
 | 
			
		||||
	SERVICE_UNAVAILABLE = 503,
 | 
			
		||||
	GATEWAY_TIMEOUT = 504,
 | 
			
		||||
	HTTP_VERSION_NOT_SUPPORTED = 505,
 | 
			
		||||
	VARIANT_ALSO_NEGOTIATES = 506,
 | 
			
		||||
	INSUFFICIENT_STORAGE = 507,
 | 
			
		||||
	LOOP_DETECTED = 508,
 | 
			
		||||
	NOT_EXTENDED = 510,
 | 
			
		||||
	NETWORK_AUTHENTICATION_REQUIRED = 511,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Private constants
 | 
			
		||||
 | 
			
		||||
const __DESCRIPTIONS: Dictionary = {
 | 
			
		||||
	CONTINUE: "Continue",
 | 
			
		||||
	SWITCHING_PROTOCOLS: "Switching Protocols",
 | 
			
		||||
	PROCESSING: "Processing",
 | 
			
		||||
	EARLY_HINTS: "Early Hints",
 | 
			
		||||
	OK: "Ok",
 | 
			
		||||
	CREATED: "Created",
 | 
			
		||||
	ACCEPTED: "Accepted",
 | 
			
		||||
	NON_AUTHORITATIVE_INFORMATION: "Non-Authoritative Information",
 | 
			
		||||
	NO_CONTENT: "No Content",
 | 
			
		||||
	RESET_CONTENT: "Reset Content",
 | 
			
		||||
	PARTIAL_CONTENT: "Partial Content",
 | 
			
		||||
	MULTI_STATUS: "Multi-Status",
 | 
			
		||||
	ALREADY_REPORTED: "Already Reported",
 | 
			
		||||
	IM_USED: "IM Used",
 | 
			
		||||
	MULTIPLE_CHOICE: "Multiple Choice",
 | 
			
		||||
	MOVED_PERMANENTLY: "Moved Permanently",
 | 
			
		||||
	FOUND: "Found",
 | 
			
		||||
	SEE_OTHER: "See Other",
 | 
			
		||||
	NOT_MODIFIED: "Not Modified",
 | 
			
		||||
	TEMPORARY_REDIRECT: "Temporary Redirect",
 | 
			
		||||
	PERMANENT_REDIRECT: "Permanent Redirect",
 | 
			
		||||
	BAD_REQUEST: "Bad Request",
 | 
			
		||||
	UNAUTHORIZED: "Unauthorized",
 | 
			
		||||
	PAYMENT_REQUIRED: "Payment Required",
 | 
			
		||||
	FORBIDDEN: "Forbidden",
 | 
			
		||||
	NOT_FOUND: "Not Found",
 | 
			
		||||
	METHOD_NOT_ALLOWED: "Method Not Allowed",
 | 
			
		||||
	NOT_ACCEPTABLE: "Not Acceptable",
 | 
			
		||||
	PROXY_AUTHENTICATION_REQUIRED: "Proxy Authentication Requested",
 | 
			
		||||
	REQUEST_TIMEOUT: "Request Timeout",
 | 
			
		||||
	CONFLICT: "Conflict",
 | 
			
		||||
	GONE: "Gone",
 | 
			
		||||
	LENGTH_REQUIRED: "Length Required",
 | 
			
		||||
	PRECONDITION_FAILED: "Precondition Failed",
 | 
			
		||||
	PAYLOAD_TOO_LARGE: "Payload Too Large",
 | 
			
		||||
	URI_TOO_LONG: "URI Too long",
 | 
			
		||||
	UNSUPPORTED_MEDIA_TYPE: "Unsupported Media Type",
 | 
			
		||||
	RANGE_NOT_SATISFIABLE: "Range Not Satisfiable",
 | 
			
		||||
	EXPECTATION_FAILED: "Expectation Failed",
 | 
			
		||||
	IM_A_TEAPOT: "I'm A Teapot",
 | 
			
		||||
	MISDIRECTED_REQUEST: "Misdirected Request",
 | 
			
		||||
	UNPROCESSABLE_ENTITY: "Unprocessable Entity",
 | 
			
		||||
	LOCKED: "Locked",
 | 
			
		||||
	FAILED_DEPENDENCY: "Failed Dependency",
 | 
			
		||||
	TOO_EARLY: "Too Early",
 | 
			
		||||
	UPGRADE_REQUIRED: "Upgrade Required",
 | 
			
		||||
	PRECONDITION_REQUIRED: "Precondition Required",
 | 
			
		||||
	TOO_MANY_REQUESTS: "Too Many Requests",
 | 
			
		||||
	REQUEST_HEADER_FIELDS_TOO_LARGE: "Request Header Fields Too Large",
 | 
			
		||||
	UNAVAILABLE_FOR_LEGAL_REASONS: "Unavailable For Legal Reasons",
 | 
			
		||||
	INTERNAL_SERVER_ERROR: "Internal Server Error",
 | 
			
		||||
	NOT_IMPLEMENTED: "Not Implemented",
 | 
			
		||||
	BAD_GATEWAY: "Bad Gateway",
 | 
			
		||||
	SERVICE_UNAVAILABLE: "Service Unavailable",
 | 
			
		||||
	GATEWAY_TIMEOUT: "Gateway Timeout",
 | 
			
		||||
	HTTP_VERSION_NOT_SUPPORTED: "HTTP Version Not Supported",
 | 
			
		||||
	VARIANT_ALSO_NEGOTIATES: "Variant Also Negotiates",
 | 
			
		||||
	INSUFFICIENT_STORAGE: "Insufficient Storage",
 | 
			
		||||
	LOOP_DETECTED: "Loop detected",
 | 
			
		||||
	NOT_EXTENDED: "Not Extended",
 | 
			
		||||
	NETWORK_AUTHENTICATION_REQUIRED: "Network Authentication Required",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Public methods
 | 
			
		||||
 | 
			
		||||
static func code_to_description(code: int) -> String:
 | 
			
		||||
	return __DESCRIPTIONS[code]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static func code_to_identifier(code: int) -> String:
 | 
			
		||||
	return code_to_description(code).to_upper().replace(" ", "_").replace("'", "")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static func code_to_status_line(code: int) -> String:
 | 
			
		||||
	return "HTTP/1.1 %d %s" % [code, code_to_identifier(code)]
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user