{"record":{"id":"d5534d5ab3923033","repo":"iflytek/astron-agent","slug":"response-failed-bad-url-e-getmessage","errorCode":"RESPONSE_FAILED","errorMessage":"Bad URL: ${e.getMessage()}","messagePattern":"Bad URL: (.+?)","errorType":"error_code","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/util/ssrf/SsrfValidators.java","lineNumber":168,"sourceCode":"        return false;\n    }\n\n    /**\n     * Normalize a URL by removing encoding and fragment part.\n     *\n     * @param url original URL string\n     * @return normalized URL\n     * @throws MalformedURLException if URL format is invalid\n     * @throws BusinessException if URI syntax is invalid\n     */\n    public static URL normalize(String url) throws MalformedURLException {\n        URL u = new URL(url);\n        try {\n            URI uri = new URI(u.getProtocol(), u.getUserInfo(), u.getHost(), u.getPort(),\n                    u.getPath(), u.getQuery(), null);\n            return uri.normalize().toURL();\n        } catch (URISyntaxException e) {\n            throw new BusinessException(ResponseEnum.RESPONSE_FAILED, \"Bad URL: \" + e.getMessage());\n        }\n    }\n\n    /**\n     * Check whether the host hits the IP blacklist.\n     *\n     * <p>\n     * Features:\n     * </p>\n     * <ul>\n     * <li>Host can be domain or IP (IPv4/IPv6), domain resolves all A/AAAA records.</li>\n     * <li>Blacklist supports both exact IP and CIDR (e.g., 192.168.0.0/16, fd00::/8).</li>\n     * <li>IP canonicalization avoids misjudgment from different notations (::1, 0:0:0:0:0:0:0:1).</li>\n     * <li>DNS resolution error is treated as \"not hit\".</li>\n     * </ul>\n     *\n     * @param host target host (domain or IP, IPv6 can include [])\n     * @param ipBlacklist blacklist entries (exact IP or CIDR)","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/util/ssrf/SsrfValidators.java#L150-L186","documentation":"SsrfValidators.normalize re-encodes a parsed URL through URI to canonicalize it; if the re-encoded URL cannot be converted back (URISyntaxException), it throws RESPONSE_FAILED with 'Bad URL: <detail>'. This guards against malformed URLs before further SSRF checks.","triggerScenarios":"normalize(url) is given a string that parses as java.net.URL but produces an invalid URI during re-encoding — e.g. illegal characters in host, port out of range, or characters incompatible with the URI RFC after reconstruction.","commonSituations":"URLs copied with trailing whitespace/control characters, IPv6 literals malformed (missing brackets), percent-encoding mishandled, or ports like 'https://host:99999/path'.","solutions":["Read the URISyntaxException detail in the message to find the offending character/position.","Manually percent-encode illegal characters before passing the URL.","Correct IPv6 literal formatting (wrap in square brackets).","Normalize/trim the input string and re-test with new URI(url) locally to reproduce."],"exampleFix":"// before\nString url = \"https://host:99999/path\"; // port out of range\n// after\nString url = \"https://host:8443/path\";","handlingStrategy":"validation","validationCode":"function isValidHttpUrl(s) {\n  try { const u = new URL(s.trim()); return u.protocol === 'https:' || u.protocol === 'http:'; }\n  catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n    URL normalized = SsrfValidators.normalize(rawUrl);\n} catch (BusinessException e) {\n    log.error(\"Cannot normalize URL: {}\", e.getMessage());\n    throw e;\n}","preventionTips":["Trim and percent-encode URLs before passing them in.","Format IPv6 literals with brackets.","Reject suspicious input at the API boundary before normalization."],"tags":["url-parsing","ssrf","validation"],"backgroundTag":"invalid-url-format","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}