4
0
Fork 0
WolfBox/addons/godottpd/http_response.gd

175 lines
6.6 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## A response object useful to send out responses
class_name HttpResponse
extends RefCounted
## The client currently talking to the server
var client: StreamPeer
## The server identifier to use on responses [GodotTPD]
var server_identifier: String = "GodotTPD"
## A dictionary of headers
## [br] Headers can be set using the `set(name, value)` function
var headers: Dictionary = {}
## An array of cookies
## [br] Cookies can be set using the `cookie(name, value, options)` function
## [br] Cookies will be automatically sent via "Set-Cookie" headers to clients
var cookies: Array = []
## Origins allowed to call this resource
var access_control_origin = "*"
## Comma separed methods for the access control
var access_control_allowed_methods = "POST, GET, OPTIONS"
## Comma separed headers for the access control
var access_control_allowed_headers = "content-type"
## Send out a raw (Bytes) response to the client
## [br] Useful to send files faster or raw data which will be converted by the client
## [br][param status] - The HTTP Status code to send
## [br][param data] - The body data to send
## [br][param content_type] - The type of content to send.
func send_raw(status_code: int, data: PackedByteArray = PackedByteArray([]), content_type: String = "application/octet-stream") -> void:
client.put_data(("HTTP/1.1 %d %s\r\n" % [status_code, _match_status_code(status_code)]).to_ascii_buffer())
client.put_data(("Server: %s\r\n" % server_identifier).to_ascii_buffer())
for header in headers.keys():
client.put_data(("%s: %s\r\n" % [header, headers[header]]).to_ascii_buffer())
for cookie in cookies:
client.put_data(("Set-Cookie: %s\r\n" % cookie).to_ascii_buffer())
client.put_data(("Content-Length: %d\r\n" % data.size()).to_ascii_buffer())
client.put_data("Connection: close\r\n".to_ascii_buffer())
client.put_data(("Access-Control-Allow-Origin: %s\r\n" % access_control_origin).to_ascii_buffer())
client.put_data(("Access-Control-Allow-Methods: %s\r\n" % access_control_allowed_methods).to_ascii_buffer())
client.put_data(("Access-Control-Allow-Headers: %s\r\n" % access_control_allowed_headers).to_ascii_buffer())
client.put_data(("Content-Type: %s\r\n\r\n" % content_type).to_ascii_buffer())
client.put_data(data)
## Send out a response to the client
## [br]
## [br][param status_code] - The HTTP status code to send
## [br][param data] - The body to send
## [br][param content_type] - The type of the content to send
func send(status_code: int, data: String = "", content_type = "text/html") -> void:
send_raw(status_code, data.to_ascii_buffer(), content_type)
## Send out a JSON response to the client
## [br] This function will internally call the [method send]
## [br]
## [br][param status_code] - The HTTP status code to send
## [br][param data] - The body to send
func json(status_code: int, data) -> void:
send(status_code, JSON.stringify(data), "application/json")
## Sets the responses header "field" to "value"
## [br]
## [br][param field] - The name of the header. i.e. [code]Accept-Type[/code]
## [br][param value] - The value of this header. i.e. [code]application/json[/code]
func set(field: StringName, value: Variant) -> void:
headers[field] = value
## Sets cookie "name" to "value"
## [br]
## [br][param name] - The name of the cookie. i.e. [code]user-id[/code]
## [br][param value] - The value of this cookie. i.e. [code]abcdef[/code]
## [br][param options] - A Dictionary of [url=https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#attributes]cookie attributes[/url]
## for this specific cokkie in the [code]{ "secure" : "true"}[/code] format.
func cookie(name: String, value: String, options: Dictionary = {}) -> void:
var cookie: String = name+"="+value
if options.has("domain"): cookie+="; Domain="+options["domain"]
if options.has("max-age"): cookie+="; Max-Age="+options["max-age"]
if options.has("expires"): cookie+="; Expires="+options["expires"]
if options.has("path"): cookie+="; Path="+options["path"]
if options.has("secure"): cookie+="; Secure="+options["secure"]
if options.has("httpOnly"): cookie+="; HttpOnly="+options["httpOnly"]
if options.has("sameSite"):
match (options["sameSite"]):
true: cookie += "; SameSite=Strict"
"lax": cookie += "; SameSite=Lax"
"strict": cookie += "; SameSite=Strict"
"none": cookie += "; SameSite=None"
_: pass
cookies.append(cookie)
## Automatically matches a "status_code" to an RFC 7231 compliant "status_text"
## [br]
## [br][param code] - The HTTP Status code to be matched
## [br]Returns: the matched [code]status_text[/code]
func _match_status_code(code: int) -> String:
var text: String = "OK"
match(code):
# 1xx - Informational Responses
100: text="Continue"
101: text="Switching protocols"
102: text="Processing"
103: text="Early Hints"
# 2xx - Successful Responses
200: text="OK"
201: text="Created"
202: text="Accepted"
203: text="Non-Authoritative Information"
204: text="No Content"
205: text="Reset Content"
206: text="Partial Content"
207: text="Multi-Status"
208: text="Already Reported"
226: text="IM Used"
# 3xx - Redirection Messages
300: text="Multiple Choices"
301: text="Moved Permanently"
302: text="Found (Previously 'Moved Temporarily')"
303: text="See Other"
304: text="Not Modified"
305: text="Use Proxy"
306: text="Switch Proxy"
307: text="Temporary Redirect"
308: text="Permanent Redirect"
# 4xx - Client Error Responses
400: text="Bad Request"
401: text="Unauthorized"
402: text="Payment Required"
403: text="Forbidden"
404: text="Not Found"
405: text="Method Not Allowed"
406: text="Not Acceptable"
407: text="Proxy Authentication Required"
408: text="Request Timeout"
409: text="Conflict"
410: text="Gone"
411: text="Length Required"
412: text="Precondition Failed"
413: text="Payload Too Large"
414: text="URI Too Long"
415: text="Unsupported Media Type"
416: text="Range Not Satisfiable"
417: text="Expectation Failed"
418: text="I'm a Teapot"
421: text="Misdirected Request"
422: text="Unprocessable Entity"
423: text="Locked"
424: text="Failed Dependency"
425: text="Too Early"
426: text="Upgrade Required"
428: text="Precondition Required"
429: text="Too Many Requests"
431: text="Request Header Fields Too Large"
451: text="Unavailable For Legal Reasons"
# 5xx - Server Error Responses
500: text="Internal Server Error"
501: text="Not Implemented"
502: text="Bad Gateway"
503: text="Service Unavailable"
504: text="Gateway Timeout"
505: text="HTTP Version Not Supported"
506: text="Variant Also Negotiates"
507: text="Insufficient Storage"
508: text="Loop Detected"
510: text="Not Extended"
511: text="Network Authentication Required"
return text