HTTPClient Interrupt

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Gramps
:warning: Old Version Published before Godot 3 was released.

This is part of a previous question I had asked and not sure if this is an engine issue or something I am doing wrong. However, I find that if I am using the HTTPClient to query a server and the process is interrupted then the game silently crashes with no errors.

To clarify, in my example, a user clicks on Leaderboards, which polls a server and gets data then displays it. However, if the user click the back button before the server’s response comes then the game crashes with no errors.

Perhaps there is something wrong with my method? Perhaps the engine?

It’s hard to tell what the problem is without any code but I use the HTTPClient a lot without any crashes. I think there is something wrong with your method, maybe you free something on back button and the response is trying to use the object you just removed with your back button.

alexholly | 2016-04-16 18:17

Thanks for the reply. I will post the code in question when I get back to my laptop. However, for now I just have it disable the buttons until the process is done. That seems to work.

Gramps | 2016-04-17 01:08

Okay, finally got my laptop cord back and powered up! I will share the code for the version checking, where I first noticed it crash out if the player interrupts it.

# Set up some variables
var thread = Thread.new()

func _ready():
	thread.start(self, "versionChecking", "Loading...")

func versionChecking(message):
	get_node("Loading Message").set_text(message)
	# Pull the game version
	var RESPONSE = http.getGameVersion()
	call_deferred(gameUpToDate())
	return RESPONSE

func gameUpToDate():
	var RESPONSE = thread.wait_to_finish()
	# Loading server data is done so end the loading screen
	get_node("/root/global").goto_scene("res://src/splash.scn")

The HTTP script that this calls is set as a global script (singleton) to be called whenever needed. This is the code that this is calling:

# Get game's official version
func getGameVersion():
	talkToServer("version-check.php", "check", "")

# Loads the page and gets the response
func talkToServer(url, mode, data):
	# Connect to host/port
	HTTP = HTTPClient.new()
	RESPONSE = HTTP.connect("whatever.com",80)
	# Wait until resolved and connected
	while(HTTP.get_status() == HTTPClient.STATUS_CONNECTING or HTTP.get_status() == HTTPClient.STATUS_RESOLVING):
		HTTP.poll()
		OS.delay_msec(300)
	# Error catch: Could not connect
	assert(HTTP.get_status() == HTTPClient.STATUS_CONNECTED)
	# Check for a GET or POST command
	if data == "":
		HEADERS =["User-Agent: Pirulo/1.0 (Godot)", "Accept: */*"]
		RESPONSE = HTTP.request(HTTPClient.METHOD_GET, url, HEADERS)
	else:
		QUERY = HTTP.query_string_from_dict(data)
		HEADERS = ["User-Agent: Pirulo/1.0 (Godot)", "Content-Type: application/x-www-form-urlencoded", "Content-Length: " + str(QUERY.length())]
		RESPONSE = HTTP.request(HTTPClient.METHOD_POST, url, HEADERS, QUERY)
	# Make sure all is OK
	assert(RESPONSE == OK)
	# Keep polling until the request is going on
	while (HTTP.get_status() == HTTPClient.STATUS_REQUESTING):
		HTTP.poll()
		OS.delay_msec(300)
	# Make sure request finished
	assert(HTTP.get_status() == HTTPClient.STATUS_BODY or HTTP.get_status() == HTTPClient.STATUS_CONNECTED)
	# Set up some variables
	var RB = RawArray()
	var CHUNK = 0
	var RESULT = 0
	# Raw data array
	if HTTP.has_response():
		# Get response headers
		var headers = HTTP.get_response_headers_as_dictionary()
		while(HTTP.get_status() == HTTPClient.STATUS_BODY):
			HTTP.poll()
			CHUNK = HTTP.read_response_body_chunk()
			if(CHUNK.size() == 0):
				OS.delay_usec(100)
			else:
				RB = RB + CHUNK
		HTTP.close()
		RESULT = RB.get_string_from_ascii()
		# Do something with the response
		if mode == 'check':
			global.GAME_VERSION = RESULT

At the end of the code, it passes the version number to the global variable to be displayed on the menu screen. If this process is interrupted, it silently crashes the game with no error at all. No idea why.

As you can see here, I basically prevent any user input from disrupting this and make it change scenes once the process is done. The same applies to the stats and leaderboard screens.

In Python, I essentially used the same system but did not have to prevent user interaction until it was finished. It would just poll the server and display the information when it was fetched, provided the user didn’t change scenes by then.

Gramps | 2016-04-19 03:24

:bust_in_silhouette: Reply From: alexholly

I can’t see any problem right now, have you checked the output in the terminal/CMD that is showing sometimes more than the default output in godot.

I also noticed that threads somethimes hide errors so maybe you try to run the http request in “_process(delta)”

In the Linux version of Godot it does not open a terminal like it does in Windows, though I never actually checked what happens in Windows.

I will try both a Windows test and checking for hidden errors with _process(delta), cheers!

Gramps | 2016-04-19 17:13

On linux you can start godot in a terminal it will show the same output like Windows

  1. Open Terminal in godot folder
  2. run ./bin/godot.x11.tools.64 or ./godot.x11.tools.64

alexholly | 2016-04-19 19:37

I have a shortcut that runs it, I’ll just have it run that in Terminal. Thanks again!

Gramps | 2016-04-19 21:07