summaryrefslogtreecommitdiff
path: root/scene/main/http_request.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/main/http_request.cpp')
-rw-r--r--scene/main/http_request.cpp196
1 files changed, 83 insertions, 113 deletions
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index da0169b60b..a4fcc04e20 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.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 */
@@ -30,7 +30,7 @@
#include "http_request.h"
#include "core/io/compression.h"
-#include "core/ustring.h"
+#include "scene/main/timer.h"
void HTTPRequest::_redirect_request(const String &p_new_url) {
}
@@ -40,47 +40,30 @@ Error HTTPRequest::_request() {
}
Error HTTPRequest::_parse_url(const String &p_url) {
- url = p_url;
use_ssl = false;
-
request_string = "";
port = 80;
request_sent = false;
got_response = false;
body_len = -1;
body.resize(0);
- downloaded = 0;
+ downloaded.set(0);
redirections = 0;
- String url_lower = url.to_lower();
- if (url_lower.begins_with("http://")) {
- url = url.substr(7, url.length() - 7);
- } else if (url_lower.begins_with("https://")) {
- url = url.substr(8, url.length() - 8);
+ String scheme;
+ Error err = p_url.parse_url(scheme, url, port, request_string);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Error parsing URL: " + p_url + ".");
+ if (scheme == "https://") {
use_ssl = true;
- port = 443;
- } else {
- ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Malformed URL: " + url + ".");
+ } else if (scheme != "http://") {
+ ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Invalid URL scheme: " + scheme + ".");
}
-
- ERR_FAIL_COND_V_MSG(url.length() < 1, ERR_INVALID_PARAMETER, "URL too short: " + url + ".");
-
- int slash_pos = url.find("/");
-
- if (slash_pos != -1) {
- request_string = url.substr(slash_pos, url.length());
- url = url.substr(0, slash_pos);
- } else {
- request_string = "/";
+ if (port == 0) {
+ port = use_ssl ? 443 : 80;
}
-
- int colon_pos = url.find(":");
- if (colon_pos != -1) {
- port = url.substr(colon_pos + 1, url.length()).to_int();
- url = url.substr(0, colon_pos);
- ERR_FAIL_COND_V(port < 1 || port > 65535, ERR_INVALID_PARAMETER);
+ if (request_string.is_empty()) {
+ request_string = "/";
}
-
return OK;
}
@@ -121,9 +104,11 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h
CharString charstr = p_request_data.utf8();
size_t len = charstr.length();
- raw_data.resize(len);
- uint8_t *w = raw_data.ptrw();
- copymem(w, charstr.ptr(), len);
+ if (len > 0) {
+ raw_data.resize(len);
+ uint8_t *w = raw_data.ptrw();
+ memcpy(w, charstr.ptr(), len);
+ }
return request_raw(p_url, p_custom_headers, p_ssl_validate_domain, p_method, raw_data);
}
@@ -159,16 +144,16 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust
requesting = true;
- if (use_threads) {
- thread_done = false;
- thread_request_quit = false;
+ if (use_threads.is_set()) {
+ thread_done.clear();
+ thread_request_quit.clear();
client->set_blocking_mode(true);
- thread = Thread::create(_thread_func, this);
+ thread.start(_thread_func, this);
} else {
client->set_blocking_mode(false);
err = _request();
if (err != OK) {
- call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
return ERR_CANT_CONNECT;
}
@@ -184,9 +169,9 @@ void HTTPRequest::_thread_func(void *p_userdata) {
Error err = hr->_request();
if (err != OK) {
- hr->call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
+ hr->call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
} else {
- while (!hr->thread_request_quit) {
+ while (!hr->thread_request_quit.is_set()) {
bool exit = hr->_update_connection();
if (exit) {
break;
@@ -195,7 +180,7 @@ void HTTPRequest::_thread_func(void *p_userdata) {
}
}
- hr->thread_done = true;
+ hr->thread_done.set();
}
void HTTPRequest::cancel_request() {
@@ -205,13 +190,11 @@ void HTTPRequest::cancel_request() {
return;
}
- if (!use_threads) {
+ if (!use_threads.is_set()) {
set_process_internal(false);
} else {
- thread_request_quit = true;
- Thread::wait_to_finish(thread);
- memdelete(thread);
- thread = nullptr;
+ thread_request_quit.set();
+ thread.wait_to_finish();
}
if (file) {
@@ -228,7 +211,7 @@ void HTTPRequest::cancel_request() {
bool HTTPRequest::_handle_response(bool *ret_value) {
if (!client->has_response()) {
- call_deferred("_request_done", RESULT_NO_RESPONSE, 0, PackedStringArray(), PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_NO_RESPONSE, 0, PackedStringArray(), PackedByteArray());
*ret_value = true;
return true;
}
@@ -238,25 +221,25 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
List<String> rheaders;
client->get_response_headers(&rheaders);
response_headers.resize(0);
- downloaded = 0;
- for (List<String>::Element *E = rheaders.front(); E; E = E->next()) {
- response_headers.push_back(E->get());
+ downloaded.set(0);
+ for (const String &E : rheaders) {
+ response_headers.push_back(E);
}
if (response_code == 301 || response_code == 302) {
// Handle redirect
if (max_redirects >= 0 && redirections >= max_redirects) {
- call_deferred("_request_done", RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_REDIRECT_LIMIT_REACHED, response_code, response_headers, PackedByteArray());
*ret_value = true;
return true;
}
String new_request;
- for (List<String>::Element *E = rheaders.front(); E; E = E->next()) {
- if (E->get().findn("Location: ") != -1) {
- new_request = E->get().substr(9, E->get().length()).strip_edges();
+ for (const String &E : rheaders) {
+ if (E.findn("Location: ") != -1) {
+ new_request = E.substr(9, E.length()).strip_edges();
}
}
@@ -278,7 +261,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
got_response = false;
body_len = -1;
body.resize(0);
- downloaded = 0;
+ downloaded.set(0);
redirections = new_redirs;
*ret_value = false;
return true;
@@ -292,7 +275,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) {
bool HTTPRequest::_update_connection() {
switch (client->get_status()) {
case HTTPClient::STATUS_DISCONNECTED: {
- call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
return true; // End it, since it's doing something
} break;
case HTTPClient::STATUS_RESOLVING: {
@@ -301,7 +284,7 @@ bool HTTPRequest::_update_connection() {
return false;
} break;
case HTTPClient::STATUS_CANT_RESOLVE: {
- call_deferred("_request_done", RESULT_CANT_RESOLVE, 0, PackedStringArray(), PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_CANT_RESOLVE, 0, PackedStringArray(), PackedByteArray());
return true;
} break;
@@ -311,7 +294,7 @@ bool HTTPRequest::_update_connection() {
return false;
} break; // Connecting to IP
case HTTPClient::STATUS_CANT_CONNECT: {
- call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray());
return true;
} break;
@@ -326,24 +309,25 @@ bool HTTPRequest::_update_connection() {
return ret_value;
}
- call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, PackedByteArray());
return true;
}
if (body_len < 0) {
// Chunked transfer is done
- call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body);
+ call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body);
return true;
}
- call_deferred("_request_done", RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PackedByteArray());
return true;
- // Request migh have been done
+ // Request might have been done
} else {
// Did not request yet, do request
- Error err = client->request_raw(method, request_string, headers, request_data);
+ int size = request_data.size();
+ Error err = client->request(method, request_string, headers, size > 0 ? request_data.ptr() : nullptr, size);
if (err != OK) {
- call_deferred("_request_done", RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray());
return true;
}
@@ -366,7 +350,7 @@ bool HTTPRequest::_update_connection() {
}
if (!client->is_response_chunked() && client->get_response_body_length() == 0) {
- call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, PackedByteArray());
return true;
}
@@ -375,59 +359,65 @@ bool HTTPRequest::_update_connection() {
body_len = client->get_response_body_length();
if (body_size_limit >= 0 && body_len > body_size_limit) {
- call_deferred("_request_done", RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
return true;
}
if (download_to_file != String()) {
file = FileAccess::open(download_to_file, FileAccess::WRITE);
if (!file) {
- call_deferred("_request_done", RESULT_DOWNLOAD_FILE_CANT_OPEN, response_code, response_headers, PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_DOWNLOAD_FILE_CANT_OPEN, response_code, response_headers, PackedByteArray());
return true;
}
}
}
client->poll();
+ if (client->get_status() != HTTPClient::STATUS_BODY) {
+ return false;
+ }
PackedByteArray chunk = client->read_response_body_chunk();
- downloaded += chunk.size();
- if (file) {
- const uint8_t *r = chunk.ptr();
- file->store_buffer(r, chunk.size());
- if (file->get_error() != OK) {
- call_deferred("_request_done", RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PackedByteArray());
- return true;
+ if (chunk.size()) {
+ downloaded.add(chunk.size());
+ if (file) {
+ const uint8_t *r = chunk.ptr();
+ file->store_buffer(r, chunk.size());
+ if (file->get_error() != OK) {
+ call_deferred(SNAME("_request_done"), RESULT_DOWNLOAD_FILE_WRITE_ERROR, response_code, response_headers, PackedByteArray());
+ return true;
+ }
+ } else {
+ body.append_array(chunk);
}
- } else {
- body.append_array(chunk);
}
- if (body_size_limit >= 0 && downloaded > body_size_limit) {
- call_deferred("_request_done", RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
+ if (body_size_limit >= 0 && downloaded.get() > body_size_limit) {
+ call_deferred(SNAME("_request_done"), RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray());
return true;
}
if (body_len >= 0) {
- if (downloaded == body_len) {
- call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body);
+ if (downloaded.get() == body_len) {
+ call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body);
return true;
}
} else if (client->get_status() == HTTPClient::STATUS_DISCONNECTED) {
// We read till EOF, with no errors. Request is done.
- call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body);
+ call_deferred(SNAME("_request_done"), RESULT_SUCCESS, response_code, response_headers, body);
+ return true;
}
return false;
} break; // Request resulted in body: break which must be read
case HTTPClient::STATUS_CONNECTION_ERROR: {
- call_deferred("_request_done", RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_CONNECTION_ERROR, 0, PackedStringArray(), PackedByteArray());
return true;
} break;
case HTTPClient::STATUS_SSL_HANDSHAKE_ERROR: {
- call_deferred("_request_done", RESULT_SSL_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_SSL_HANDSHAKE_ERROR, 0, PackedStringArray(), PackedByteArray());
return true;
} break;
}
@@ -452,7 +442,7 @@ void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArra
is_compressed = false;
}
- const PackedByteArray *data = NULL;
+ const PackedByteArray *data = nullptr;
if (accept_gzip && is_compressed && p_data.size() > 0) {
// Decompress request body
@@ -475,12 +465,12 @@ void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArra
data = &p_data;
}
- emit_signal("request_completed", p_status, p_code, p_headers, *data);
+ emit_signal(SNAME("request_completed"), p_status, p_code, p_headers, *data);
}
void HTTPRequest::_notification(int p_what) {
if (p_what == NOTIFICATION_INTERNAL_PROCESS) {
- if (use_threads) {
+ if (use_threads.is_set()) {
return;
}
bool done = _update_connection();
@@ -499,11 +489,11 @@ void HTTPRequest::_notification(int p_what) {
void HTTPRequest::set_use_threads(bool p_use) {
ERR_FAIL_COND(get_http_client_status() != HTTPClient::STATUS_DISCONNECTED);
- use_threads = p_use;
+ use_threads.set_to(p_use);
}
bool HTTPRequest::is_using_threads() const {
- return use_threads;
+ return use_threads.is_set();
}
void HTTPRequest::set_accept_gzip(bool p_gzip) {
@@ -557,7 +547,7 @@ int HTTPRequest::get_max_redirects() const {
}
int HTTPRequest::get_downloaded_bytes() const {
- return downloaded;
+ return downloaded.get();
}
int HTTPRequest::get_body_size() const {
@@ -575,7 +565,7 @@ int HTTPRequest::get_timeout() {
void HTTPRequest::_timeout() {
cancel_request();
- call_deferred("_request_done", RESULT_TIMEOUT, 0, PackedStringArray(), PackedByteArray());
+ call_deferred(SNAME("_request_done"), RESULT_TIMEOUT, 0, PackedStringArray(), PackedByteArray());
}
void HTTPRequest::_bind_methods() {
@@ -609,7 +599,7 @@ void HTTPRequest::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_timeout", "timeout"), &HTTPRequest::set_timeout);
ClassDB::bind_method(D_METHOD("get_timeout"), &HTTPRequest::get_timeout);
- ClassDB::bind_method(D_METHOD("set_download_chunk_size"), &HTTPRequest::set_download_chunk_size);
+ ClassDB::bind_method(D_METHOD("set_download_chunk_size", "chunk_size"), &HTTPRequest::set_download_chunk_size);
ClassDB::bind_method(D_METHOD("get_download_chunk_size"), &HTTPRequest::get_download_chunk_size);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "download_file", PROPERTY_HINT_FILE), "set_download_file", "get_download_file");
@@ -640,31 +630,11 @@ void HTTPRequest::_bind_methods() {
}
HTTPRequest::HTTPRequest() {
- thread = nullptr;
-
- port = 80;
- redirections = 0;
- max_redirects = 8;
- body_len = -1;
- got_response = false;
- validate_ssl = false;
- use_ssl = false;
- accept_gzip = true;
- response_code = 0;
- request_sent = false;
- requesting = false;
- client.instance();
- use_threads = false;
- thread_done = false;
- downloaded = 0;
- body_size_limit = -1;
- file = nullptr;
-
+ client = Ref<HTTPClient>(HTTPClient::create());
timer = memnew(Timer);
timer->set_one_shot(true);
timer->connect("timeout", callable_mp(this, &HTTPRequest::_timeout));
add_child(timer);
- timeout = 0;
}
HTTPRequest::~HTTPRequest() {