Last active
January 20, 2024 15:07
-
-
Save freehuntx/4170405eeb4729a6cb817ea7afa3be0e to your computer and use it in GitHub Desktop.
Godot HTTP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class_name Http extends RefCounted | |
class Response: | |
var code := -1 | |
var headers := {} | |
var error := "" | |
var text := "" | |
var json = null | |
func _init(opts:={}): | |
for key in opts.keys(): | |
self[key] = opts[key] | |
func _to_string() -> String: | |
return JSON.stringify({"code":code,"headers":headers,"error":error,"text":text,"json":json}) | |
static func parse_url(url): | |
var regex := RegEx.new() | |
regex.compile("^(https?)://([^:/]+)(:\\d+)?([^?#]*)?(\\?[^#]*)?(\\#.*)?$") | |
var match := regex.search(url) | |
if match == null: return null | |
var proto = match.get_string(1) | |
var host = match.get_string(2) | |
var port = match.get_string(3) | |
var path = match.get_string(4) | |
var search = match.get_string(5) | |
var hashstr = match.get_string(6) | |
if port != "": | |
port = int(port.substr(1)) | |
else: | |
port = 443 if proto == "https" else 80 | |
if path == "": path = "/" | |
return { proto=proto, host=host, port=port, path=path, search=search, hash=hashstr } | |
static func request_get(url: String, headers:={}, search:={}) -> Response: | |
return await request({ method=HTTPClient.METHOD_GET, url=url, headers=headers, search=search }) | |
static func request_post(url: String, data=null, headers:={}, search:={}) -> Response: | |
var options = { | |
method=HTTPClient.METHOD_POST, | |
url=url, | |
headers=headers, | |
search=search | |
} | |
if data != null: | |
if typeof(data) == TYPE_DICTIONARY or typeof(data) == TYPE_ARRAY: | |
options.headers['Content-Type'] = 'application/json' | |
options.body = JSON.stringify(data) | |
else: | |
options.headers['Content-Type'] = 'application/text' | |
options.body = str(data) | |
return await request(options) | |
static func request(options) -> Response: | |
var method = HTTPClient.METHOD_GET if not "method" in options else options.method | |
var url = options.url | |
var headers = {} if not "headers" in options else options.headers | |
var search = {} if not "search" in options else options.search # TODO: Implement this | |
var body = "" if not "body" in options else options.body | |
var packed_headers = [] | |
for key in headers: | |
packed_headers.append("%s: %s" % [key, headers[key]]) | |
var parsed_url = parse_url(url) | |
var http := HTTPClient.new() | |
var err := http.connect_to_host(parsed_url.host, parsed_url.port, TLSOptions.client() if parsed_url.proto == "https" else null) | |
if err != OK: | |
return Response.new({ "error": "CONNECTION_FAILED" }) | |
while http.get_status() == HTTPClient.STATUS_CONNECTING or http.get_status() == HTTPClient.STATUS_RESOLVING: | |
await Engine.get_main_loop().process_frame | |
http.poll() | |
if http.get_status() != HTTPClient.STATUS_CONNECTED: | |
return Response.new({ "error": "CONNECTION_FAILED" }) | |
err = http.request(method, parsed_url.path + parsed_url.search, packed_headers, body) | |
if err != OK: | |
return Response.new({ "error": "REQUEST_FAILED" }) | |
while http.get_status() == HTTPClient.STATUS_REQUESTING: | |
await Engine.get_main_loop().process_frame | |
http.poll() | |
if http.get_status() != HTTPClient.STATUS_BODY and http.get_status() != HTTPClient.STATUS_CONNECTED: | |
return Response.new({ "error": "GETTING_RESPONSE_FAILED" }) | |
if not http.has_response(): | |
return null | |
var response := Response.new({ | |
"code": http.get_response_code(), | |
"headers": http.get_response_headers_as_dictionary() | |
}) | |
var buffer = PackedByteArray() | |
while http.get_status() == HTTPClient.STATUS_BODY: | |
await Engine.get_main_loop().process_frame | |
http.poll() | |
var chunk = http.read_response_body_chunk() | |
if chunk.size() > 0: | |
buffer += chunk | |
response.text = buffer.get_string_from_ascii() | |
if "Content-Type" in response.headers and response.headers["Content-Type"].contains("application/json"): | |
response.json = JSON.parse_string(response.text) | |
return response |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment