package mfer import ( "net/url" "strings" ) // ManifestURL represents a URL pointing to a manifest file. type ManifestURL string // FileURL represents a URL pointing to a file to be fetched. type FileURL string // BaseURL represents a base URL for constructing file URLs. type BaseURL string // JoinPath safely joins a relative file path to a base URL. // The path is properly URL-encoded to prevent path traversal. func (b BaseURL) JoinPath(path RelFilePath) (FileURL, error) { base, err := url.Parse(string(b)) if err != nil { return "", err } // Ensure base path ends with / if !strings.HasSuffix(base.Path, "/") { base.Path += "/" } // Encode each path segment individually to preserve slashes segments := strings.Split(string(path), "/") for i, seg := range segments { segments[i] = url.PathEscape(seg) } ref, err := url.Parse(strings.Join(segments, "/")) if err != nil { return "", err } resolved := base.ResolveReference(ref) return FileURL(resolved.String()), nil } // String returns the URL as a string. func (b BaseURL) String() string { return string(b) } // String returns the URL as a string. func (f FileURL) String() string { return string(f) } // String returns the URL as a string. func (m ManifestURL) String() string { return string(m) }