forked from yagich/tickle-godot-frontend
		
	add godot-http-server
This commit is contained in:
		
							
								
								
									
										175
									
								
								addons/http_server/http_server.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								addons/http_server/http_server.gd
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,175 @@
 | 
			
		||||
class_name HTTPServer extends TCP_Server
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# 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: [FuncRef, Variant], index 0 = reference to function to call, index 1 = binds to pass to func
 | 
			
		||||
}
 | 
			
		||||
var __fallback: FuncRef = null
 | 
			
		||||
var __server: TCP_Server = null
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Public methods
 | 
			
		||||
 | 
			
		||||
func endpoint(type: int, endpoint: String, function: FuncRef, binds = null) -> 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, binds]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
func fallback(function: FuncRef) -> 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: PoolByteArray = PoolByteArray([])
 | 
			
		||||
 | 
			
		||||
	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.empty():
 | 
			
		||||
		return
 | 
			
		||||
 | 
			
		||||
	var content_string: String = content.get_string_from_utf8()
 | 
			
		||||
	var content_parts: Array = content_string.split("\r\n")
 | 
			
		||||
 | 
			
		||||
	if content_parts.empty():
 | 
			
		||||
		connection.put_data(__response_from_status(Status.BAD_REQUEST).to_utf8())
 | 
			
		||||
		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" % [String(content)]
 | 
			
		||||
		)
 | 
			
		||||
		connection.put_data(__response_from_status(Status.BAD_REQUEST).to_utf8())
 | 
			
		||||
		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 = PoolStringArray(body_parts).join("\r\n")
 | 
			
		||||
 | 
			
		||||
	var response: Response = __process_request(method, endpoint, headers, body)
 | 
			
		||||
	connection.put_data(response.to_utf8())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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: FuncRef = null
 | 
			
		||||
	var endpoint_parts: PoolStringArray = endpoint.split("/", false)
 | 
			
		||||
	var binds
 | 
			
		||||
 | 
			
		||||
	# special case for if endpoint is just root
 | 
			
		||||
	if endpoint == "/":
 | 
			
		||||
		var endpoint_hash: Array = [type, "/"]
 | 
			
		||||
		if __endpoints.has(endpoint_hash):
 | 
			
		||||
			endpoint_func = __endpoints[endpoint_hash][0]
 | 
			
		||||
			binds = __endpoints[endpoint_hash][1]
 | 
			
		||||
	else:
 | 
			
		||||
		while (!endpoint_func && !endpoint_parts.empty()):
 | 
			
		||||
			var endpoint_hash: Array = [type, "/" + endpoint_parts.join("/")]
 | 
			
		||||
			if __endpoints.has(endpoint_hash):
 | 
			
		||||
				endpoint_func = __endpoints[endpoint_hash][0]
 | 
			
		||||
				binds = __endpoints[endpoint_hash][1]
 | 
			
		||||
			else:
 | 
			
		||||
				endpoint_parts.remove(endpoint_parts.size() - 1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if !endpoint_func:
 | 
			
		||||
		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_valid():
 | 
			
		||||
		print(
 | 
			
		||||
			"[ERR] FuncRef for endpoint not valid, method: %s, endpoint: %s" % [method, endpoint]
 | 
			
		||||
		)
 | 
			
		||||
	else:
 | 
			
		||||
		print(
 | 
			
		||||
			"[INF] Recieved request method: %s, endpoint: %s" % [method, endpoint]
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
		if !binds:
 | 
			
		||||
			endpoint_func.call_func(request, response)
 | 
			
		||||
		else:
 | 
			
		||||
			endpoint_func.call_func(request, response, binds)
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
							
								
								
									
										68
									
								
								addons/http_server/request.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								addons/http_server/request.gd
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
 | 
			
		||||
# 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) -> void:
 | 
			
		||||
	__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 on a request with content-type: %s" % [content_type]
 | 
			
		||||
		)
 | 
			
		||||
		return null
 | 
			
		||||
 | 
			
		||||
	var result = JSON.parse(__body)
 | 
			
		||||
	if result.error:
 | 
			
		||||
		print(
 | 
			
		||||
			"[ERR] Error parsing request json: %s" % [result.error_string]
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
	__json_data = result.result
 | 
			
		||||
 | 
			
		||||
	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() -> PoolByteArray:
 | 
			
		||||
	var content = PoolStringArray()
 | 
			
		||||
 | 
			
		||||
	content.append(Status.code_to_status_line(__status))
 | 
			
		||||
 | 
			
		||||
	var data = __data
 | 
			
		||||
	if !data:
 | 
			
		||||
		data = Status.code_to_description(__status)
 | 
			
		||||
 | 
			
		||||
	if __headers.get("content-type", "") == "application/json":
 | 
			
		||||
		data = JSON.print(data)
 | 
			
		||||
 | 
			
		||||
	__headers['content-length'] = len(data)
 | 
			
		||||
 | 
			
		||||
	for header in __headers:
 | 
			
		||||
		content.append("%s: %s" % [header, String(__headers[header])])
 | 
			
		||||
 | 
			
		||||
	content.append("")
 | 
			
		||||
 | 
			
		||||
	if data:
 | 
			
		||||
		content.append(data)
 | 
			
		||||
 | 
			
		||||
	return content.join("\r\n").to_utf8()
 | 
			
		||||
							
								
								
									
										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