flipped-aurora/gin-vue-admin · error

仅允许 http/https, 实际为 %q

Error message

仅允许 http/https, 实际为 %q

What it means

After parsing, runHTTP enforces a scheme allowlist: only http and https are accepted. Any other scheme (ftp, file, gopher, javascript, empty) is rejected to prevent SSRF/local-file access. The actual scheme is quoted in the error.

Source

Thrown at server/service/system/sys_timed_task_runner.go:132

	select {
	case err := <-done:
		if err != nil && errors.Is(err, context.DeadlineExceeded) {
			return "", errTaskTimeout
		}
		return "", err
	case <-ctx.Done():
		return "", errTaskTimeout
	}
}

// runHTTP 执行 HTTP 回调(SSRF 防护见 sys_timed_task_http.go)
func (s *TimedTaskService) runHTTP(t system.SysTimedTask) (string, error) {
	u, err := url.Parse(t.HttpUrl)
	if err != nil {
		return "", fmt.Errorf("URL 非法: %w", err)
	}
	if u.Scheme != "http" && u.Scheme != "https" {
		return "", fmt.Errorf("仅允许 http/https, 实际为 %q", u.Scheme)
	}
	method := strings.ToUpper(strings.TrimSpace(t.HttpMethod))
	if method == "" {
		method = http.MethodGet
	}
	var body io.Reader
	if t.HttpBody != "" {
		body = strings.NewReader(t.HttpBody)
	}
	req, err := http.NewRequest(method, t.HttpUrl, body)
	if err != nil {
		return "", fmt.Errorf("构造请求失败: %w", err)
	}
	if len(t.HttpHeader) > 0 {
		var hdr map[string]string
		if err := json.Unmarshal(t.HttpHeader, &hdr); err != nil {
			return "", fmt.Errorf("http_header 必须是 JSON 对象: %w", err)
		}

View on GitHub (pinned to 3136500ef3)

Solutions

  1. Change the task URL to start with http:// or https://
  2. Normalize schemeless URLs by prefixing https:// when saving tasks
  3. Keep the allowlist; do not loosen it for internal schemes

Example fix

// before
HttpUrl: "ftp://backup.example.com/ping"
// after
HttpUrl: "https://backup.example.com/ping"
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(httpUrl)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
    return errors.New("callback URL must use http or https")
}

Type guard

func isHTTPOrHTTPS(s string) bool {
    u, err := url.Parse(s)
    return err == nil && (u.Scheme == "http" || u.Scheme == "https")
}

Try / catch

if err := RunTask(t); err != nil {
    if strings.Contains(err.Error(), "仅允许 http/https") {
        log.Warnf("task %d rejected scheme in %q", t.ID, t.HttpUrl)
    }
}

Prevention

When it happens

Trigger: t.HttpUrl uses a non-http(s) scheme — e.g. 'file:///etc/passwd', 'ftp://...', or a schemeless 'example.com/hook' (empty scheme).

Common situations: Trying to use the HTTP callback for internal file reads; forgetting the 'http://' prefix when entering the URL; probing SSRF protections during security review.

Related errors


AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31). Data as JSON: /api/errors/e307e54fc42800e6. Report an issue: GitHub.