add godot-http-server
This commit is contained in:
parent
a1ffe4d4ba
commit
01835ec2d7
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)]
|
||||||
|
|
@ -8,11 +8,25 @@
|
|||||||
|
|
||||||
config_version=4
|
config_version=4
|
||||||
|
|
||||||
|
_global_script_classes=[ {
|
||||||
|
"base": "TCP_Server",
|
||||||
|
"class": "HTTPServer",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://addons/http_server/http_server.gd"
|
||||||
|
} ]
|
||||||
|
_global_script_class_icons={
|
||||||
|
"HTTPServer": ""
|
||||||
|
}
|
||||||
|
|
||||||
[application]
|
[application]
|
||||||
|
|
||||||
config/name="Ticle Frontend"
|
config/name="Ticle Frontend"
|
||||||
config/icon="res://icon.png"
|
config/icon="res://icon.png"
|
||||||
|
|
||||||
|
[editor_plugins]
|
||||||
|
|
||||||
|
enabled=PoolStringArray( "res://addons/http_server/plugin.cfg" )
|
||||||
|
|
||||||
[gui]
|
[gui]
|
||||||
|
|
||||||
common/drop_mouse_on_gui_input_disabled=true
|
common/drop_mouse_on_gui_input_disabled=true
|
||||||
|
Loading…
Reference in New Issue
Block a user