daemon/logger: remove uses of pkg/urlutil, fix fluentd validation and parsing
### daemon/logger/gelf: remove uses of pkg/urlutil.IsTransportURL()

pkg/urlutil (despite its poorly chosen name) is not really intended as a generic utility to handle URLs, and should only be used by the builder to handle (remote) build contexts.

This patch:

- removes a redundant use of urlutil.IsTransportURL(); code further below already checked if the given scheme (protocol) was supported.
- renames some variables that collided with imported packages.

### daemon/logger/splunk: remove uses of pkg/urlutil.IsURL()

pkg/urlutil (despite its poorly chosen name) is not really intended as a generic utility to handle URLs, and should only be used by the builder to handle (remote) build contexts.

This patch removes the use of urlutil.IsURL(), in favor of just checking if the provided scheme (protocol) is supported.

### daemon/logger/syslog: remove uses of pkg/urlutil.IsTransportURL()

pkg/urlutil (despite its poorly chosen name) is not really intended as a generic utility to handle URLs, and should only be used by the builder to handle (remote) build contexts.

This patch:

- removes a redundant use of urlutil.IsTransportURL(); instead adding some code to check if the given scheme (protocol) is supported.
- define a `defaultPort` const for the default port.
- use `net.JoinHostPort()` instead of string concatenating, to account for possible issues with IPv6 addresses.
- renames a variable that collided with an imported package.


### daemon/logger/fluentd: add coverage for ValidateLogOpt(), parseAddress()

This exposed a bug where host is ignored on some valid cases (to be fixed).

### daemon/logger/fluentd: rename var that collided with import

### daemon/logger/fluentd: make error-handling less DRY

### daemon/logger/fluentd: validate path element

fix some missing validation: the driver was silently ignoring path elements in some cases, and expecting a host (not an URL), and for unix sockets did not validate if a path was specified.

For the latter case, we should have a fix in the upstream driver, as it uses an empty path as default path for the socket (`defaultSocketPath`), and performs no validation.

### daemon/logger/fluentd: fix missing host, remove urlutil.IsTransportURL()

pkg/urlutil (despite its poorly chosen name) is not really intended as a generic utility to handle URLs, and should only be used by the builder to handle (remote) build contexts.

This patch:

- fix some cases where the host was ignored for valid addresses.
- removes a redundant use of urlutil.IsTransportURL(); instead adding code to check if the given scheme (protocol) is supported.
- improve port validation for out of range ports.
- fix some missing validation: the driver was silently ignoring path elements, but expected a host (not an URL)

### daemon/logger/fluentd: remove udp, tcp+tls, unixgram, add tls scheme

unix and unixgram were added in cb176c848e0731f77fa48b4e1a90ae74d1f2deae (https://github.com/moby/moby/pull/26088), but at the time, the driver only supported "tcp" and "unix": see [vendor/src/github.com/fluent/fluent-logger-golang/fluent/fluent.go#L243-L2610](https://github.com/moby/moby/blob/cb176c848e0731f77fa48b4e1a90ae74d1f2deae/vendor/src/github.com/fluent/fluent-logger-golang/fluent/fluent.go#L243-L2610)

support for tls was added in github.com/fluent/fluent-logger-golang v1.8.0, which was vendored in e24d61b7efac787ff3d5176d994608937a057522 (https://github.com/moby/moby/pull/42979).

the list of currently supported schemes by the driver is: tcp, tls and unix: see [vendor/github.com/fluent/fluent-logger-golang/fluent/fluent.go#L435-L463](https://github.com/moby/moby/blob/5179299b98a37ac2ba6eb8aefe8bf211f33f7dcc/vendor/github.com/fluent/fluent-logger-golang/fluent/fluent.go#L435-L463)

daemon/logger/fluentd/fluentd_test.go
package fluentd // import "github.com/docker/docker/daemon/logger/fluentd"
import (
	"testing"

	"gotest.tools/v3/assert"
)

func TestValidateLogOptReconnectInterval(t *testing.T) {
	invalidIntervals := []string{"-1", "1", "-1s", "99ms", "11s"}
	for _, v := range invalidIntervals {
		t.Run("invalid "+v, func(t *testing.T) {
			err := ValidateLogOpt(map[string]string{asyncReconnectIntervalKey: v})
			assert.ErrorContains(t, err, "invalid value for fluentd-async-reconnect-interval:")
		})
	}

	validIntervals := []string{"100ms", "10s"}
	for _, v := range validIntervals {
		t.Run("valid "+v, func(t *testing.T) {
			err := ValidateLogOpt(map[string]string{asyncReconnectIntervalKey: v})
			assert.NilError(t, err)
		})
	}
}

package fluentd // import "github.com/docker/docker/daemon/logger/fluentd"
import (
	"testing"

	"github.com/google/go-cmp/cmp"
	"gotest.tools/v3/assert"
)

func TestValidateLogOptReconnectInterval(t *testing.T) {
	invalidIntervals := []string{"-1", "1", "-1s", "99ms", "11s"}
	for _, v := range invalidIntervals {
		t.Run("invalid "+v, func(t *testing.T) {
			err := ValidateLogOpt(map[string]string{asyncReconnectIntervalKey: v})
			assert.ErrorContains(t, err, "invalid value for fluentd-async-reconnect-interval:")
		})
	}

	validIntervals := []string{"100ms", "10s"}
	for _, v := range validIntervals {
		t.Run("valid "+v, func(t *testing.T) {
			err := ValidateLogOpt(map[string]string{asyncReconnectIntervalKey: v})
			assert.NilError(t, err)
		})
	}
}

func TestValidateLogOptAddress(t *testing.T) {
	// ports to try, and their results
	validPorts := map[string]int{
		"":       defaultPort,
		":":      defaultPort,
		":123":   123,
		":65535": 65535,
	}
	// paths to try, which should result in an error
	paths := []string{"/", "/some-path"}

	tests := []struct {
		addr        string
		ports       map[string]int // combinations of addr + port -> expected port
		paths       []string       // paths to append to addr, should be an error for tcp/udp
		expected    location
		expectedErr string
	}{
		{
			addr: "",
			expected: location{
				protocol: defaultProtocol,
				host:     defaultHost,
				port:     defaultPort,
			},
		},
		{
			addr:  "192.168.1.1",
			ports: validPorts,
			paths: paths,
			expected: location{
				protocol: defaultProtocol,
				host:     "192.168.1.1",
			},
		},
		{
			addr:  "[::1]",
			ports: validPorts,
			paths: paths,
			expected: location{
				protocol: defaultProtocol,
				host:     "::1",
			},
		},
		{
			addr:  "example.com",
			ports: validPorts,
			paths: paths,
			expected: location{
				protocol: defaultProtocol,
				host:     "example.com",
			},
		},
		{
			addr:  "tcp://",
			paths: paths,
			expected: location{
				protocol: "tcp",
				host:     defaultHost,
				port:     defaultPort,
			},
		},
		{
			addr:  "tcp://example.com",
			ports: validPorts,
			paths: paths,
			expected: location{
				protocol: "tcp",
				host:     "example.com",
			},
		},
		{
			addr:  "tls://",
			paths: paths,
			expected: location{
				protocol: "tls",
				host:     defaultHost,
				port:     defaultPort,
			},
		},
		{
			addr:  "tls://example.com",
			ports: validPorts,
			paths: paths,
			expected: location{
				protocol: "tls",
				host:     "example.com",
			},
		},
		{
			addr:        "://",
			expectedErr: "missing protocol scheme",
		},
		{
			addr:        "something://",
			expectedErr: "unsupported scheme: 'something'",
		},
		{
			addr:        "udp://",
			expectedErr: "unsupported scheme: 'udp'",
		},
		{
			addr:        "unixgram://",
			expectedErr: "unsupported scheme: 'unixgram'",
		},
		{
			addr:        "tcp+tls://",
			expectedErr: "unsupported scheme: 'tcp+tls'",
		},
		{
			addr:        "corrupted:c",
			expectedErr: "invalid port",
		},
		{
			addr:        "tcp://example.com:port",
			expectedErr: "invalid port",
		},
		{
			addr:        "tcp://example.com:-1",
			expectedErr: "invalid port",
		},
		{
			addr:        "tcp://example.com:65536",
			expectedErr: "invalid port",
		},
		{
			addr:        "unix://",
			expectedErr: "path is empty",
		},
		{
			addr: "unix:///some/socket.sock",
			expected: location{
				protocol: "unix",
				path:     "/some/socket.sock",
			},
		},
		{
			addr: "unix:///some/socket.sock:80", // unusual, but technically valid
			expected: location{
				protocol: "unix",
				path:     "/some/socket.sock:80",
			},
		},
	}
	for _, tc := range tests {
		tc := tc
		if len(tc.ports) == 0 {
			tc.ports = map[string]int{"": tc.expected.port}
		}

		// always try empty paths; add paths to try if the test specifies it
		tc.paths = append([]string{""}, tc.paths...)
		for port, expectedPort := range tc.ports {
			for _, path := range tc.paths {
				address := tc.addr + port + path
				expected := tc.expected
				expected.port = expectedPort
				t.Run(address, func(t *testing.T) {
					err := ValidateLogOpt(map[string]string{addressKey: address})
					if path != "" {
						assert.ErrorContains(t, err, "should not contain a path element")
						return
					}
					if tc.expectedErr != "" {
						assert.ErrorContains(t, err, tc.expectedErr)
						return
					}

					assert.NilError(t, err)
					addr, _ := parseAddress(address)
					assert.DeepEqual(t, expected, *addr, cmp.AllowUnexported(location{}))
				})
			}
		}
	}
}

~This doesn't appear to be used as an input for any of the test cases.~

Edit: This starts to be used in "daemon/logger/fluentd: fix missing host, remove urlutil.IsTransportURL()".  Maybe remove it from this first commit and add it in the commit where it's being used?