Re: [PATCH v3 09/18] gweb: Adopt optional, immutable GError instance for GWeb result errors.

Denis Kenzior <[email protected]> Mon, 24 Mar 2025 17:28:35 -0500
Newsgroups dev.linux.lists.connman
Message-ID <[email protected]>
Hi Grant,

On 3/20/25 6:39 PM, Grant Erickson wrote:
> In the following instances, GWeb can fail before initiating or while
> processing a web request:
> 
>    1. TCP connection timeout to the remote server peer.
>    2. Decoding a chunked response.
>    3. Non-successful events (that is, G_IO_NVAL, G_IO_ERR, or G_IO_HUP)
>       from 'g_io_add_watch'.
>    4. GResolve "host not found" DNS forward resolution failure.
>    5. Transport creation failure from 'create_transport'.
> 
> Rather than trying to overload 'GWEB_HTTP_STATUS_CODE_' error
> enumerations from actual web server responses for these non-response
> or response-in-progress failures, the signature of 'GWebResultFunc' is
> amended to take an optional pointer to an immutable GError instance
> which describes one of the five errors above on a GWeb request
> failure.

This looks so much better, a few nits:

> ---
>   gweb/gweb.c      | 125 +++++++++++++++++++++++++++++++++++------------
>   gweb/gweb.h      |   2 +-
>   src/6to4.c       |   3 +-
>   src/wispr.c      |   5 +-
>   tools/web-test.c |   2 +-
>   tools/wispr.c    |   2 +-
>   6 files changed, 101 insertions(+), 38 deletions(-)
> 

<snip>

> @@ -233,9 +233,14 @@ static inline void call_route_func(struct web_session *session)
>   static gboolean connect_timeout_cb(gpointer user_data)
>   {
>   	struct web_session *session = user_data;
> +	g_autofree char *message = NULL;
> +	GError *local_error = NULL;

Could you use:

g_autoptr(GError) local_error = NULL;

...

> +
> +	message = g_strdup_printf("connect timeout to %s after %ums",
> +		session->address, g_web_get_connect_timeout(session->web));
>   
> -	debug(session->web, "session %p connect timeout after %ums",
> -			session, g_web_get_connect_timeout(session->web));
> +	debug(session->web, "session %p %s",
> +			session, message);
>   
>   	session->connect_timeout = 0;
>   
> @@ -244,7 +249,14 @@ static gboolean connect_timeout_cb(gpointer user_data)
>   	session->result.buffer = NULL;
>   	session->result.length = 0;
>   
> -	call_result_func(session, GWEB_HTTP_STATUS_CODE_REQUEST_TIMEOUT);
> +	local_error = g_error_new_literal(G_IO_ERROR,
> +					G_IO_ERROR_TIMED_OUT,
> +					message);
> +
> +	call_result_func(session, local_error);
> +
> +	if (local_error)
> +		g_error_free(local_error);

And avoid this if statement completely.

>   
>   	return G_SOURCE_REMOVE;
>   }
> @@ -1020,6 +1030,8 @@ static int handle_body(struct web_session *session,
>   				const guint8 *buf, gsize len)
>   {
>   	int err;
> +	g_autofree char *message = NULL;
> +	GError *local_error = NULL;

Ditto here

>   
>   	debug(session->web, "[body] length %zu", len);
>   
> @@ -1027,19 +1039,28 @@ static int handle_body(struct web_session *session,
>   		if (len > 0) {
>   			session->result.buffer = buf;
>   			session->result.length = len;
> -			call_result_func(session,
> -				GWEB_HTTP_STATUS_CODE_UNKNOWN);
> +			call_result_func(session, NULL);
>   		}
>   		return 0;
>   	}
>   
>   	err = decode_chunked(session, buf, len);
>   	if (err < 0) {
> -		debug(session->web, "Error in chunk decode %d", err);
> +		message = g_strdup_printf("Error in chunk decode %d", err);
> +
> +		debug(session->web, message);
>   
>   		session->result.buffer = NULL;
>   		session->result.length = 0;
> -		call_result_func(session, GWEB_HTTP_STATUS_CODE_BAD_REQUEST);
> +
> +		local_error = g_error_new_literal(G_WEB_ERROR,
> +			G_WEB_ERROR_CHUNK_DECODE,
> +			message);
> +
> +		call_result_func(session, local_error);
> +
> +		if (local_error)
> +			g_error_free(local_error);

Ditto

>   	}
>   
>   	return err;

<snip>

> @@ -1255,6 +1274,7 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond,
>   	struct web_session *session = user_data;
>   	gsize bytes_read;
>   	GIOStatus status;
> +	GError *local_error = NULL;

And here

>   
>   	/* We received some data or condition, cancel the connect timeout. */
>   
> @@ -1270,7 +1290,14 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond,
>   		session->result.buffer = NULL;
>   		session->result.length = 0;
>   
> -		call_result_func(session, GWEB_HTTP_STATUS_CODE_BAD_REQUEST);
> +		local_error = g_error_new_literal(G_IO_ERROR,
> +			g_io_error_from_errno(EIO),
> +			g_strerror(EIO));
> +
> +		call_result_func(session, local_error);
> +
> +		if (local_error)
> +			g_error_free(local_error);

Ditto

>   
>   		return FALSE;
>   	}
> @@ -2288,6 +2315,8 @@ static void handle_resolved_address(struct web_session *session)
>   	struct addrinfo hints;
>   	g_autofree char *port;
>   	int ret;
> +	g_autofree char *message = NULL;
> +	GError *local_error = NULL;
>   
>   	debug(session->web, "address %s", session->address);
>   
> @@ -2303,16 +2332,35 @@ static void handle_resolved_address(struct web_session *session)
>   	port = g_strdup_printf("%u", session->port);
>   	ret = getaddrinfo(session->address, port, &hints, &session->addr);
>   	if (ret != 0 || !session->addr) {
> -		call_result_func(session, GWEB_HTTP_STATUS_CODE_BAD_REQUEST);
> -		return;
> +		message = g_strdup_printf("could not resolve %s: %s",
> +			session->address,
> +			gai_strerror(ret));

Maybe consider dropping 'message' variable entirely and using g_set_error or 
g_error_new?

> +
> +		local_error = g_error_new_literal(G_WEB_ERROR,
> +			G_WEB_ERROR_HOST_NOT_FOUND,
> +			message);
> +
> +		call_result_func(session, local_error);
> +
> +		goto done;
>   	}
>   
>   	call_route_func(session);
>   
> -	if (create_transport(session) < 0) {
> -		call_result_func(session, GWEB_HTTP_STATUS_CODE_CONFLICT);
> -		return;
> +	ret = create_transport(session);
> +	if (ret < 0) {
> +		local_error = g_error_new_literal(G_IO_ERROR,
> +						g_io_error_from_errno(ret),
> +						g_strerror(ret));
> +
> +		call_result_func(session, local_error);
> +
> +		goto done;

nit: The above line is not needed

>   	}
> +
> + done:
> +	if (local_error)
> +		g_error_free(local_error);
>   }
>   
>   static gboolean already_resolved(gpointer data)
> @@ -2329,9 +2377,22 @@ static void resolv_result(GResolvResultStatus status,
>   					char **results, gpointer user_data)
>   {
>   	struct web_session *session = user_data;
> +	g_autofree char *message = NULL;
> +	GError *local_error = NULL;
>   
>   	if (!results || !results[0]) {
> -		call_result_func(session, GWEB_HTTP_STATUS_CODE_NOT_FOUND);
> +		message = g_strdup_printf("could not resolve %s",
> +			session->host);
> +
> +		local_error = g_error_new_literal(G_WEB_ERROR,
> +				G_WEB_ERROR_HOST_NOT_FOUND,
> +				message);
> +

Same here, consider dropping 'message' entirely and using g_set_error or g_error_new

> +		call_result_func(session, local_error);
> +
> +		if (local_error)
> +			g_error_free(local_error);
> +
>   		return;
>   	}
>   

Regards,
-Denis