64 lines
1.7 KiB
Go
64 lines
1.7 KiB
Go
package webconnectivity
|
|
|
|
//
|
|
// Input parsing
|
|
//
|
|
|
|
import (
|
|
"errors"
|
|
"net"
|
|
"net/url"
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/runtimex"
|
|
)
|
|
|
|
// InputParser helps to print the experiment's input.
|
|
type InputParser struct {
|
|
// List of accepted URL schemes.
|
|
AcceptedSchemes []string
|
|
|
|
// Whether to allow endpoints in input.
|
|
AllowEndpoints bool
|
|
|
|
// The default scheme to use if AllowEndpoints == true.
|
|
DefaultScheme string
|
|
}
|
|
|
|
// Parse parses the experiment input and returns the resulting URL.
|
|
func (ip *InputParser) Parse(input string) (*url.URL, error) {
|
|
// put this check at top-level such that we always see the crash if needed
|
|
runtimex.PanicIfTrue(
|
|
ip.AllowEndpoints && ip.DefaultScheme == "",
|
|
"invalid configuration for InputParser.AllowEndpoints == true",
|
|
)
|
|
URL, err := url.Parse(input)
|
|
if err != nil {
|
|
return ip.maybeAllowEndpoints(URL, err)
|
|
}
|
|
for _, scheme := range ip.AcceptedSchemes {
|
|
if URL.Scheme == scheme {
|
|
// TODO: here you may want to perform additional parsing
|
|
return URL, nil
|
|
}
|
|
}
|
|
return nil, errors.New("cannot parse input")
|
|
}
|
|
|
|
// Conditionally allows endpoints when ip.AllowEndpoints is true.
|
|
func (ip *InputParser) maybeAllowEndpoints(URL *url.URL, err error) (*url.URL, error) {
|
|
runtimex.PanicIfNil(err, "expected to be called with a non-nil error")
|
|
if ip.AllowEndpoints && URL.Scheme != "" && URL.Opaque != "" && URL.User == nil &&
|
|
URL.Host == "" && URL.Path == "" && URL.RawPath == "" &&
|
|
URL.RawQuery == "" && URL.Fragment == "" && URL.RawFragment == "" {
|
|
// See https://go.dev/play/p/Rk5pS_zGY5U
|
|
//
|
|
// Note that we know that `ip.DefaultScheme != ""` from the above runtime check.
|
|
out := &url.URL{
|
|
Scheme: ip.DefaultScheme,
|
|
Host: net.JoinHostPort(URL.Scheme, URL.Opaque),
|
|
}
|
|
return out, nil
|
|
}
|
|
return nil, err
|
|
}
|