summaryrefslogtreecommitdiffstats
path: root/core/io/http_client.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/io/http_client.cpp')
-rw-r--r--core/io/http_client.cpp84
1 files changed, 62 insertions, 22 deletions
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index 46e45500bf..0cf870e7e7 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -77,7 +77,7 @@ Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl,
if (conn_host.is_valid_ip_address()) {
// Host contains valid IP
- Error err = tcp_connection->connect_to_host(IP_Address(conn_host), p_port);
+ Error err = tcp_connection->connect_to_host(IPAddress(conn_host), p_port);
if (err) {
status = STATUS_CANT_CONNECT;
return err;
@@ -96,6 +96,15 @@ Error HTTPClient::connect_to_host(const String &p_host, int p_port, bool p_ssl,
void HTTPClient::set_connection(const Ref<StreamPeer> &p_connection) {
ERR_FAIL_COND_MSG(p_connection.is_null(), "Connection is not a reference to a valid StreamPeer object.");
+ if (ssl) {
+ ERR_FAIL_NULL_MSG(Object::cast_to<StreamPeerSSL>(p_connection.ptr()),
+ "Connection is not a reference to a valid StreamPeerSSL object.");
+ }
+
+ if (connection == p_connection) {
+ return;
+ }
+
close();
connection = p_connection;
status = STATUS_CONNECTED;
@@ -105,24 +114,41 @@ Ref<StreamPeer> HTTPClient::get_connection() const {
return connection;
}
+static bool _check_request_url(HTTPClient::Method p_method, const String &p_url) {
+ switch (p_method) {
+ case HTTPClient::METHOD_CONNECT: {
+ // Authority in host:port format, as in RFC7231
+ int pos = p_url.find_char(':');
+ return 0 < pos && pos < p_url.length() - 1;
+ }
+ case HTTPClient::METHOD_OPTIONS: {
+ if (p_url == "*") {
+ return true;
+ }
+ [[fallthrough]];
+ }
+ default:
+ // Absolute path or absolute URL
+ return p_url.begins_with("/") || p_url.begins_with("http://") || p_url.begins_with("https://");
+ }
+}
+
Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector<String> &p_headers, const Vector<uint8_t> &p_body) {
ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!p_url.begins_with("/"), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!_check_request_url(p_method, p_url), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA);
String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n";
- if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) {
- // Don't append the standard ports
- request += "Host: " + conn_host + "\r\n";
- } else {
- request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n";
- }
+ bool add_host = true;
bool add_clen = p_body.size() > 0;
bool add_uagent = true;
bool add_accept = true;
for (int i = 0; i < p_headers.size(); i++) {
request += p_headers[i] + "\r\n";
+ if (add_host && p_headers[i].findn("Host:") == 0) {
+ add_host = false;
+ }
if (add_clen && p_headers[i].findn("Content-Length:") == 0) {
add_clen = false;
}
@@ -133,6 +159,14 @@ Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector
add_accept = false;
}
}
+ if (add_host) {
+ if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) {
+ // Don't append the standard ports
+ request += "Host: " + conn_host + "\r\n";
+ } else {
+ request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n";
+ }
+ }
if (add_clen) {
request += "Content-Length: " + itos(p_body.size()) + "\r\n";
// Should it add utf8 encoding?
@@ -174,22 +208,20 @@ Error HTTPClient::request_raw(Method p_method, const String &p_url, const Vector
Error HTTPClient::request(Method p_method, const String &p_url, const Vector<String> &p_headers, const String &p_body) {
ERR_FAIL_INDEX_V(p_method, METHOD_MAX, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!p_url.begins_with("/"), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!_check_request_url(p_method, p_url), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(status != STATUS_CONNECTED, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(connection.is_null(), ERR_INVALID_DATA);
String request = String(_methods[p_method]) + " " + p_url + " HTTP/1.1\r\n";
- if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) {
- // Don't append the standard ports
- request += "Host: " + conn_host + "\r\n";
- } else {
- request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n";
- }
+ bool add_host = true;
bool add_uagent = true;
bool add_accept = true;
bool add_clen = p_body.length() > 0;
for (int i = 0; i < p_headers.size(); i++) {
request += p_headers[i] + "\r\n";
+ if (add_host && p_headers[i].findn("Host:") == 0) {
+ add_host = false;
+ }
if (add_clen && p_headers[i].findn("Content-Length:") == 0) {
add_clen = false;
}
@@ -200,6 +232,14 @@ Error HTTPClient::request(Method p_method, const String &p_url, const Vector<Str
add_accept = false;
}
}
+ if (add_host) {
+ if ((ssl && conn_port == PORT_HTTPS) || (!ssl && conn_port == PORT_HTTP)) {
+ // Don't append the standard ports
+ request += "Host: " + conn_host + "\r\n";
+ } else {
+ request += "Host: " + conn_host + ":" + itos(conn_port) + "\r\n";
+ }
+ }
if (add_clen) {
request += "Content-Length: " + itos(p_body.utf8().length()) + "\r\n";
// Should it add utf8 encoding?
@@ -288,7 +328,7 @@ Error HTTPClient::poll() {
return OK; // Still resolving
case IP::RESOLVER_STATUS_DONE: {
- IP_Address host = IP::get_singleton()->get_resolve_item_address(resolving);
+ IPAddress host = IP::get_singleton()->get_resolve_item_address(resolving);
Error err = tcp_connection->connect_to_host(host, conn_port);
IP::get_singleton()->erase_resolve_item(resolving);
resolving = IP::RESOLVER_INVALID_ID;
@@ -593,7 +633,7 @@ PackedByteArray HTTPClient::read_response_body_chunk() {
ret.resize(chunk.size() - 2);
uint8_t *w = ret.ptrw();
- copymem(w, chunk.ptr(), chunk.size() - 2);
+ memcpy(w, chunk.ptr(), chunk.size() - 2);
chunk.clear();
}
@@ -701,14 +741,14 @@ String HTTPClient::query_string_from_dict(const Dictionary &p_dict) {
String query = "";
Array keys = p_dict.keys();
for (int i = 0; i < keys.size(); ++i) {
- String encoded_key = String(keys[i]).http_escape();
+ String encoded_key = String(keys[i]).uri_encode();
Variant value = p_dict[keys[i]];
switch (value.get_type()) {
case Variant::ARRAY: {
// Repeat the key with every values
Array values = value;
for (int j = 0; j < values.size(); ++j) {
- query += "&" + encoded_key + "=" + String(values[j]).http_escape();
+ query += "&" + encoded_key + "=" + String(values[j]).uri_encode();
}
break;
}
@@ -719,7 +759,7 @@ String HTTPClient::query_string_from_dict(const Dictionary &p_dict) {
}
default: {
// Add the key-value pair
- query += "&" + encoded_key + "=" + String(value).http_escape();
+ query += "&" + encoded_key + "=" + String(value).uri_encode();
}
}
}