@@ -66,6 +66,27 @@ import java.util.regex.Pattern
6666@AutoFinal @CompileStatic
6767class GrapeIvy implements GrapeEngine {
6868
69+ static {
70+ // GROOVY-12005 / 2026-05: Maven Central (Fastly) currently returns HTTP 404
71+ // with a 1-byte body for requests whose User-Agent is the JDK URLConnection
72+ // default "Java/<version>". Any other value (curl/x.y, Apache-Ivy/..., etc.)
73+ // gets the expected HTTP 200. Ivy 2.5.3 uses java.net.URLConnection under
74+ // the hood, which honours -Dhttp.agent. We set it here so direct grape use
75+ // (CLI `grape install`, `groovy script-with-@Grab.groovy`, embedded usage)
76+ // gets a working agent — those paths load GrapeIvy before any other class
77+ // touches the network, so this static init runs early enough.
78+ //
79+ // For test JVMs the same property MUST be set on the JVM command line —
80+ // see the matching -Dhttp.agent in build-logic/.../org.apache.groovy-tested.gradle —
81+ // because by the time GrapeIvy is class-loaded for the first @Grab in a test,
82+ // the agent has already been cached deep in the JDK's HTTP machinery.
83+ //
84+ // Respect any value the user has already configured.
85+ if (System . getProperty(' http.agent' ) == null ) {
86+ System . setProperty(' http.agent' , ' Apache-Ivy_Groovy-Grape' )
87+ }
88+ }
89+
6990 private static final List<String > DEFAULT_CONF = Collections . singletonList(' default' )
7091 private static final Map<String , Set<String > > MUTUALLY_EXCLUSIVE_KEYS = processGrabArgs([
7192 [' group' , ' groupId' , ' organisation' , ' organization' , ' org' ],
0 commit comments